pixmicat

Subversion Repositories:
Compare Path: Rev
With Path: Rev
/ @ 886  →  / @ 887
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_audit/mod_audit.php
@@ -0,0 +1,61 @@
<?php
class mod_audit{
var $logname, $logLevel;
 
function mod_audit($PMS){
$this->logname = '.audit'; // 稽核紀錄檔檔名
$this->logLevel = array( // 監察等級
'Add' => false, // 記錄發文
'Login' => true, // 記錄後端登入
'Delete' => true, // 記錄刪除文章
'AdminFunc' => true // 記錄後端操作
);
$PMS->addCHP('mod_audit_logcat', array(&$this, '_log'));
}
 
function getModuleName(){
return 'mod_audit : 稽核記錄功能';
}
 
function getModuleVersionInfo(){
return '6th.Release-pre (b110320)';
}
 
function _log($info){
$t = time() + TIME_ZONE * 3600;
error_log(getREMOTE_ADDR().' ['.gmdate('y/m/d H:i:s', $t).'] '."$info\n", 3, $this->logname);
}
 
// 記錄登入資訊
function autoHookAuthenticate($passwordField, $action, &$result){
if(!$this->logLevel['Login']) return;
switch($action){
case 'admin':
$this->_log('Login: '.($result ? 'Successfully' : 'Denied, Pwd guessed: '.$_POST['pass']));
break;
case 'userdel':
$this->_log('UserDelete: '.($result ? 'by Admin' : 'by User'));
break;
}
}
 
// 記錄刪除資訊
function autoHookPostOnDeletion($delnoArray, $cond){
if(!$this->logLevel['Delete']) return;
$this->_log('Deleting: No.'.implode(', ', $delnoArray)." [$cond]");
}
 
// 記錄發文資訊
function autoHookRegistAfterCommit($lastno, $resto, $name, $email, $sub, $com){
if(!$this->logLevel['Add']) return;
$this->_log("Adding: No.$lastno (Res:$resto) [Name: $name, Mail: $email, Subject: $sub, Comment: $com]");
}
 
// 記錄後端操作
function autoHookAdminFunction($action, &$param, $funcLabel, &$message){
if(!$this->logLevel['AdminFunc']) return;
if($action != 'run') return;
$this->_log("AdminFunc: $funcLabel [No.".implode(', ', $param).']');
}
}
?>
New file
/release/Modules-PIO-v6/mod_vipquality/mod_vipquality.php
@@ -0,0 +1,87 @@
<?php
class mod_vipquality{
function mod_vipquality(){
list($usec, $sec) = explode(" ", microtime());
mt_srand(intval($usec*1000 + $sec));
}
 
function getModuleName(){
return 'mod_vipquality : VIPクオリティ(子集)';
}
 
function getModuleVersionInfo(){
return 'v071119';
}
 
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status){
if(strpos($name,"!dama")!==false) $this->_dama($name);
if(strpos($name,"!omikuji")!==false) $this->_omikuji($name);
if(strpos($name,"!uptime")!==false) $this->_uptime($name);
if(strpos($name,"!power")!==false) $this->_power($name);
if(strpos($name,"fusianasan")!==false) $name=str_replace("fusianasan","<span class='nor'>".gethostbyaddr($_SERVER['REMOTE_ADDR'])."</span>",$name);
if(strpos($name,"mokorikomo")!==false) $name=str_replace("mokorikomo","<span class='nor'>".$_SERVER['REMOTE_ADDR']."</span>",$name);
}
 
function _uptime(&$name) {
$loadavg='';
if(strtoupper(substr(PHP_OS, 0, 3))!='WIN') {
preg_match_all('/\d\.\d\d/',exec('uptime',$t1,$t2),$loadavg);
$loadavg=$loadavg[0][2];
}
$name=str_replace("!uptime",$loadavg?"<span class='nor'>(LA:".$loadavg.")</span>":"",$name);
unset($t1);unset($t2);
}
function _power(&$name) {
$name=str_replace("!power","<span class='nor'>(Lv:".mt_rand(1,999).")</span>",$name);
}
function _dama(&$name) {
$name=str_replace("!dama",(gmdate("j",time()+TIME_ZONE*60*60)==1?"<span class='nor'>【".(int)(mt_rand(0,1000)*(mt_rand(100,1000)/100)*1.1)."円】</span>":""),$name);
}
function _omikuji(&$name) {
$omikuji = array('大吉','中吉','吉','小吉','末吉','凶','大凶','豚','ぴょん吉','だん吉','神','女神');
$omi_v=mt_rand(0,8510);
switch($omi_v){
case ($omi_v<2000):
$omi_v=0;
break;
case ($omi_v>=2000 && $omi_v<3500):
$omi_v=1;
break;
case ($omi_v>=3500 && $omi_v<4500):
$omi_v=2;
break;
case ($omi_v>=4500 && $omi_v<5500):
$omi_v=3;
break;
case ($omi_v>=5500 && $omi_v<6000):
$omi_v=4;
break;
case ($omi_v>=6000 && $omi_v<6500):
$omi_v=5;
break;
case ($omi_v>=6500 && $omi_v<7000):
$omi_v=6;
break;
case ($omi_v>=7000 && $omi_v<7500):
$omi_v=7;
break;
case ($omi_v>=7500 && $omi_v<8000):
$omi_v=8;
break;
case ($omi_v>=8000 && $omi_v<8500):
$omi_v=9;
break;
case ($omi_v>=8500 && $omi_v<8505):
$omi_v=10;
break;
case ($omi_v>=8505 && $omi_v<=8510):
$omi_v=11;
break;
}
$name=str_replace("!omikuji","<span class='nor'>【".$omikuji[$omi_v]."】</span>",$name);
}
 
 
}
?>
New file
/release/Modules-PIO-v6/mod_showip/mod_showip.php
@@ -0,0 +1,512 @@
<?php
class mod_showip{
 
function getModuleName(){
return 'mod_showip : 顯示部份IP/hostname';
}
 
function getModuleVersionInfo(){
return 'v100808';
}
 
function _isgTLD($last,$add='') {
$gtld = array('biz','com','info','name','net','org','pro','aero','asia','cat','coop','edu','gov','int','jobs','mil','mobi','museum','tel','travel','xxx');
if(is_array($add)) {
foreach($add as $a) {
array_unshift($gtld,$a);
}
}
foreach($gtld as $tld) {
if($last == $tld) {
return true;
}
}
return false;
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
global $language, $PIO;
$iphost = strtolower($post['host']);
if(ip2long($iphost)!==false) {
$arrLabels['{$NOW}'] .= ' (IP: '.preg_replace('/\d+\.\d+$/','*.*',$iphost).')';
} else { // host
$parthost=''; $iscctld = false; $isgtld = false;
 
if($iphost == 'localhost') { // localhost hack
$arrLabels['{$NOW}'] .= ' (Host: localhost)';
return;
}
 
if(preg_match('/([\w\-]+)\.([\w\-]+)$/',$iphost,$parts)) {
 
// hinet/teksavvy/qwest/mchsi/smartone-vodafone/rr/swbell/sbcglobal/acanac/ameritech/
// telus/charter/embarqhsd/comcast/verizon/sparqnet/taiwanmobile/userdns/pacbell/
// comcastbusiness/fetnet/cgocable/cox/on/psu/thecloud/suddenlink/telstraclear/
// liniacom/elisa-laajakaista/zsttk/bezeqint/arcor-ip/prtc/linearg/insightbb/george24/
// pipex/amis/eircom/lijbrandt/ou/wlms-broadband/as9105/novuscom/btcentralplus/mnsi/
// asretelecom/cgocable/spcsdns/indiana.edu/metrocast/twtelecom/frontiernet/onecommunications/
// dslextreme/slicehost/as29550/clearwire-wmx/restechservices/net-infinity/myfairpoint.net/kymp.net/
// gmavt.net/cia.com/sonic.net/newwavecomm.net/telia.com IP hack
if($parts[1] == 'hinet' || $parts[1] == 'teksavvy' || $parts[1] == 'qwest'
|| $parts[1] == 'mchsi' || $parts[1] == 'smartone-vodafone' || $parts[1] == 'rr'
|| $parts[1] == 'swbell' || $parts[1] == 'sbcglobal' || $parts[1] == 'acanac'
|| $parts[1] == 'ameritech' || $parts[1] == 'telus' || $parts[1] == 'charter'
|| $parts[1] == 'embarqhsd' || $parts[1] == 'comcast' || $parts[1] == 'verizon'
|| $parts[1] == 'sparqnet' || $parts[1] == 'taiwanmobile' || $parts[1] == 'userdns'
|| $parts[1] == 'pacbell' || $parts[1] == 'comcastbusiness' || $parts[1] == 'fetnet'
|| $parts[1] == 'cgocable' || $parts[1] == 'cox' || $parts[1] == 'on' || $parts[1] == 'psu'
|| $parts[1] == 'thecloud' || $parts[1] == 'suddenlink' || $parts[1] == 'telstraclear'
|| $parts[1] == 'liniacom' || $parts[1] == 'elisa-laajakaista' || $parts[1] == 'zsttk'
|| $parts[1] == 'bezeqint' || $parts[1] == 'arcor-ip' || $parts[1] == 'prtc'
|| $parts[1] == 'linearg' || $parts[1] == 'insightbb' || $parts[1] == 'george24'
|| $parts[1] == 'pipex' || $parts[1] == 'amis' || $parts[1] == 'eircom' || $parts[1] == 'lijbrandt'
|| $parts[1] == 'ou' || $parts[1] == 'wlms-broadband' || $parts[1] == 'as9105' || $parts[1] == 'novuscom'
|| $parts[1] == 'btcentralplus' || $parts[1] == 'mnsi' || $parts[1] == 'asretelecom' || $parts[1] == 'cgocable'
|| $parts[1] == 'spcsdns' || $parts[1] == 'indiana' || $parts[1] == 'metrocast' || $parts[1] == 'twtelecom'
|| $parts[1] == 'frontiernet' || $parts[1] == 'onecommunications' || $parts[1] == 'dslextreme' || $parts[1] == 'slicehost'
|| $parts[1] == 'as29550' || $parts[1] == 'clearwire-wmx' || $parts[1] == 'restechservices' || $parts[1] == 'net-infinity'
|| $parts[1] == 'myfairpoint' || $parts[1] == 'kymp' || $parts[1] == 'gmavt' || $parts[1] == 'cia' || $parts[1] == 'sonic'
|| $parts[1] == 'newwavecomm' || $parts[1] == 'telia') {
if($parts[1] == 'hinet') preg_match('/([\w\-]+)\.([\w\-]+)\.(\w+)$/',$iphost,$parts); // show IP type for hinet
if(preg_match('/^[a-z\-]*(\d+\-\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
// netvigator/bbtec/HKBN IP hack
} elseif($parts[1] == 'netvigator' || $parts[1] == 'bbtec' || $parts[1] == 'ctinets') {
if(preg_match('/^[a-z]*(\d{3})(\d{3})\d{3}\d{3}/',$iphost,$ipparts))
$parthost = intval($ipparts[1]).'.'.intval($ipparts[2]).'.*.'.$parts[0];
elseif($parts[1] == 'netvigator') {
if (preg_match('/^(pcd\d{3})\d{3}/',$iphost,$ipparts)) // no IP hack for pcd******.netvigator.com
$parthost = $ipparts[1].'*.'.$parts[0];
elseif(preg_match('/^[a-z]*(\d{3})(\d{3})/',$iphost,$ipparts)) { // PCCW egg pain (n1164818021)
if(intval($ipparts[2]) > 255) $ipparts[2] = substr($ipparts[2],0,-1);
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[0];
} elseif(preg_match('/^\d+-\d+-(\d+)-(\d+)/',$iphost,$ipparts)) { // PCCW egg pain II (109-1-246-220.static.netvigator.com)
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[0];
} elseif(preg_match('/^\d+\.\d+\.(\d+)\.(\d+)/',$iphost,$ipparts)) { // PCCW egg pain III (031.126.198.203.static.netvigator.com)
$parthost = intval($ipparts[2]).'-'.intval($ipparts[1]).'-*.'.$parts[0];
} else
$parthost = '*.'.$parts[0];
} else
$parthost = '*.'.$parts[0];
// pldt/quadranet/totbb/plus/ono/edpnet/telnor.net/dvois.com IP hack
} elseif($parts[1] == 'pldt' || $parts[1] == 'quadranet' || $parts[1] == 'totbb' || $parts[1] == 'plus'
|| $parts[1] == 'ono' || $parts[1] == 'edpnet' || $parts[1] == 'telnor' || $parts[1] == 'dvois') {
if(preg_match('/^(\d+\.\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'.*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'bjtelecom' || $parts[1] == 'cndata' || $parts[1] == 'ttn' || $parts[1] == 'siwnet' || $parts[1] == 'gibconnect') { // bjtelecom/cndata/ttn.net/siwnet.net/gibconnect.com IP hack
if(preg_match('/^(\d+)\.(\d+)\.(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[4].'-'.$ipparts[3].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'proxad') { // proxad IP hack
if(preg_match('/^[a-z\-]*\d+\-\d+\-(\d+\-\d+)\-\d+\-\d+/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'comunitel' || $parts[1] == 'ukrtel' || $parts[1] == 'vtr' || $parts[1] == 'on-nets') { // comunitel/ukrtel/vtr/on-nets IP hack
if(preg_match('/^[\w\-]*(\d+)\-(\d+)-(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[4].'-'.$ipparts[3].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'gaoland') { // gaoland IP hack
if(preg_match('/^(\d+)\.(\d+)\.(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[4].'-'.$ipparts[3].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'ctm') { // ctm.net IP hack (bb* only)
if(preg_match('/^[\w]+\.bb(\d{3})(\d+)\./',$iphost,$ipparts))
$parthost = intval($ipparts[1]).'-'.intval($ipparts[2]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
// web-pass/windstream/1dial/mundo-r/g3telecom IP hack
} elseif($parts[1] == 'web-pass' || $parts[1] == 'windstream' || $parts[1] == '1dial' || $parts[1] == 'mundo-r' || $parts[1] == 'g3telecom') {
if(preg_match('/^\w+\.\d+\.(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'sky' || $parts[1] == 'aol') { // sky.com/aol.com IP hack
if(preg_match('/^([0-9a-f]{2})([0-9a-f]{2})[0-9a-f]{2}[0-9a-f]{2}\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[1]).'-'.hexdec($ipparts[2]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 't-dialin' || $parts[1] == 'perspektivbredband') { // t-dialin/perspektivbredband.net IP hack
if(preg_match('/^[a-z]([0-9a-f]{2})([0-9a-f]{2})[0-9a-f]{2}[0-9a-f]{2}\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[1]).'-'.hexdec($ipparts[2]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'tmodns') { // tmodns IP hack
if(preg_match('/^[a-z][0-9a-f]{2}[0-9a-f]{2}([0-9a-f]{2})([0-9a-f]{2})\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[2]).'-'.hexdec($ipparts[1]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'mediaways' || $parts[1] == 'optonline') { // mediaways/optonline IP hack
if(preg_match('/^\w+\-([0-9a-f]{2})([0-9a-f]{2})[0-9a-f]{2}[0-9a-f]{2}\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[1]).'-'.hexdec($ipparts[2]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'rima-tde' || $parts[1] == 'myvzw') { // rima-tde/myvzw IP hack
if(preg_match('/^\d+\.[a-z]+\-(\d+\-\d+)\-/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'theplanet') { // theplanet IP hack
if(preg_match('/^[0-9a-f]+\.[0-9a-f]+\.([0-9a-f]{2})([0-9a-f]{2})/',$iphost,$ipparts)) {
$ipdec = hexdec($ipparts[1]);
$parthost = hexdec($ipparts[2]).'-'.hexdec($ipparts[1]).'-*.'.$parts[0];
} else
$parthost = '*.'.$parts[0];
} elseif(preg_match('/on-nets$/',$parts[1])) { // on-nets IP hack
if(preg_match('/(\d+)\-(\d+)-on-nets/',$parts[1],$ipparts))
$parthost = $ipparts[2].'.'.$ipparts[1].'.*.on-nets.com';
else
$parthost = '*-on-nets.com';
} else {
$lastpart = $parts[2];
$isgtld = $this->_isgTLD($lastpart);
 
if(!$isgtld) {
$cctld = array('ac','ad','ae','af','ag','ai','al','am','an','ao','aq','ar','as','at','au','aw','ax','az','ba','bb','bd','be','bf','bg','bh','bi','bj','bm','bn','bo','br','bs','bt','bw','by','bz','ca','cc','cd','cf','cg','ch','ci','ck','cl','cm','cn','co','cr','cu','cv','cx','cy','cz','de','dj','dk','dm','do','dz','ec','ee','eg','er','es','et','eu','fi','fj','fk','fm','fo','fr','ga','gd','ge','gf','gg','gh','gi','gl','gm','gn','gp','gq','gr','gs','gt','gu','gw','gy','hk','hm','hn','hr','ht','hu','id','ie','il','im','in','io','iq','ir','is','it','je','jm','jo','jp','ke','kg','kh','ki','km','kn','kp','kr','kw','ky','kz','la','lb','lc','li','lk','lr','ls','lt','lu','lv','ly','ma','mc','md','me','mg','mh','mk','ml','mm','mn','mo','mp','mq','mr','ms','mt','mu','mv','mw','mx','my','mz','na','nc','ne','nf','ng','ni','nl','no','np','nr','nu','nz','om','pa','pe','pf','pg','ph','pk','pl','pn','pr','ps','pt','pw','py','qa','re','ro','rs','ru','rw','sa','sb','sc','sd','se','sg','sh','si','sk','sl','sm','sn','sr','st','su','sv','sy','sz','tc','td','tf','tg','th','tj','tk','tl','tm','tn','to','tr','tt','tv','tw','tz','ua','ug','uk','us','uy','uz','va','vc','ve','vg','vi','vn','vu','wf','ws','ye','za','zm','zw');
foreach($cctld as $tld) {
if($lastpart == $tld) {
$iscctld = true;
preg_match('/([\w\-]+)\.([\w\-]+)\.(\w+)$/',$iphost,$parts);
$isgtld = $this->_isgTLD($parts[2],array('ac','ad','co','ed','go','gr'.'lg','ne','or','ind','ltd','nic','plc','vet')); // '.co.uk' etc. are common
if($isgtld) {
// kbronet/seed/so-net.net.tw/tfn/giga/lsc/canvas/tpgi/adam/iinet/tbcnet/xtra/nkcatv/telesp/netvision/twt1/dodo/
// adsl24/btvm/netspace/connections.net.nz/orcon.net.nz/kbtelecom.net.tw/tstt.net.tt/vivax.com.br/
// clear.net.nz/hiway.net.tw/ihug.co.nz/asta-net.com.pl/eonet.ne.jp IP hack
if($parts[1] == 'kbronet' || $parts[1] == 'seed' || $parts[1] == 'so-net'
|| $parts[1] == 'tfn' || $parts[1] == 'giga' || $parts[1] == 'lsc'
|| $parts[1] == 'canvas' || $parts[1] == 'tpgi' || $parts[1] == 'adam'
|| $parts[1] == 'iinet' || $parts[1] == 'tbcnet' || $parts[1] == 'xtra'
|| $parts[1] == 'nkcatv' || $parts[1] == 'telesp' || $parts[1] == 'netvision'
|| $parts[1] == 'twt1' || $parts[1] == 'dodo' || $parts[1] == 'adsl24' || $parts[1] == 'btvm'
|| $parts[1] == 'connections' || $parts[1] == 'orcon' || $parts[1] == 'kbtelecom' || $parts[1] == 'tstt'
|| $parts[1] == 'vivax' || $parts[1] == 'clear' || $parts[1] == 'hiway' || $parts[1] == 'ihug' || $parts[1] == 'asta-net' || $parts[1] == 'eonet') {
if(preg_match('/^(\d+\-\d+)/',$iphost,$ipparts))
$parthost = $ipparts[0].'-*.'.$parts[0];
elseif($parts[1] == 'seed' && preg_match('/^\w+\-(\d+\-\d+)-\d+/',$iphost,$ipparts)) // seed h* IP hack
$parthost = $ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
// i-cable/singnet/optusnet/plala/rosenet/bethere/asianet/home.ne.jp/hidatakayama/apol/pikara/bigpond/netspace.net.au/orange.co.il/
// callplus/prod-infinitum/xnet/unwired/e-mobile/gol.ne.jp/ksu.edu.tw/monash.edu.au/sinica.edu.tw/cjcu.edu.tw/asianet/tic.net.tw/
// dialog.net.pl/canet.ne.jp/catvisp.net.tw/connect.net.au/anteldata.net.uy/iburst.co.za/ccnw.ne.jp IP hack
} elseif($parts[1] == 'hkcable' || $parts[1] == 'singnet' || $parts[1] == 'optusnet'
|| $parts[1] == 'plala' || $parts[1] == 'rosenet' || $parts[1] == 'bethere'
|| $parts[1] == 'asianet' || $parts[1] == 'home' || $parts[1] == 'hidatakayama'
|| $parts[1] == 'apol' || $parts[1] == 'pikara' || $parts[1] == 'bigpond'
|| $parts[1] == 'netspace' || $parts[1] == 'orange' || $parts[1] == 'callplus'
|| $parts[1] == 'prod-infinitum' || $parts[1] == 'xnet' || $parts[1] == 'unwired'
|| $parts[1] == 'e-mobile' || $parts[1] == 'gol' || $parts[1] == 'ksu' || $parts[1] == 'monash'
|| $parts[1] == 'sinica' || $parts[1] == 'cjcu' || $parts[1] == 'asianet' || $parts[1] == 'tic'
|| $parts[1] == 'dialog' || $parts[1] == 'canet' || $parts[1] == 'catvisp' || $parts[1] == 'connect'
|| $parts[1] == 'anteldata' || $parts[1] == 'iburst' || $parts[1] == 'ccnw') {
if(preg_match('/^[a-z\-]*(\d+\-\d+)-\d+\-\d+/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'ocn' || $parts[1] == 'nttpc') { // OCN/nttpc hack (no IP hack available)
preg_match('/([\w\-]+\.){3}(\w+)$/',$iphost,$parts);
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'infoweb') { // infoweb hack (no IP hack available)
preg_match('/([\w\-]+\.){6}(\w+)$/',$iphost,$parts);
$parthost = '*.'.$parts[0];
// tcol/yournet/m1connect/exetel/megaegg/pacific/snap.net.nz IP hack
} elseif($parts[1] == 'tcol' || $parts[1] == 'yournet' || $parts[1] == 'm1connect' || $parts[1] == 'exetel'
|| $parts[1] == 'megaegg' || $parts[1] == 'pacific' || $parts[1] == 'snap') {
if(preg_match('/^(\d+)\.(\d+)\.(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[4].'-'.$ipparts[3].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'eaccess' || $parts[1] == 'gvt' || $parts[1] == 'aanet') { // eaccess/gvt/aanet IP hack
if(preg_match('/^(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[0].'.*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'tinp' || $parts[1] == 'savecom' || $parts[1] == 'cdbnet') { // tinp/savecom/cdbnet IP hack
if(preg_match('/^(\d+)\-(\d+)-(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[4].'-'.$ipparts[3].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'ucom' || $parts[1] == 'gyao') { // ucom/gyao IP hack
if(preg_match('/^(\d+)x(\d+)x(\d+)x(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'totalbb') { // totalbb IP hack
if(preg_match('/^[\w\-]+\.(\d+)-(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[3].'-'.$ipparts[2].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'sig') { // sig.com.tw IP hack
if(preg_match('/^[\w\-]+\.(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'maxonline') { // maxonline.com.sg IP hack (proxy.* only)
if(preg_match('/^proxy\.(\d+)\.(\d+)\./',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'wakwak' || $parts[1] == 'ntti') { // wakwak/ntti.net.sg IP hack
if(preg_match('/^[\w\-]+\.(\d+)-(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'gcn') { // gcn IP hack
if(preg_match('/^\w+\.(\d{3})(\d{2})\d+/',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'tnc' || $parts[1] == 'thn' || $parts[1] == 'tokai') { // tnc/thn/tokai IP hack
if(preg_match('/^[\w\-]+\.[a-z]+(\d{3})(\d{3})\d{3}/',$iphost,$ipparts))
$parthost = intval($ipparts[1]).'-'.intval($ipparts[2]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'ctt') { // ctt IP hack
if(preg_match('/^[\w\-]+\.[a-z]+\d{3}(\d{3})(\d{3})/',$iphost,$ipparts))
$parthost = intval($ipparts[2]).'-'.intval($ipparts[1]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'ayu') { // ayu IP hack
if(preg_match('/^[\w\-]+\-[a-z]+(\d{3})(\d{3})\d{3}/',$iphost,$ipparts))
$parthost = intval($ipparts[1]).'-'.intval($ipparts[2]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'dongfong') { // dongfong IP hack
if(preg_match('/^(\d+)\.(\d+)-(\d+)\-[a-z]+(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'mesh') { // mesh.ad.jp IP hack (partly)
if(preg_match('/^\w+\-(\d+\-\d+)-\d+\-\d+/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'deloitte') { // deloitte IP hack
if(preg_match('/^\w+\-(\d+\-\d+)-\d+/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'iprimus') { // iprimus IP hack
if(preg_match('/^\d+\.\d+\-(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'tm') { // tm.net.my IP hack ( *-home, *-hsbb only)
if(preg_match('/^\d+\.\d+\.(\d+)\.(\d+)\.\w+\-(home|hsbb)/',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[0];
elseif(preg_match('/(\d+)\.(\d+)\.in-addr/',$iphost,$ipparts)) // in-addr hack
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == '163data' || $parts[1] == 'cta') { // 163data/cta IP hack
if(preg_match('/^\d+\.\d+\.(\d+)\.(\d+)\./',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif($parts[1] == 'zaq') { // zaq IP hack
if(preg_match('/^zaq([0-9a-f]{2})([0-9a-f]{2})[0-9a-f]{2}[0-9a-f]{2}\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[1]).'-'.hexdec($ipparts[2]).'-*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
// dion/kcn-tv/janis/panda-world/coralnet IP hack
} elseif($parts[1] == 'dion' || $parts[1] == 'kcn-tv' || $parts[1] == 'janis' || $parts[1] == 'panda-world' || $parts[1] == 'coralnet') {
if(preg_match('/^[a-z]*(\d{3})(\d{3})/',$iphost,$ipparts))
$parthost = intval($ipparts[1]).'.'.intval($ipparts[2]).'.*.'.$parts[0];
else
$parthost = '*.'.$parts[0];
} elseif(preg_match('/tinp$/',$parts[1])) { // tinp IP hack 2
if(preg_match('/^(\d+)\-(\d+)-(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[4].'-'.$ipparts[3].'-*.tinp.com.tw';
else
$parthost = '*.'.$parts[0];
} else {
$parthost = '*.'.$parts[0];
}
} else {
if($parts[2] == 'wanadoo' && $parts[3] == 'fr') { // wanadoo.fr IP hack
if(preg_match('/^[\w\-]+\.[a-z]{1}(\d+-\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
// corbina/j-cnet/numericable/telekom.at/tele2.se/tele2.at/kou/bbiq/inode/superkabel/novis.pt/maconet.cz/quicknet.nl/pbthawe.eu IP hack
} elseif($parts[2] == 'corbina' || $parts[2] == 'j-cnet' || $parts[2] == 'numericable'
|| $parts[2] == 'telekom' || $parts[2] == 'tele2' || $parts[2] == 'kou' || $parts[2] == 'bbiq'
|| $parts[2] == 'inode' || $parts[2] == 'superkabel' || $parts[2] == 'novis' || $parts[2] == 'maconet' || $parts[2] == 'quicknet' || $parts[2] == 'pbthawe') {
if(preg_match('/^[a-z]?(\d+\-\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
// commufa/unitymediagroup/yaroslavl/otenet/scarlet/netcabo/mtu-net/eunet/chello.nl/chello.pl/net-htp/upc/t3/telfort/qsc/comhem/
// mnet-online/upcbroadband/scarlet.be/ownit/itscom/sk.ca/swipnet.se/nextra.sk/nationalcablenetworks.ru/netcologne.de IP hack
} elseif($parts[2] == 'commufa' || $parts[2] == 'unitymediagroup' || $parts[2] == 'yaroslavl'
|| $parts[2] == 'otenet' || $parts[2] == 'scarlet' || $parts[2] == 'netcabo' || $parts[2] == 'mtu-net'
|| $parts[2] == 'eunet' || $parts[2] == 'chello' || $parts[2] == 'net-htp' || $parts[2] == 'upc'
|| $parts[2] == 't3' || $parts[2] == 'telfort' || $parts[2] == 'qsc' || $parts[2] == 'comhem'
|| $parts[2] == 'mnet-online' || $parts[2] == 'upcbroadband' || $parts[2] == 'scarlet' || $parts[2] == 'ownit'
|| $parts[2] == 'itscom' || $parts[2] == 'sk' || $parts[2] == 'swipnet' || $parts[2] == 'nextra'
|| $parts[2] == 'nationalcablenetworks' || $parts[2] == 'netcologne') {
if(preg_match('/^[a-z]*-?(\d+\-\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
elseif($parts[2] == 'chello' && $parts[3] == 'pl') { // chello.pl IP hack
if(preg_match('/^[a-z]*(\d{3})(\d{3})\d{3}\d{3}/',$iphost,$ipparts))
$parthost = intval($ipparts[1]).'-'.intval($ipparts[2]).'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'bbexcite' || $parts[2] == 'estpak' || $parts[2] == 'sx' || $parts[2] == 'cdi') { // bbexcite/estpak/sx.cn/cdi.no IP hack
if(preg_match('/^(\d+)\.(\d+)\.(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[4].'-'.$ipparts[3].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'zoot') { // zoot IP hack
if(preg_match('/^(\d+)\.(\d+)\.(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'bell') { // bell.ca IP hack
if(preg_match('/^\w+\-\w+\-(\d+)\./',$iphost,$ipparts)) {
$ipparts = explode('.',long2ip($ipparts[1]));
$parthost = $ipparts[0].'-'.$ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
} else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'tiscali') { // tiscali.it IP hack
if(preg_match('/^\w+\-\w+\-(\d+\-\d+)\-/',$iphost,$ipparts)) {
$parthost = $ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
} else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'dbnet') { // dbnet.dk IP hack
if(preg_match('/^(\d+)\./',$iphost,$ipparts)) {
$ipparts = explode('.',long2ip($ipparts[1]));
$parthost = $ipparts[0].'-'.$ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
} else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'mm') { // mm.pl IP hack
if(preg_match('/^[\w]+-(\d+\-\d+)\-/',$iphost,$ipparts)) {
$parthost = $ipparts[1].'-*.'.$parts[0]; //include subdomain
} else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'club-internet') { // club-internet IP hack
if(preg_match('/^\w+\-\d+\-(\d+)\-(\d+)\-(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'kabel-badenwuerttemberg') { // kabel-badenwuerttemberg IP hack
if(preg_match('/^\w+\-\w+\-(\d+\-\d+)\-\d+\-\d+/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'telecomitalia') { // telecomitalia IP hack
if(preg_match('/^[\w\-]+\.(\d+)\-(\d+)\-/',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'belgacom' || $parts[2] == 'videotron') { // belgacom/videotron IP hack
if(preg_match('/^[a-z]*\d+\.\d+\-(\d+)\-(\d+)\./',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'orange') { // orange.es IP hack
if(preg_match('/^\d+\.[a-z]+(\d+)\-(\d+)\-/',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'libero' || $parts[2] == 'net24') { // libero.it/net24.it IP hack
if(preg_match('/^[\w\-]+\.(\d+)\-(\d+)\./',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'sh') { // sh.cn IP hack
if(preg_match('/^\w+\-\d+\-(\d+)\-(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'su29' || $parts[2] == 'getinternet') { // su29.ru/getinternet.no IP hack
if(preg_match('/^[a-z]+\-(\d+)\.(\d+)\./',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'wcgwave' ||$parts[2] == 'hol') { // wcgwave/hol.gr IP hack
if(preg_match('/^[a-z]+(\d{3})(\d{3})\d{3}\d{3}/',$iphost,$ipparts))
$parthost = intval($ipparts[1]).'-'.intval($ipparts[2]).'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'bredbandsbolaget') { // bredbandsbolaget IP hack
if(preg_match('/^\w+\-[0-9a-f]{2}[0-9a-f]{2}([0-9a-f]{2})([0-9a-f]{2})\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[2]).'-'.hexdec($ipparts[1]).'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'ucd') { // ucd.ie IP hack
if(preg_match('/^\w+\-([0-9a-f]{2})([0-9a-f]{2})[0-9a-f]{2}[0-9a-f]{2}\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[1]).'-'.hexdec($ipparts[2]).'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'cybercity' || $parts[2] == 'ziggozakelijk' || $parts[2] == 'enternet') { // cybercity.dk/ziggozakelijk.nl/enternet.hu IP hack
if(preg_match('/^(0x)?([0-9a-f]{2})([0-9a-f]{2})[0-9a-f]{2}[0-9a-f]{2}\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[2]).'-'.hexdec($ipparts[3]).'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} elseif($parts[2] == 'mdcc-fun') { // mdcc-fun.de IP hack
if(preg_match('/^\w+\-\w+\-(\d+-\d+)-\d+-\d+/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
// gavle/t-ipconnect/telenet/direct-adsl/wanadoo.nl/catch.no IP hack
} elseif($parts[2] == 'gavle' || $parts[2] == 't-ipconnect' || $parts[2] == 'telenet' || $parts[2] == 'direct-adsl'
|| $parts[2] == 'wanadoo' || $parts[2] == 'catch') {
if(preg_match('/^[a-z]([0-9a-f]{2})([0-9a-f]{2})[0-9a-f]{2}[0-9a-f]{2}\./',$iphost,$ipparts))
$parthost = hexdec($ipparts[1]).'-'.hexdec($ipparts[2]).'-*.'.$parts[2].'.'.$parts[3];
elseif($parts[2] == 'telenet' && preg_match('/^(\d+\-\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-*.'.$parts[2].'.'.$parts[3];
else
$parthost = '*.'.$parts[2].'.'.$parts[3];
} else {
$parthost = '*.'.$parts[2].'.'.$parts[3];
}
}
break;
}
}
} else {
$parthost = '*.'.$parts[0];
}
if(!$iscctld && !$isgtld) {
if($parts[1] == 'in-addr' && $parts[2] == 'arpa') { // in-addr.apra hack
if(preg_match('/(\d+)\.(\d+)\.in-addr/',$iphost,$ipparts))
$parthost = $ipparts[2].'-'.$ipparts[1].'-*.'.$parts[1].'.'.$parts[2];
else
$parthost = '*.'.$parts[1].'.'.$parts[2];
} elseif($parts[1] == 'ha' && $parts[2] == 'cnc') { // ha.cnc IP hack
if(preg_match('/^(\d+)\.(\d+)\.(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[4].'-'.$ipparts[3].'-*.'.$parts[1].'.'.$parts[2];
else
$parthost = '*.'.$parts[1].'.'.$parts[2];
} elseif(preg_match('/-bj-cnc$/',$parts[2])) { // *-bj-cnc IP hack
if(preg_match('/^(\d+)\.(\d+)\.(\d+)\.(\d+)/',$iphost,$ipparts))
$parthost = $ipparts[1].'-'.$ipparts[2].'-*.BJ-CNC';
else
$parthost = '*.'.$parts[2];
} else
$parthost = $iphost; // unresolvable
}
}
} else {
$parthost = $iphost; // unresolvable
}
 
$arrLabels['{$NOW}'] .= ' (Host: '.$parthost.')';
}
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
}
?>
New file
/release/Modules-PIO-v6/mod_code/howto.txt
@@ -0,0 +1,18 @@
License:
 
dp.SyntaxHighlighter is licensed under GNU Lesser Public License. Copyright ©2004-2007 Alex Gorbatchev, http://code.google.com/p/syntaxhighlighter/
mod_code is not a part of Pixmicat! package. So it's not licensed under the Clarified Artistic License. It's in the public domain.
 
中文安裝指引:
 
1. 下載 SyntaxHighlighter (http://code.google.com/p/syntaxhighlighter/) 儲存
2. 將 mod_code.php, 1. 解壓後的 dp.SyntaxHighlighter/Scripts 目錄檔案及 dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css 放到 module/ 目錄
3. 修改 config.php,在模組載入區塊下加一行 $ModuleList[] = 'mod_code';
4. 程式問題,在 XHTML 模式下會無法作用,可將 USE_XHTML 設為 0 取消
 
English Instruction:
 
1. Download the SyntaxHighlighter from the SyntaxHighlighter project page (http://code.google.com/p/syntaxhighlighter/).
2. Put the following files into the module/ directory: "mod_code.php", "shCore.js", "SyntaxHighlighter.css" and all "shBrushXxx.js."
3. Use your favorite editor to open the "config.php" and add one line ($ModuleList[] = 'mod_code';) into the "Modules to be loaded" block.
4. You can change the value of USE_XHTML to 0 to avoid display problem in XHTML parsing mode.
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_code/mod_code.php
@@ -0,0 +1,45 @@
<?php
class mod_code{
var $brushes;
 
function getModuleName(){
return 'mod_code : dp.SyntaxHighlighter Embedded';
}
 
function getModuleVersionInfo(){
return '4th.Release.3 (v080520)';
}
 
function autoHookHead(&$dat){
$dat .= <<< _EOF_
<link rel="stylesheet" type="text/css" href="module/SyntaxHighlighter.css" />
 
_EOF_;
}
 
function autoHookPostInfo(&$postinfo){
$postinfo .= '<li>程式碼可使用 [code=類型][/code] 以 dp.SyntaxHighlighter 標亮 (<a href="http://code.google.com/p/syntaxhighlighter/wiki/Languages" rel="_blank">類型列表</a>)</li>'."\n";
}
 
function _textarea($s){
return '<textarea name="code" cols="48" rows="6" class="'.$s[1].'">'.str_replace('<br />', "\n", $s[2]).'</textarea>';
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
extract($post);
if(strpos($arrLabels['{$COM}'], '[/code]')===false) return;
 
$arrLabels['{$COM}'] = preg_replace_callback('/\[code=(\S*?)\](.*?)\[\/code\]/us', array(&$this, '_textarea'), $arrLabels['{$COM}']);
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
function autoHookFoot(&$dat){
$dat .= '<script type="text/javascript" src="module/mod_code.js"></script>
<script type="text/javascript" src="module/shCore.js"></script>
<script type="text/javascript">Tdp.SyntaxHighlighter(\'code\');</script>'."\n";
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_code/mod_code.js
@@ -0,0 +1,75 @@
if(!Array.prototype.indexOf){ // Implemented in JavaScript 1.6
Array.prototype.indexOf = function(elt /*, from*/){
var len = this.length;
var from = Number(arguments[1]) || 0;
from = from < 0 ? Math.ceil(from) : Math.floor(from);
if(from < 0){ from += len; }
 
for(; from < len; from++){
if(from in this && this[from] === elt){ return from; }
}
return -1;
};
}
 
// dp.SyntaxHighlighter 動態載入
var Tdp = {
Sensor : { // 一些有用數值
Name : '', // dp.SyntaxHighlighter 作用欄位名稱
Interval : null, // dp.sh.Brushes Check Interval
LibLoaded : [] // 載入函式庫
},
Alias : { // 別名資料庫
Cpp : ['cpp', 'c', 'c++'],
CSharp : ['c#', 'c-sharp', 'csharp'],
Css : ['css'],
Delphi : ['delphi', 'pascal'],
Java : ['java'],
JScript : ['js', 'jscript', 'javascript'],
Php : ['php'],
Python : ['py', 'python'],
Ruby : ['rb', 'ruby', 'rails', 'ror'],
Sql : ['sql'],
Vb : ['vb', 'vb.net'],
Xml : ['xml', 'html', 'xhtml', 'xslt']
},
/* 動態載入 */
SyntaxHighlighter : function (taName){
Tdp.Sensor.Name = taName; // 設定作用欄位名
var tas = document.getElementsByTagName('textarea');
var sc, tx;
for(var i = 0, tl = tas.length; i < tl; i++){ // 逐一搜尋欄位
tx = tas[i];
if(tx.getAttribute('name') == taName){
for(var a in Tdp.Alias){ // 逐一搜尋程式類別
if(Tdp.Alias[a].indexOf(tx.className.toLowerCase()) != -1){ // 找到
Tdp.Sensor.LibLoaded.push(a); delete Tdp.Alias[a]; // 推入載入名單
break;
}
}
}
}
var libcount = Tdp.Sensor.LibLoaded.length;
if(libcount === 0){ return; } // 未使用直接跳出
 
var insertnode = document.getElementsByTagName('head')[0];
for(var j = 0; j < libcount; j++){ // 動態載入
sc = document.createElement('script');
sc.type = 'text/javascript';
sc.src = 'module/shBrush' + Tdp.Sensor.LibLoaded[j] + '.js';
insertnode.appendChild(sc);
}
Tdp.Sensor.Interval = setInterval(Tdp.executeSyntaxHighlighter, 1000); // 設定 Interval
},
/* 確定全部載入完成,執行標亮 */
executeSyntaxHighlighter : function(){
if(typeof dp==='undefined'){ return false; } // dp Not ready
for(var lib in Tdp.Sensor.LibLoaded){
if(typeof dp.sh.Brushes[Tdp.Sensor.LibLoaded[lib]]==='function'){ Tdp.Sensor.LibLoaded.splice(lib, 1); }
}
if(Tdp.Sensor.LibLoaded.join('')===''){
clearInterval(Tdp.Sensor.Interval);
dp.SyntaxHighlighter.HighlightAll(Tdp.Sensor.Name); // dp.SyntaxHighlighter
}
}
};
New file
/release/Modules-PIO-v6/mod_tag/mod_tag.php
@@ -0,0 +1,225 @@
<?php
class mod_tag{
var $mypage;
 
function mod_tag(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 向系統登記模組專屬獨立頁面
$this->mypage = $PMS->getModulePageURL(__CLASS__);
 
AttachLanguage(array($this, '_loadLanguage')); // 載入語言檔
 
}
 
/* Get the name of module */
function getModuleName(){
/* 注意: 這個插件大部分的原碼來自 mod_opentag 以及 pixmicat 內建的 "category" 功能。
絕大部分還是剪貼過來的, 而且本插件採用相同的資料庫欄位。因此,本插件不會修改
您的資料庫格式。但是您不能同時採用這個插件以及內建的 "category" 功能。
簡單說,這個插件修改程式基本作業,廢掉內建的 "category" 來提供更實用的標籤系統。
 
本插件採取類似論壇軟體的標籤系統,只允許 OP 帖可以有標籤。搜尋的時候自動調用
整串討論出來。如果您需要允許每篇回覆都有自己的標籤,請用內建的 "category" 功能。
*/
return 'mod_tag : 標籤編輯系統';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return 'Alpha Release (svn: r648++)';
}
 
function autoHookHead(&$txt, $isReply){
$txt .= '<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript">
// <![CDATA[
jQuery(function($){
$("div.category a.change").click(function(){
var tag = "";
var no = this.href.match(/&no=([0-9]+)/) ? RegExp.$1 : 0;
var obj = $(this);
obj.siblings("a").each(function(){ tag += "," + this.innerHTML; });
obj.parent().html("<input type=\'text\' id=\'attrTag" + no + "\' size=\'28\'><input type=\'button\' value=\'Tag!\' id=\'sendTag" + no + "\'>");
$g("attrTag" + no).value = tag.substr(1);
$("#sendTag" + no).click(function(){
var tmpthis = this;
$.post("'.str_replace('&amp;', '&', $this->mypage).'&no=" + no, {ajaxmode: true, tag: this.previousSibling.value}, function(newTag){
newTag = $.map(newTag.split(","), function(n){
return n.link("pixmicat.php?mode=module&load=mod_tag&do=search&c=" + encodeURI(n));
});
tmpthis.parentNode.innerHTML = newTag.join(", ");
});
});
return false;
});
});
// ]]>
</script>';
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
global $language;
// 改變 category 顯示規定
if ($post["resto"] == 0) {
// if (!$isReply) {
// OP,把連結改到我們的 tag search
$arrLabels['{$CATEGORY}'] = str_replace("mode=category&amp;c=", "mode=module&amp;load=mod_tag&amp;do=search&amp;c=", $arrLabels['{$CATEGORY}']);
$arrLabels['{$CATEGORY}'] = "<span>".$arrLabels['{$CATEGORY}']." [<a href='".$this->mypage."&amp;no=".$post['no']."' class='change'>" . $language['modtag_edit'] . "</a>]</span>";
} else {
// 回文,刪除 category 資料
$arrLabels['{$CATEGORY}'] = '';
}
}
function autoHookThreadReply(&$arrLabels, $post, $isReply){
// 導向至 autoHookThreadPost 來一起處理
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
function autoHookPostForm(&$form){
// 很白目的隱藏表單上 category 的欄位的辦法
if (isset($_GET['res']) || (isset($_GET['no']) && ($_GET['load'] == "mod_edit"))) {
global $PTE;
// 從回文的表單上移除標籤欄位
$what = '<tr><td class="Form_bg"><b>{$FORM_CATEGORY_TEXT}</b></td><td>{$FORM_CATEGORY_FIELD}<small>{$FORM_CATEGORY_NOTICE}</small></td></tr>';
$PTE->tpl = str_replace($what, "", $PTE->tpl);
}
}
 
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status) {
// 移除回文的 category
if ($isReply) {
$category = "";
}
}
 
 
function ModulePage(){
global $PIO, $PTE;
if(!isset($_GET['do'])) {
// 沒有 "do" 指令,舊的 tag 連接
if(!isset($_GET['no'])) die('[Error] not enough parameter.');
if(!isset($_POST['tag'])) {
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
$pte_vals = array('{$TITLE}'=>TITLE, '{$RESTO}'=>'');
$dat = $PTE->ParseBlock('HEADER', $pte_vals);
$dat .= '</head><body id="main">';
$dat .= '<form action="'.$this->mypage.'&amp;no='.$_GET['no'].'" method="POST">Tag: <input type="text" name="tag" value="'.htmlentities(substr(str_replace('&#44;', ',', $post[0]['category']),1,-1), ENT_QUOTES, 'UTF-8').'" size="28" /><input type="submit" name="submit" value="Tag!" /></form>';
echo $dat."</body></html>";
} else {
$Tag = CleanStr($_POST['tag']);
if($_SERVER['REQUEST_METHOD'] != 'POST') error(_T('regist_notpost')); // 非正規POST方式
$post = $PIO->fetchPosts($_GET['no']);
$parentNo = $post[0]['resto'] ? $post[0]['resto'] : $post[0]['no'];
$threads = array_flip($PIO->fetchThreadList());
$threadPage = floor($threads[$parentNo] / PAGE_DEF);
if(!count($post)) die('[Error] Post does not exist.');
$ss = method_exists($PIO, '_replaceComma') ? '&#44;' : ','; // Dirty implement
$category = explode(',', $Tag); // 把標籤拆成陣列
$category = $ss.implode($ss, array_map('trim', $category)).$ss; // 去空白再合併為單一字串 (左右含,便可以直接以,XX,形式搜尋)
$PIO->updatePost($_GET['no'], array('category'=>$category));
$PIO->dbCommit();
if(STATIC_HTML_UNTIL == -1 || $threadPage <= STATIC_HTML_UNTIL) updatelog(0, $threadPage, true); // 僅更新討論串出現那頁
deleteCache(array($parentNo)); // 刪除討論串舊快取
 
if(isset($_POST['ajaxmode'])){
echo $Tag;
}else{
header('HTTP/1.1 302 Moved Temporarily');
header('Location: '.fullURL().PHP_SELF2.'?'.time());
}
}
} else {
// 有 "do" 指令,查看下一步
if ($_GET['do'] == "search") {
// 搜尋符合標籤的主題
global $PTE, $PIO, $PMS, $FileIO, $language;
$category = isset($_GET['c']) ? strtolower(strip_tags(trim($_GET['c']))) : ''; // 搜尋之類別標籤
if(!$category) error(_T('category_nokeyword'));
$category_enc = urlencode($category); $category_md5 = md5($category);
$page = isset($_GET['p']) ? @intval($_GET['p']) : 1; if($page < 1) $page = 1; // 目前瀏覽頁數
$isrecache = isset($_GET['recache']); // 是否強制重新生成快取
 
// 利用Session快取類別標籤出現篇別以減少負擔
session_start(); // 啟動Session
if(!isset($_SESSION['loglist_'.$category_md5]) || $isrecache){
$loglist = $PIO->searchCategory($category);
$_SESSION['loglist_'.$category_md5] = serialize($loglist);
}else $loglist = unserialize($_SESSION['loglist_'.$category_md5]);
 
$loglist_count = count($loglist);
if(!$loglist_count) error(_T('category_notfound'));
$page_max = ceil($loglist_count / PAGE_DEF); if($page > $page_max) $page = $page_max; // 總頁數
 
// 分割陣列取出適當範圍作分頁之用
$loglist_cut = array_slice($loglist, PAGE_DEF * ($page - 1), PAGE_DEF); // 取出特定範圍文章
$loglist_cut_count = count($loglist_cut);
 
$dat = '';
head($dat);
$links = '[<a href="'.PHP_SELF2.'?'.time().'">'._T('return').'</a>][<a href="'.PHP_SELF.'?mode=module&amp;load=mod_tag&amp;do=search&amp;c='.$category_enc.'&amp;recache=1">'._T('category_recache').'</a>]';
$PMS->useModuleMethods('LinksAboveBar', array(&$links,'category'));
$dat .= "<div>$links</div>\n";
for($i = 0; $i < $loglist_cut_count; $i++){
$tID = $loglist_cut[$i];
$tree_count = $PIO->postCount($tID) - 1; // 討論串回應個數
$RES_start = $tree_count - RE_DEF + 1; if($RES_start < 1) $RES_start = 1; // 開始
$RES_amount = RE_DEF; // 取幾個
$hiddenReply = $RES_start - 1; // 被隱藏回應
// $RES_start, $RES_amount 拿去算新討論串結構 (分頁後, 部分回應隱藏)
$tree = $PIO->fetchPostList($tID); // 整個討論串樹狀結構
$tree_cut = array_slice($tree, $RES_start, $RES_amount); array_unshift($tree_cut, $tID); // 取出特定範圍回應
$posts = $PIO->fetchPosts($tree_cut); // 取得文章架構內容
$dat .= arrangeThread($PTE, $tree, $tree_cut, $posts, $hiddenReply, 0, array(), array(), false, false, false);
}
 
$dat .= '<table border="1"><tr>';
if($page > 1) $dat .= '<td><form action="'.PHP_SELF.'?mode=module&amp;load=mod_tag&amp;do=search&amp;c='.$category_enc.'&amp;p='.($page - 1).'" method="post"><div><input type="submit" value="'._T('prev_page').'" /></div></form></td>';
else $dat .= '<td style="white-space: nowrap;">'._T('first_page').'</td>';
$dat .= '<td>';
for($i = 1; $i <= $page_max ; $i++){
if($i==$page) $dat .= "[<b>".$i."</b>] ";
else $dat .= '[<a href="'.PHP_SELF.'?mode=module&amp;load=mod_tag&amp;do=search&amp;c='.$category_enc.'&amp;p='.$i.'">'.$i.'</a>] ';
}
$dat .= '</td>';
if($page < $page_max) $dat .= '<td><form action="'.PHP_SELF.'?mode=module&amp;load=mod_tag&amp;do=search&amp;c='.$category_enc.'&amp;p='.($page + 1).'" method="post"><div><input type="submit" value="'._T('next_page').'" /></div></form></td>';
else $dat .= '<td style="white-space: nowrap;">'._T('last_page').'</td>';
$dat .= '</tr></table>'."\n";
 
foot($dat);
echo $dat;
} else if ($_GET['do'] == "cloud") {
// 建立 tag cloud?
// blah blah blah
} else {
// 不知道該如何處理的 "do" 指令
echo "スクリプトはTranslation Server Errorに免費の午餐を食べています!<br />";
echo "...你想表達什麼?";
}
}
}
 
function _loadLanguage(){
// 載入語言
global $language;
if(PIXMICAT_LANGUAGE != 'zh_TW' && PIXMICAT_LANGUAGE != 'ja_JP' && PIXMICAT_LANGUAGE != 'en_US') $lang = 'en_US';
else $lang = PIXMICAT_LANGUAGE;
 
if($lang=='zh_TW'){
$language['modtag_tag'] = '標籤';
$language['modtag_separate_with_comma'] = '請以 , 逗號分隔多個標籤';
$language['modtag_edit'] = '編輯';
}elseif($lang=='ja_JP'){
$language['modtag_tag'] = 'タグ';
$language['modtag_separate_with_comma'] = '半形カンマ(,)でタグを個別してください。';
$language['modtag_edit'] = '編集';
}elseif($lang=='en_US'){
$language['modtag_tag'] = 'Tags';
$language['modtag_separate_with_comma'] = 'Please separate tags with a single comma [,]';
$language['modtag_edit'] = 'Edit';
}
}
}
?>
New file
/release/Modules-PIO-v6/mod_tripcheck/mod_tripcheck.php
@@ -0,0 +1,94 @@
<?php
class mod_tripcheck{
var $TRIPFILE,$TRIPPOST_THREAD,$TRIPPOST_THREAD_REGED,$TRIPPOST_REPLY,$TRIPPOST_REPLY_REGED;
function mod_tripcheck(){
$this->TRIPFILE = 'board.trip'; // トリップ記錄檔檔名
$this->TRIPPOST_THREAD = 1; // 發新討論串需要トリップ (是:1 否:0)
$this->TRIPPOST_THREAD_REGED = 1; // 發新討論串需要已登錄的トリップ (是:1 否:0)
$this->TRIPPOST_REPLY = 0; // 回文需要トリップ (是:1 否:0)
$this->TRIPPOST_REPLY_REGED = 0; // 回文需要已登錄的トリップ (是:1 否:0)
}
 
function getModuleName(){
return 'mod_tripcheck : Trip限制模組';
}
 
function getModuleVersionInfo(){
return 'v071119';
}
 
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status){
$trip='';
if(($trippos=strpos($name,_T('trip_pre')))!==false) {
$trip=substr($name,$trippos+strlen(_T('trip_pre')),10);
if((!$isReply && $this->TRIPPOST_THREAD && $this->TRIPPOST_THREAD_REGED)||($isReply && $this->TRIPPOST_REPLY && $this->TRIPPOST_REPLY_REGED)) {
$tres=$this->_tripCheck($trip);
switch($tres) {
case 'OK':
break;
case 'BN':
error("Trip已被封鎖",$dest);
case 'NA':
error("Trip未啟用",$dest);
case 'NF':
error("Trip無效",$dest);
}
}
}else{
if(!$isReply && $this->TRIPPOST_THREAD) error("發文需要Trip",$dest);
if($isReply && $this->TRIPPOST_REPLY) error("回文需要Trip",$dest);
}
}
 
function autoHookLinksAboveBar(&$link, $pageId, $addinfo=false) {
if($pageId == 'admin') $link.=' [<a href="tripadmin.php">Trip管理</a>]';
}
 
function autoHookAuthenticate($pass, $act, &$result){
if(!$result) $result = ($this->_tripPermission($this->_tripping(substr($pass,1))) == 'OK');
}
 
function _tripCheck($trip) {
$res='NF';
if(!$this->_tripFormat($trip)) return $res;
$TripList = @file($this->TRIPFILE);
 
if(is_array($TripList)) {
foreach($TripList as $tripline){
@list($szTrip,$szTime,$szIP,$szActivate,$szBan) = @explode("<>", trim($tripline));
if($trip==$szTrip && $szActivate && !$szBan) {$res='OK'; break;}
elseif($trip==$szTrip && !$szActivate) {$res='NA'; break;}
elseif($trip==$szTrip && $szBan) {$res='BN'; break;}
}
}
return $res;
}
 
function _tripPermission($trip) {
$res='NF';
if(!$this->_tripFormat($trip)) return $res;
$TripList = @file($this->TRIPFILE);
 
if(is_array($TripList)) {
foreach($TripList as $tripline){
@list($szTrip,$szTime,$szIP,$szActivate,$szBan,$szDelPerm) = @explode("<>", trim($tripline));
if($trip==$szTrip && $szActivate && !$szBan && $szDelPerm) {$res='OK'; break;}
else {$res='NG'; break;}
}
}
return $res;
}
 
function _tripFormat($trip) {
return strlen($trip) == 10;
}
 
function _tripping($str) {
$salt = preg_replace('/[^\.-z]/', '.', substr($str.'H.', 1, 2));
$salt = strtr($salt, ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
return substr(crypt($str, $salt), -10);
}
 
}
?>
New file
/release/Modules-PIO-v6/mod_tripcheck/README.txt
@@ -0,0 +1 @@
tripadmin.php should place in same directory as config.php
New file
/release/Modules-PIO-v6/mod_tripcheck/tripadmin.php
@@ -0,0 +1,287 @@
<?php
include_once('./config.php');
define("TRIPFILE", 'board.trip'); // トリップ記錄檔檔名
define("ALLOW_TRIP_REG", '1'); // 容許一般使用者註冊トリップ (是:1 否:0)
 
$action='';$viewstart=0;$viewend=100;
extract($_POST);
extract($_GET);
 
// ファイル全体読み込み
function FileRead($szFileName) {
if(!file_exists("$szFileName")) SysError("<B>$szFileName</B> をオープンできません");
return @file("$szFileName");
}
// ファイル書き込み
function FileWrite($szFileName, &$writedata, $bMode = "w") {
if($bMode != "a" && $bMode != "w"){ $bMode = "w"; }
// Windowsシステムのためバイナリモードを付加しておく
if(substr($bMode, -1) != "b"){ $bMode .= "b"; }
if(!($fp = @fopen("$szFileName", $bMode))){ SysError("<B>$szFileName</B> をオープンできません"); }
flock($fp, 2);
fwrite($fp, $writedata);
fclose($fp);
}
// ファイル消去
function FileFlush($szFileName) {
if(!($fp = @fopen("$szFileName", "wb"))){ SysError("<B>$szFileName</B> をオープンできません"); }
flock($fp, 2);
fwrite($fp, "");
fclose($fp);
}
// 不要文字列除去($str:文字列)
function CleanStr(&$szStr) {
if(get_magic_quotes_gpc()){ $szStr = stripslashes($szStr); }
$szStr = htmlspecialchars($szStr);
$szStr = str_replace(",", "&#44;", $szStr);
return chop(str_replace("&amp;", "&", $szStr));
}
// システムエラー
function SysError($text) {
echo '<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>ERROR!</TITLE>
</HEAD>
<body>
<FONT size="+1" color="#FF0000"><B>ERROR:'.$text.'</B></FONT>
<BR><BR>
';
HtmlFooter(1);
exit();
}
 
function HtmlHeader() {
// HTMLヘッダー
echo '<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>トリップ事務所</TITLE>
</HEAD>
<body>
<H2><FONT face="Arial">トリップ事務所 for futaba</FONT></H2>
<HR noshade size="1">
';
}
 
function HtmlFooter($self=0) {
$PHPSELF=$self?$_SERVER['PHP_SELF']:PHP_SELF2;
// HTMLフッター
echo <<<HTML
<HR noshade size="1">
【 <A href="$PHPSELF">Return</A> 】
<HR noshade size="1">
<div align="right"><FONT size="1">tripadmin.php(adopted from ThreadBBS)</FONT></div>
</BODY>
</HTML>
HTML;
exit();
}
 
function check_login($forcelogin=1) {
if (!isset($_SESSION['username']) || !isset($_SESSION['password'])) {
$logged_in=0;
if($forcelogin) SysError("ユーザーの認証が必要です。<br /><form action=\"".$_SERVER['PHP_SELF']."?action=login\" method=\"POST\">ユーザー:<INPUT type=\"text\" name=\"username\"><br />パスワード:<INPUT type=\"password\" name=\"password\"><INPUT type=\"submit\" value=\"認証\"></form>");
else return $logged_in;
} else {
if($_SESSION['username']!=CAP_NAME || $_SESSION['password']!=CAP_PASS) {
$logged_in=0;
unset($_SESSION['username']);
unset($_SESSION['password']);
// kill incorrect session variables.
if($forcelogin) SysError("ユーザーの認証が必要です。<br /><form action=\"".$_SERVER['PHP_SELF']."?action=login\" method=\"POST\">ユーザー:<INPUT type=\"text\" name=\"username\"><br />パスワード:<INPUT type=\"password\" name=\"password\"><INPUT type=\"submit\" value=\"認証\"></form>");
else return $logged_in;
}else {
// valid password for username
$logged_in = 1; // they have correct info
return $logged_in; // in session variables.
}
}
}
 
$goto=0;
session_start();
 
switch($action){
case 'logout':
unset($_SESSION['username']);
unset($_SESSION['password']);
echo "<META http-equiv=\"refresh\" content=\"1;URL=$_SERVER[PHP_SELF]\">";
echo "ログアウトしました。<br />数秒後にページが自動的に切り変わります。<br />しばらく待っても変わらない場合は、<a href=\"$_SERVER[PHP_SELF]\">こちら</a>をクリックしてください。";
break;
case 'login':
if(isset($_POST['username'])&&isset($_POST['password'])) {
$_SESSION['username']=$_POST['username'];
$_SESSION['password']=$_POST['password'];
}
check_login();
echo "<META http-equiv=\"refresh\" content=\"1;URL=$_SERVER[PHP_SELF]\">";
echo "ログインしました。<br />数秒後にページが自動的に切り変わります。<br />しばらく待っても変わらない場合は、<a href=\"$_SERVER[PHP_SELF]\">こちら</a>をクリックしてください。";
break;
case 'manage':
check_login();
$delflag = isset($_POST["del"]); // 是否有「削除」勾選
$actflag = isset($_POST["act"]); // 是否有「有効」勾選
$banflag = isset($_POST["ban"]); // 是否有「禁止」勾選
$dpflag = isset($_POST["dp"]); // 是否有「削除人」勾選
 
if($delflag || $actflag || $banflag || $dpflag) {
$aTripList = FileRead(TRIPFILE);
$szTemp = "";
while(list(, $val) = @each($aTripList)){
$bFlag = TRUE;
@list($szTrip,$szTime,$szIP,$szActivate,$szBan,$szDelPerm) = @explode("<>", $val);
if($banflag) {
reset($_POST["ban"]);
while(list(, $tTrip) = @each($_POST["ban"])){
if($szTrip == $tTrip){ $val = "$szTrip<>$szTime<>$szIP<>$szActivate<>".($szBan=!$szBan)."<>$szDelPerm<>\n"; break; }
}
}
if($dpflag) {
reset($_POST["dp"]);
while(list(, $tTrip) = @each($_POST["dp"])){
if($szTrip == $tTrip){ $val = "$szTrip<>$szTime<>$szIP<>$szActivate<>$szBan<>".($szDelPerm=!$szDelPerm)."<>\n"; break; }
}
}
if($actflag) {
reset($_POST["act"]);
while(list(, $tTrip) = @each($_POST["act"])){
if($szTrip == $tTrip){ $val = "$szTrip<>$szTime<>$szIP<>1<>$szBan<>$szDelPerm<>\n"; break; }
}
}
if($delflag) {
reset($_POST["del"]);
while(list(, $tTrip) = @each($_POST["del"])){
if($szTrip == $tTrip){ $bFlag = FALSE; break; }
}
}
if($bFlag){ $szTemp .= $val; }
}
FileWrite(TRIPFILE, $szTemp, "w");
HtmlHeader();
echo "<BR>処理しました。<BR><BR>";
}
$goto=1;
break;
case 'add':
if(preg_match("/(#|#)(.*)/",$triptext,$regs)){
$cap = $regs[2];
$cap = strtr($cap,array("&amp;"=>"&","&#44;"=>","));
$salt = substr($cap."H.",1,2);
$salt = preg_replace("/[^\.-z]/",".",$salt);
$salt = strtr($salt,":;<=>?@[\\]^_`","ABCDEFGabcdef");
$trip=substr(crypt($cap,$salt),-10);
}else{
SysError("フォーマットは正しくない。");
}
$aTripList = FileRead(TRIPFILE);
$bFlag = FALSE;
while(list(,$val) = @each($aTripList)){
list($szTrip,) = explode("<>", $val);
if($trip == $szTrip){ $bFlag = TRUE; break; }
}
if($bFlag){ SysError("同じトリップが存在します。"); }
$szTemp = "$trip<>".time()."<>".$_SERVER['REMOTE_ADDR']."<>0<>0<>0<>\n";
FileWrite(TRIPFILE, $szTemp, "a");
HtmlHeader();
echo "トリップ <B>$trip</B> を追加しました。";
$goto=1;
break;
case 'alldelview':
check_login();
HtmlHeader();
echo <<<HTML
<P>全てのトリップを削除します。<BR>よろしいですか?</P>
<FORM method="POST" action="$_SERVER[PHP_SELF]" ENCTYPE="multipart/form-data">
<INPUT type="hidden" name="action" value="alldel">
<INPUT type="submit" value="全削除">
</FORM>
HTML;
 
break;
case 'alldel':
check_login();
FileFlush(TRIPFILE);
HtmlHeader();
echo "<BR>トリップを全削除しました。<BR><BR>";
$goto=1;
break;
default:
HtmlHeader();
if(ALLOW_TRIP_REG||check_login(0)) echo <<<HTML
<P>トリップ追加</P>
<FORM method="POST" action="$_SERVER[PHP_SELF]" ENCTYPE="multipart/form-data">
<INPUT type="hidden" name="action" value="add">
<TABLE border="0" cellpadding="0" cellspacing="0">
<TBODY>
<TR>
<TD><dl><dt>トリップ("#"というのから始めます、例:"#123")</dt>
<dd><INPUT size="20" type="text" maxlength="100" name="triptext"></dd></dl></TD>
</TR>
<TR>
<TD><INPUT type="submit" value="追加"> <INPUT type="reset" value="リセット"></TD>
</TR>
</TBODY>
</TABLE>
</FORM>
HTML;
if(check_login(0)) {
$aTripList = FileRead(TRIPFILE);
echo <<<HTML
<HR size="1" noshade>
<P>トリップ全削除</P>
<FORM method="POST" action="$_SERVER[PHP_SELF]" ENCTYPE="multipart/form-data">
<INPUT type="hidden" name="action" value="alldelview">
<INPUT type="submit" value="全削除">
</FORM>
<HR size="1" noshade>
<P>トリップ管理</P>
<FORM method="POST" action="$_SERVER[PHP_SELF]" ENCTYPE="multipart/form-data">
<INPUT type="hidden" name="action" value="manage">
<table border=1>
<tr><th>削除</th><th>トリップ</th><th>日時</th><th>IP</th><th>有効</th><th>禁止</th><th>削除人</th></tr>
HTML;
$TripCount=count($aTripList);
if($viewstart == ""){ $vstart = 1; }
else{ $vstart = $viewstart; }
if($viewend == ""){ $vend = 100; }
else{ $vend = $viewend; }
$vend=$TripCount>$viewend?$viewend:$TripCount;
$szNextLink = "";
for($i=1; $i<=$TripCount; $i+=100){
$end = $i + 99;
$szNextLink .= " <a href=\"$_SERVER[PHP_SELF]?viewstart=$i&viewend=$end\">$i-</a>";
}
if($szNextLink != ""){ echo "$szNextLink<BR>"; }
for($i=$vstart-1;$i<$vend;$i++){
if($aTripList[$i] == ""){ break; }
@list($szTrip,$szTime,$szIP,$szActivate,$szBan,$szDelPerm) = @explode("<>", $aTripList[$i]);
echo "<tr><td><INPUT type=\"checkbox\" name=\"del[]\" value=\"$szTrip\"></td><td>$szTrip</td><td>".date('Y-m-d H:m:s',$szTime)."</td><td>$szIP</td><td>".(!$szActivate?"<INPUT type=\"checkbox\" name=\"act[]\" value=\"$szTrip\">":'はい')."</td><td><INPUT type=\"checkbox\" name=\"ban[]\" value=\"$szTrip\">".($szBan?'はい':'')."</td><td><INPUT type=\"checkbox\" name=\"dp[]\" value=\"$szTrip\">".($szDelPerm?'はい':'')."</td></tr>";
}
echo "</table>";
if($szNextLink != ""){ echo "$szNextLink<BR>"; }
echo <<<HTML
<INPUT type="submit" value="送信">
</FORM>
<FORM method="POST" action="$_SERVER[PHP_SELF]" ENCTYPE="multipart/form-data">
<INPUT type="hidden" name="action" value="logout">
<INPUT type="submit" value="ログアウト">
</FORM>
HTML;
} else {
echo "<HR size=\"1\" noshade><P>ログイン</P><form action=\"".$_SERVER['PHP_SELF']."?action=login\" method=\"POST\">ユーザー:<INPUT type=\"text\" name=\"username\"><br />パスワード:<INPUT type=\"password\" name=\"password\"><INPUT type=\"submit\" value=\"認証\"></form>";
}
break;
}
HtmlFooter($goto);
?>
New file
/release/Modules-PIO-v6/mod_bbcode/mod_bbcode.php
@@ -0,0 +1,193 @@
<?php
class mod_bbcode{
var $ImgTagTagMode, $URLTagMode, $MaxURLCount, $URLTrapLog;
var $myPage, $urlcount;
 
function mod_bbcode(){
global $PMS;
 
$PMS->hookModuleMethod('ModulePage', 'mod_bbcode'); // 向系統登記模組專屬獨立頁面
$this->myPage = $PMS->getModulePageURL('mod_bbcode'); // 基底位置
 
$this->ImgTagTagMode = 1; // [img]標籤行為 (0:不轉換 1:無貼圖時轉換 2:常時轉換)
$this->URLTagMode = 1; // [url]標籤行為 (0:不轉換 1:正常)
$this->MaxURLCount = 2; // [url]標籤上限 (超過上限時標籤為陷阱標籤[寫入至$URLTrapLog])
$this->URLTrapLog = './URLTrap.log'; // [url]陷阱標籤記錄檔
 
if(method_exists($PMS,'addCHP')) {
$PMS->addCHP('mod_bbbutton_addButtons',array($this,'_addButtons'));
}
}
 
function getModuleName(){
return 'mod_bbcode : 內文BBCode轉換';
}
 
function getModuleVersionInfo(){
return '6th.Release-dev (v110319)';
}
 
function autoHookPostInfo(&$postinfo){
$postinfo .= "<li>可使用 <a href='".$this->myPage."' rel='_blank'>BBCode</a></li>\n";
}
 
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $resto, $imgWH){
$com = $this->_bb2html($com,$dest);
}
 
function _addButtons($txt) {
$txt .= 'bbbuttons.tags = $.extend({
b:{desc:"Bold"},
i:{desc:"Italic"},
u:{desc:"Underline"},
p:{desc:"Paragraph"},
color:{desc:"Color", prompt:{prompt:"Enter Color:",def:""}},
pre:{desc:"Pre-formatted text"},
quote:{desc:"Quotation"},
email:{desc:"Insert e-mail address"},
'.($this->URLTagMode?'url:{desc:"Insert URL"},':'').'
'.($this->ImgTagTagMode?'img:{desc:"Insert Image"},':'').'
},bbbuttons.tags);';
}
 
function _bb2html($string, $dest){
$this->urlcount=0; // Reset counter
$string = preg_replace('#\[b\](.*?)\[/b\]#si', '<b>\1</b>', $string);
$string = preg_replace('#\[i\](.*?)\[/i\]#si', '<i>\1</i>', $string);
$string = preg_replace('#\[u\](.*?)\[/u\]#si', '<u>\1</u>', $string);
$string = preg_replace('#\[p\](.*?)\[/p\]#si', '<p>\1</p>', $string);
 
$string = preg_replace('#\[color=(\S+?)\](.*?)\[/color\]#si', '<font color="\1">\2</font>', $string);
 
$string = preg_replace('#\[s([1-7])\](.*?)\[/s([1-7])\]#si', '<font size="\1">\2</font>', $string);
 
$string = preg_replace('#\[pre\](.*?)\[/pre\]#si', '<pre>\1</pre>', $string);
$string = preg_replace('#\[quote\](.*?)\[/quote\]#si', '<blockquote>\1</blockquote>', $string);
 
if($this->URLTagMode){
$string=preg_replace_callback('#\[url\](https?|ftp)(://\S+?)\[/url\]#si', array(&$this, '_URLConv1'), $string);
$string=preg_replace_callback('#\[url\](\S+?)\[/url\]#si', array(&$this, '_URLConv2'), $string);
$string=preg_replace_callback('#\[url=(https?|ftp)(://\S+?)\](.*?)\[/url\]#si', array(&$this, '_URLConv3'), $string);
$string=preg_replace_callback('#\[url=(\S+?)\](.*?)\[/url\]#si', array(&$this, '_URLConv4'), $string);
$this->_URLExcced();
}
 
$string = preg_replace('#\[email\](\S+?@\S+?\\.\S+?)\[/email\]#si', '<a href="mailto:\1">\1</a>', $string);
 
$string = preg_replace('#\[email=(\S+?@\S+?\\.\S+?)\](.*?)\[/email\]#si', '<a href="mailto:\1">\2</a>', $string);
if (($this->ImgTagTagMode == 2) || ($this->ImgTagTagMode && !$dest)){
$string = preg_replace('#\[img\](([a-z]+?)://([^ \n\r]+?))\[\/img\]#si', '<img src="\1" border="0" alt="\1" />', $string);
}
 
return $string;
}
 
function _URLConv1($m){
++$this->urlcount;
return "<a href=\"$m[1]$m[2]\" rel=\"_blank\">$m[1]$m[2]</a>";
}
 
function _URLConv2($m){
++$this->urlcount;
return "<a href=\"http://$m[1]\" rel=\"_blank\">$m[1]</a>";
}
 
function _URLConv3($m){
++$this->urlcount;
return "<a href=\"$m[1]$m[2]\" rel=\"_blank\">$m[3]</a>";
}
 
function _URLConv4($m){
++$this->urlcount;
return "<a href=\"http://$m[1]\" rel=\"_blank\">$m[2]</a>";
}
 
function _URLRevConv($m){
if($m[1]=='http' && $m[2]=='://'.$m[3]) {
return '[url]'.$m[3].'[/url]';
} elseif(($m[1].$m[2])==$m[3]) {
return '[url]'.$m[1].$m[2].'[/url]';
} else {
if($m[1]=='http')
return '[url='.substr($m[2],3).']'.$m[3].'[/url]';
else
return '[url='.$m[1].$m[2].']'.$m[3].'[/url]';
}
}
 
function _EMailRevConv($m){
if($m[1]==$m[2]) return '[email]'.$m[1].'[/email]';
else return '[email='.$m[1].']'.$m[2].'[/email]';
}
 
function _html2bb(&$string){
$string = preg_replace('#<b>(.*?)</b>#si', '[b]\1[/b]', $string);
$string = preg_replace('#<i>(.*?)</i>#si', '[i]\1[/i]', $string);
$string = preg_replace('#<u>(.*?)</u>#si', '[u]\1[/u]', $string);
$string = preg_replace('#<p>(.*?)</p>#si', '[p]\1[/p]', $string);
 
$string = preg_replace('#<font color="(\S+?)">(.*?)</font>#si', '[color=\1]\2[/color]', $string);
 
$string = preg_replace('#<font size="([1-7])">(.*?)</font>#si', '[s\1]\2[/s\1]', $string);
 
$string = preg_replace('#<pre>(.*?)</pre>#si', '[pre]\1[/pre]', $string);
$string = preg_replace('#<blockquote>(.*?)</blockquote>#si', '[quote]\1[/quote]', $string);
 
$string = preg_replace_callback('#<a href="(https?|ftp)(://\S+?)" rel="_blank">(.*?)</a>#si', array(&$this, '_URLRevConv'), $string);
$string = preg_replace_callback('#<a href="mailto:(\S+?@\S+?\\.\S+?)">(.*?)</a>#si', array(&$this, '_EMailRevConv'), $string);
 
$string = preg_replace('#<img src="(([a-z]+?)://([^ \n\r]+?))" border="0" alt=".*?" />#si', '[img]\1[/img]', $string);
}
 
 
function _URLExcced(){
if($this->urlcount > $this->MaxURLCount) {
$fh = fopen($this->URLTrapLog, 'a+b');
fwrite($fh, time()."\t$_SERVER[REMOTE_ADDR]\t$cnt\n");
fclose($fh);
error("[url]標籤超過上限");
}
}
 
function ModulePage(){
$dat='';$status='現時BBCode設定:<ul><li>[url]標籤行為 (0:不轉換 1:正常) - '.$this->URLTagMode.'</li><li>[url]標籤上限 (超過上限時標籤為陷阱標籤並寫入至記錄檔中) - '.$this->MaxURLCount.'</li><li>'._T('info_basic_urllinking').' '._T('info_0no1yes').' - '.AUTO_LINK.'</li><li>[img]標籤行為 (0:不轉換 1:無貼圖時轉換 2:常時轉換) - '.$this->ImgTagTagMode.'</li></ul>';
head($dat);
$dat.=<<<EOH
$status
BBCode 代碼包含一些標籤方便您快速的更改文字的基本形式. 這些可以分述如下:
<ul><li>要製作一份粗體文字可使用 <b>[b][/b]</b>, 例如: <br/><br/><b>[b]</b>哈囉<b>[/b]</b><br/><br/>會變成<b>哈囉</b><br/><br/></li>
<li>要使用底線時, 可使用<b>[u][/u]</b>, 例如:<br/><br/><b>[u]</b>早安<b>[/u]</b><br/><br/>會變成<u>早安</u><br/><br/></li>
<li>要斜體顯示時, 可使用 <b>[i][/i]</b>, 例如:<br/><br/>這個真是 <b>[i]</b>棒呆了!<b>[/i]</b><br/><br/>將會變成 這個真是 <i>棒呆了!</i></li></ul>
 
要在您的文章中修改文字顏色及大小需要使用以下的標籤. 請注意, 顯示的效果視您的瀏覽器和系統而定:
<ul><li>更改文字色彩時, 可使用 <b>[color=][/color]</b>. 您可以指定一個可被辨識的顏色名稱(例如. red, blue, yellow, 等等.) 或是使用顏色編碼, 例如: #FFFFFF, #000000. 舉例來說, 要製作一份紅色文字您必須使用:<br/><br/><b>[color=red]</b>哈囉!<b>[/color]</b><br/><br/>或是<br/><br/><b>[color=#FF0000]</b>哈囉!<b>[/color]</b><br/><br/>都將顯示:<font color="red">哈囉!</font><br/><br/></li>
<li>改變文字的大小也是使用類似的設定, 標籤為 <b>[s?][/s?]</b>. 起始值為 1 (細小) 到 7 為止 (巨大). 舉例說明:<br/><br/><b>[s1]</b>小不拉嘰<b>[/s1]</b><br/><br/>將會產生 <font size="1">小不拉嘰</font><br/><br/>當情形改變時:<br/><br/><b>[s7]</b>有夠大顆!<b>[/s7]</b><br/><br/>將會顯示 <font size="7">有夠大顆!</font></li></ul>
 
可以結合不同的標籤功能: <br/>
<ul><li>例如要吸引大家的注意時, 您可以使用:<br/><br/><b>[s5][color=red][b]</b>看我這兒!<b>[/b][/color][/s5]</b><br/><br/> 將會顯示出 <font size="5"><font color="red"><b>看我這兒!</b></font></font><br/>&nbsp;</li>
<li>我們並不建議您顯示太多這類的文字! 但是這些還是由您自行決定. 在使用 BBCode 代碼時, 請記得要正確的關閉標籤, 以下就是錯誤的使用方式:<br/><br/><b>[b][u]</b>這是錯誤的示範<b>[/b][/u]</b></li></ul>
 
如果您想要顯示一段程式代碼或是任何需要固定寬度的文字, 您必須使用 <b>[pre][/pre]</b> 標籤來包含這些文字, 例如:<br/><br/><b>[pre]</b>echo "這是代碼";<b>[/pre]</b><br/><br/>當您瀏覽時, 所有被 <b>[pre][/pre]</b> 標籤包含的文字格式都將保持不變.
 
若一個完整的URL遵照此方式寫入至討論板,將會自動產生一個超連結連往該URL
<ul><li>http://開頭的會自動成為超連結 (如果自動連結有啟用的話)</li>
<li>[url]可以做成一個超連結,請參考下例:<br/>
<b>[url=http://php.s3.to]</b>按這裡<b>[/url]</b></li>
<li>下一個方式也有類似效果<br/>
<b>[url]</b>php.s3.to<b>[/url]</b>
<p>以上舉例說明中,自動產生了連結以刊登URL。使用者按下該連結將跳出一視窗。沒有"http://"是不能自動產生連結的。<br/>第二個方法裡可以省略"http://"。避免於URL中置入「"」記號,那可能會截斷網址。</p>
</li></ul>
為了加上Email的連結,請按照以下方式刊登郵址:
<ul><li><b>[email]</b>php@php.4all.cc<b>[/email]</b></li>
<li>下一個方式也可以做成一個Email連結<br/>
<b>[email=php@php.4all.cc]</b>我的Email<b>[/email]</b></li>
</ul>
 
BBCode 代碼提供標籤在您的文章中顯示圖像. 使用前, 請記住兩件重要的事; 第一, 許多使用者並不樂於見到文章中有太多的圖片, 第二, 您的圖片必須是能在網路上顯示的 (例如: 不能是您電腦上的檔案, 除非您的電腦是台網路伺服器). 若要顯示圖像, 可以使用 <b>[img][/img]</b> 標籤並指定圖像連結網址, 例如:<br/><br/><b>[img]</b>http://www.google.com/intl/en_com/images/logo_plain.png<b>[/img]</b><br/><br/>如同在先前網址連結的說明一樣, 您也可以使用圖片網址超連結 <b>[url][/url]</b> 的標籤, 例如:<br/><br/><b>[url=http://www.google.com/][img]</b>http://www.google.com/intl/en_com/images/logo_plain.png<b>[/img][/url]</b><br/><br/>將產生:<br/><br/><a href="http://www.google.com/" rel="_blank"><img src="http://www.google.com/intl/en_com/images/logo_plain.png" alt="http://www.google.com/intl/en_com/images/logo_plain.png" border="0" /></a>
<hr/>
EOH;
foot($dat);
echo $dat;
}
}
?>
New file
/release/Modules-PIO-v6/mod_bbbutton/mod_bbbutton.php
@@ -0,0 +1,37 @@
<?php
class mod_bbbutton{
var $bbicon, $bbicon_url;
function mod_bbbutton(){
$this->bbicon = false; // 使用圖示
$this->bbicon_url = 'bbicons/'; // 圖示位置
}
 
function getModuleName(){
return 'mod_bbbutton';
}
 
function getModuleVersionInfo(){
return 'mod_bbbutton : BBcode按鈕';
}
 
function autoHookHead(&$txt, $isReply){
global $PMS;
$txt .= '<!--script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script-->
<script src="jquery.bbcode.js" type="text/javascript"></script>
<script type="text/javascript">
var bbbuttons = { tags: {}, button_image: '.(int)$this->bbicon.', image_url: "'.$this->bbicon_url.'" };
';
if(method_exists($PMS,'callCHP')) {
$PMS->callCHP('mod_bbbutton_addButtons',array(&$txt));
}
 
$txt .= '
$(document).ready(function(){
$("#fcom").bbcode(bbbuttons);
});
</script>';
}
 
}
?>
New file
/release/Modules-PIO-v6/mod_bbbutton/jquery.bbcode.js
@@ -0,0 +1,67 @@
/*
* Plugin jQuery.BBCode
* Version 0.2 (mod_bbbutton edition)
*
* Based on jQuery.BBCode plugin (http://www.kamaikinproject.ru)
* mod_bbbutton edition by RT (Pixmicat! project)
*/
(function($){
$.fn.bbcode = function(options){
// default settings
var options = $.extend({
tags: {},
button_image: false,
image_url: 'bbicon/'
},options||{});
$.fn.bbcode.options = options;
// panel
var text = '<div id="bbcode_bb_bar">';
$.each(options.tags, function(key, value) {
text += '<a href="#" id="'+key+'" title="'+value.desc+'">';
if(options.button_image){
text += '<img src="'+options.image_url+key+'.png" alt="['+key+']" />';
}else{
text += '['+key+']';
}
text += '</a>';
});
text += '</div>';
$(this).wrap('<div id="bbcode_container"></div>');
$("#bbcode_container").prepend(text);
$("#bbcode_bb_bar a img").css("border", "none");
var id = '#'+$(this).attr("id");
var e = $(id).get(0);
$('#bbcode_bb_bar a').click(function() {
var button_id = $(this).attr("id");
var start = '['+button_id+']';
var end = '[/'+button_id+']';
 
var param="";
var tag_clicked = eval('$.fn.bbcode.options.tags.'+button_id);
if (!!tag_clicked.prompt) {
param=prompt(tag_clicked.prompt.prompt,tag_clicked.prompt.def);
if (param)
start='['+button_id+'='+param+']';
}
insert(start, end, e);
return false;
});
}
function insert(start, end, element) {
if (document.selection) {
element.focus();
sel = document.selection.createRange();
sel.text = start+sel.text+end;
} else if (element.selectionStart || element.selectionStart == '0') {
element.focus();
var startPos = element.selectionStart;
var endPos = element.selectionEnd;
element.value = element.value.substring(0, startPos)+start+element.value.substring(startPos, endPos)+end+element.value.substring(endPos, element.value.length);
} else {
element.value += start+end;
}
}
 
})(jQuery)
New file
/release/Modules-PIO-v6/mod_bbbutton/howto.txt
@@ -0,0 +1,23 @@
License:
 
jquery.bbcode.js is forked from part of BBCode editor (http://www.webcheatsheet.com/javascript/bbcode_editor.php).
mod_bbbutton is not a part of Pixmicat! package. So it's not licensed under the Clarified Artistic License. It's in the public domain.
 
中文安裝指引:
 
1. 將 mod_bbbutton.php 放到 module/ 目錄
2. 將 jquery.bbcode.js 放到跟 pixmicat.php 同一目錄
2. 修改 config.php,在模組載入區塊下加一行 $ModuleList[] = 'mod_bbbutton';
 
* 此模組需求 JQuery 版本 1.3.2 或以上。請確保有其中一個模組有載入 JQuery 或修改 mod_bbbutton.php 把載入 JQuery 的一行的註解符號去除。
* 較後載入的模組的按鈕會從按鈕列的起始位置加入。
 
English Instruction:
 
1. Put mod_bbbutton.php into the module/ directory.
1. Put jquery.bbcode.js into the directory that pixmicat.php sits.
2. Use your favorite editor to open the "config.php" and add one line ($ModuleList[] = 'mod_bbbutton';) into the "Modules to be loaded" block.
 
 
* The module requires JQuery version 1.3.2 or later. Please make sure any module loads JQuery first, or edit mod_bbbutton.php to uncomment JQuery line.
* The order of buttons form later added modules will be added in front.
New file
/release/Modules-PIO-v6/mod_plusone/mod_plusone.php
@@ -0,0 +1,50 @@
<?php
class mod_plusone{
var $site, $url;
function mod_plusone(){
$this->site = TITLE;
$this->url = fullURL().PHP_SELF.'?res=';
}
 
function getModuleName(){
return __CLASS__.' : Google +1 Button';
}
 
function getModuleVersionInfo(){
return 'v110813';
}
 
function autoHookHead(&$style, $isReply){
global $PIO, $FileIO;
if($isReply){
$p = $PIO->fetchPosts($isReply);
$sub = $p[0]['sub'];
$com = htmlentities(str_cut($p[0]['com'], 100), ENT_QUOTES, 'UTF-8');
$thumb = '';
if($p[0]['ext'] != ''){
$thumb = $FileIO->resolveThumbName($p[0]['tim']); // 檢查是否有預覽圖可以顯示
$thumb = $thumb ? $FileIO->getImageURL($thumb) : '';
}
$style .= <<< _HERE_
 
<meta property="og:image" content="{$thumb}" />
<meta property="og:title" content="{$sub} - {$this->site}" />
<meta property="og:description" content="{$com}" />
_HERE_;
}
}
 
function autoHookFoot(&$foot){
$foot .= '
<script type="text/javascript" src="https://apis.google.com/js/plusone.js">
{lang: "zh-TW"}
</script>
';
}
 
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
$arrLabels['{$REPLYBTN}'] .= '&nbsp;<div class="g-plusone" data-size="small" data-href="'.$this->url.$post['no'].'"></div>';
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_pushpost/mod_pushpost.php
@@ -0,0 +1,284 @@
<?php
class mod_pushpost{
var $mypage;
 
function mod_pushpost($PMS){
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 向系統登記模組專屬獨立頁面
$this->mypage = $PMS->getModulePageURL(__CLASS__);
$this->PUSHPOST_SEPARATOR = '[MOD_PUSHPOST_USE]';
$this->PUSHPOST_DEF = 10; // 討論串最多顯示之推文筆數 (超過則自動隱藏,全部隱藏:0)
AttachLanguage(array($this, '_loadLanguage')); // 載入語言檔
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_pushpost : 文章推文機制';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '6th.Release-pre (b110416)';
}
 
/* 生成識別ID */
function _getID(){
return substr(crypt(md5(getREMOTE_ADDR().IDSEED.gmdate('Ymd', time() + TIME_ZONE * 3600)), 'id'), -8);
}
 
function autoHookHead(&$txt, $isReply){
global $language;
$txt .= '<style type="text/css">.pushpost { background-color: #fff; font-size: 0.8em; padding: 10px; }</style>
<script type="text/javascript">
// <![CDATA[
var lastpushpost=0;
function mod_pushpostShow(pid){
$g("mod_pushpostID").value = pid;
$g("mod_pushpostName").value = getCookie("namec");
$("div#mod_pushpostBOX").insertBefore($("div#r"+pid+" .quote"));
 
if(lastpushpost!=pid) {
$("div#mod_pushpostBOX").show();
} else
$("div#mod_pushpostBOX").toggle();
lastpushpost = pid;
return false;
}
function mod_pushpostKeyPress(e){if(e.which==13){e.preventDefault();mod_pushpostSend();}}
function mod_pushpostSend(){
var o0 = $g("mod_pushpostID"), o1 = $g("mod_pushpostName"), o2 = $g("mod_pushpostComm"), o3 = $g("mod_pushpostSmb"), pp = $("div#r"+o0.value+" .quote");
if(o2.value===""){ alert("'._T('modpushpost_nocomment').'"); return false; }
o1.disabled = o2.disabled = o3.disabled = true;
$.ajax({
url: "'.str_replace('&amp;', '&', $this->mypage).'&no="+o0.value,
type: "POST",
data: {ajaxmode: true, name: o1.value, comm: o2.value},
success: function(rv){
if(rv.substr(0, 4)!=="+OK "){ alert(rv); o3.disabled = false; return false; }
rv = rv.substr(4);
(pp.find(".pushpost").length===0)
? pp.append("<div class=\'pushpost\'>"+rv+"</div>")
: pp.children(".pushpost").append("<br />"+rv);
o0.value = o1.value = o2.value = ""; o1.disabled = o2.disabled = o3.disabled = false;
$("div#mod_pushpostBOX").hide();
},
error: function(){ alert("Network error."); o1.disabled = o2.disabled = o3.disabled = false; }
});
}
// ]]>
</script>';
}
 
function autoHookFoot(&$foot){
global $language;
$foot .= '
<div id="mod_pushpostBOX" style="display:none">
<input type="hidden" id="mod_pushpostID" />'._T('modpushpost_pushpost').' <ul><li>'._T('form_name').' <input type="text" id="mod_pushpostName" maxlength="20" onkeypress="mod_pushpostKeyPress(event)" /></li><li>'._T('form_comment').' <input type="text" id="mod_pushpostComm" size="50" maxlength="50" onkeypress="mod_pushpostKeyPress(event)" /><input type="button" id="mod_pushpostSmb" value="'._T('form_submit_btn').'" onclick="mod_pushpostSend()" /></li></ul>
</div>
';
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
global $language, $PIO;
$pushcount = '';
if($post['status'] != ''){
$f = $PIO->getPostStatus($post['status']);
$pushcount = $f->value('mppCnt'); // 被推次數
}
$arrLabels['{$QUOTEBTN}'] .= '&nbsp;<a href="'.$this->mypage.'&amp;no='.$post['no'].'" onclick="return mod_pushpostShow('.$post['no'].')">'.$pushcount._T('modpushpost_pushbutton').'</a>';
if(strpos($arrLabels['{$COM}'], $this->PUSHPOST_SEPARATOR.'<br />') !== false){
if($isReply || $pushcount <= $this->PUSHPOST_DEF) // 回應模式
$arrLabels['{$COM}'] = str_replace($this->PUSHPOST_SEPARATOR.'<br />', '<div class="pushpost">', $arrLabels['{$COM}']).'</div>';
else{ // 頁面瀏覽
$delimiter = strpos($arrLabels['{$COM}'], $this->PUSHPOST_SEPARATOR.'<br />'); // 定位符號位置
if($this->PUSHPOST_DEF > 0){
$push_array = explode('<br />', substr($arrLabels['{$COM}'], $delimiter + strlen($this->PUSHPOST_SEPARATOR.'<br />')));
$pushs = '<div class="pushpost">……<br />'.implode('<br />', array_slice($push_array, 0 - $this->PUSHPOST_DEF)).'</div>';
}else{
$pushs = '';
}
$arrLabels['{$COM}'] = substr($arrLabels['{$COM}'], 0, $delimiter).$pushs;
$arrLabels['{$WARN_BEKILL}'] .= '<span class="warn_txt2">'._T('modpushpost_omitted').'<br /></span>'."\n";
}
}
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
function autoHookRegistBegin(&$name, &$email, &$sub, &$com, $upfileInfo, $accessInfo, $isReply){
if(adminAuthenticate('check')) return; // 登入權限允許標籤留存不轉換 (後端登入修改文章後推文仍有效)
if(strpos($com, $this->PUSHPOST_SEPARATOR."\r\n") !== false){ // 防止不正常的插入標籤形式
$com = str_replace($this->PUSHPOST_SEPARATOR."\r\n", "\r\n", $com);
}
}
 
function autoHookAdminList(&$modFunc, $post, $isres){
$modFunc .= '[<a href="'.$this->mypage.'&amp;action=del&amp;no='.$post['no'].'">刪推</a>]';
}
 
function ModulePage(){
global $PIO, $PTE, $PMS, $language;
if(!isset($_GET['no'])) die('[Error] not enough parameter.');
if(isset($_GET['action'])) {
if(adminAuthenticate('check')) {
$pushcount = ''; $puststart=0;
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.'); // 被推之文章不存在
extract($post[0]);
 
if($status != ''){
$f = $PIO->getPostStatus($status);
$pushcount = $f->value('mppCnt'); // 被推次數
}
 
if(($puststart=strpos($com, $this->PUSHPOST_SEPARATOR.'<br />'))===false) die('[Error] No pushpost.');
 
$ocom = substr($com,0,$puststart);
$pushpost = explode('<br />',substr($com,$puststart+strlen($this->PUSHPOST_SEPARATOR.'<br />')));
$com = $ocom;
 
if($_GET['action'] == 'del') { // list
$p_count = 1;
$com .= '<div class="pushpost">';
foreach($pushpost as $p)
$com .= '<input type="checkbox" name="'.($p_count++).'" value="delete" />'.$p.'<br />';
$com .= '</div>';
 
$dat = '';
head($dat);
$dat .= '<div class="bar_reply">'._T('modpushpost_deletepush').'</div>';
$dat .= '<form action="'.$this->mypage.'&amp;action=delpush&amp;no='.$_GET['no'].'" method="post">';
$dat .= $PTE->ParseBlock('SEARCHRESULT', array('{$NO}'=>$no, '{$SUB}'=>$sub, '{$NAME}'=>$name, '{$NOW}'=>$now, '{$COM}'=>$com, '{$CATEGORY}'=>$category, '{$NAME_TEXT}'=>_T('post_name'), '{$CATEGORY_TEXT}'=>_T('post_category')));
echo $dat, '<input type="submit" value="'._T('del_btn').'" /></form></body></html>';
return;
} elseif($_GET['action'] == 'delpush') { // delete
$delno = array();
reset($_POST);
while($item = each($_POST)){ if($item[1]=='delete' && $item[0] != 'func') array_push($delno, $item[0]); }
if(count($delno)) foreach($delno as $d) if(isset($pushpost[$d-1])) unset($pushpost[$d-1]);
$pushcount = count($pushpost);
if($pushcount) {
$f->update('mppCnt',$pushcount); // 更新推文次數
$com = $ocom.$this->PUSHPOST_SEPARATOR.'<br />'.implode('<br />',$pushpost);
} else {
$f->remove('mppCnt'); // 刪除推文次數
$com = $ocom;
}
 
$PIO->updatePost($_GET['no'], array('com'=>$com, 'status'=>$f->toString())); // 更新推文
$PIO->dbCommit();
 
echo '+OK ';
return;
} else die('[Error] unknown action.');
} else die('[Error] unauthenticated action.');
}
if(!isset($_POST['comm'])){
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
 
$dat = $PTE->ParseBlock('HEADER', array('{$TITLE}'=>TITLE, '{$RESTO}'=>''));
$dat .= '</head><body id="main">';
$dat .= '<form action="'.$this->mypage.'&amp;no='.$_GET['no'].'" method="post">
'._T('modpushpost_pushpost').' <ul><li>'._T('form_name').' <input type="text" name="name" maxlength="20" /></li><li>'._T('form_comment').' <input type="text" name="comm" size="50" maxlength="50" /><input type="submit" value="'._T('form_submit_btn').'" /></li></ul>
</form>';
echo $dat, '</body></html>';
}else{
if($_SERVER['REQUEST_METHOD'] != 'POST') die(_T('regist_notpost')); // 傳送方法不正確
 
// 查IP
$baninfo = '';
$ip = getREMOTE_ADDR(); $host = gethostbyaddr($ip);
if(BanIPHostDNSBLCheck($ip, $host, $baninfo)) die(_T('regist_ipfiltered', $baninfo));
 
$name = CleanStr($_POST['name']); $comm = CleanStr($_POST['comm']);
if(strlen($name) > 30) die(_T('modpushpost_maxlength')); // 名稱太長
if(strlen($comm) > 160) die(_T('modpushpost_maxlength')); // 太多字
if(strlen($comm) == 0) die(_T('modpushpost_nocomment')); // 沒打字
$name = str_replace(array(_T('trip_pre'), _T('admin'), _T('deletor')), array(_T('trip_pre_fake'), '"'._T('admin').'"', '"'._T('deletor').'"'), $name);
$pushID = $this->_getID();
$pushtime = gmdate('y/m/d H:i', time() + intval(TIME_ZONE) * 3600);
if(preg_match('/(.*?)[##](.*)/u', $name, $regs)){
$cap = strtr($regs[2], array('&amp;'=>'&'));
$salt = strtr(preg_replace('/[^\.-z]/', '.', substr($cap.'H.', 1, 2)), ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
$name = $regs[1]._T('trip_pre').substr(crypt($cap, $salt), -10);
}
if(!$name || preg_match("/^[ | |]*$/", $name)){
if(ALLOW_NONAME) $name = DEFAULT_NONAME;
else die(_T('regist_withoutname')); // 不接受匿名
}
if(ALLOW_NONAME==2){ // 強制砍名
$name = preg_match('/(\\'._T('trip_pre').'.{10})/', $name, $matches) ? $matches[1].':' : DEFAULT_NONAME.':';
}else{
$name .= ':';
}
$pushpost = "{$name} {$comm} ({$pushID} {$pushtime})"; // 推文主體
 
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.'); // 被推之文章不存在
 
$parentNo = $post[0]['resto'] ? $post[0]['resto'] : $post[0]['no'];
$threads = array_flip($PIO->fetchThreadList());
$threadPage = floor($threads[$parentNo] / PAGE_DEF);
 
$p = ($parentNo==$post[0]['no']) ? $post : $PIO->fetchPosts($parentNo); // 取出首篇
$flgh = $PIO->getPostStatus($p[0]['status']);
if($flgh->exists('TS')) die('[Error] '._T('regist_threadlocked')); // 首篇禁止回應/同時表示禁止推文
 
$post[0]['com'] .= ((strpos($post[0]['com'], $this->PUSHPOST_SEPARATOR.'<br />')===false) ? '<br />'.$this->PUSHPOST_SEPARATOR : '').'<br /> '.$pushpost;
$flgh2 = $PIO->getPostStatus($post[0]['status']);
$flgh2->plus('mppCnt'); // 推文次數+1
$PIO->updatePost($_GET['no'], array('com'=>$post[0]['com'], 'status'=>$flgh2->toString())); // 更新推文
$PIO->dbCommit();
// logcat
$PMS->callCHP('mod_audit_logcat',
array(sprintf('[%s] No.%d %s (%s)',
__CLASS__,
$_GET['no'],
str_cut($comm, 50),
$pushID)
)
);
if(STATIC_HTML_UNTIL == -1 || $threadPage <= STATIC_HTML_UNTIL) updatelog(0, $threadPage, true); // 僅更新討論串出現那頁
deleteCache(array($parentNo)); // 刪除討論串舊快取
 
if(isset($_POST['ajaxmode'])){
echo '+OK ', $pushpost;
}else{
header('HTTP/1.1 302 Moved Temporarily');
header('Location: '.fullURL().PHP_SELF2.'?'.time());
}
}
}
 
function _loadLanguage(){
global $language;
if(PIXMICAT_LANGUAGE != 'zh_TW' && PIXMICAT_LANGUAGE != 'ja_JP' && PIXMICAT_LANGUAGE != 'en_US') $lang = 'en_US';
else $lang = PIXMICAT_LANGUAGE;
 
if($lang=='zh_TW'){
$language['modpushpost_nocomment'] = '請輸入內文';
$language['modpushpost_pushpost'] = '[推文]';
$language['modpushpost_pushbutton'] = '推';
$language['modpushpost_maxlength'] = '你話太多了';
$language['modpushpost_omitted'] = '有部分推文被省略。要閱讀全部推文請按下回應連結。';
$language['modpushpost_deletepush'] = '刪除推文模式';
}elseif($lang=='ja_JP'){
$language['modpushpost_nocomment'] = '何か書いて下さい';
$language['modpushpost_pushpost'] = '[推文]';
$language['modpushpost_pushbutton'] = '推';
$language['modpushpost_maxlength'] = 'コメントが長すぎます';
$language['modpushpost_omitted'] = '推文省略。全て読むには返信ボタンを押してください。';
$language['modpushpost_deletepush'] = '削除推文モード';
}elseif($lang=='en_US'){
$language['modpushpost_nocomment'] = 'Please type your comment.';
$language['modpushpost_pushpost'] = '[Push this post]';
$language['modpushpost_pushbutton'] = 'PUSH';
$language['modpushpost_maxlength'] = 'You typed too many words';
$language['modpushpost_omitted'] = 'Some pushs omitted. Click Reply to view.';
$language['modpushpost_deletepush'] = 'Delete Push Post Mode';
}
}
}
?>
New file
/release/Modules-PIO-v6/mod_siokara/mod_siokara.php
@@ -0,0 +1,176 @@
<?php
/*
mod_siokara : Pixmicat! siokara management subset (Alpha)
by: scribe
*/
 
class mod_siokara{
var $mypage;
 
function mod_siokara(){
global $PMS;
AttachLanguage(array($this,'_loadLanguage')); // 載入語言檔
$PMS->hookModuleMethod('ModulePage', 'mod_siokara'); // 向系統登記模組專屬獨立頁面
$this->mypage = $PMS->getModulePageURL('mod_siokara');
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_siokara : しおから式管理擴充套件';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return 'v071119';
}
 
function autoHookAdminList(&$modFunc, $post, $isres){
global $PMS,$FileIO;
extract($post);
 
$fh=new FlagHelper($status);
if(!$isres) $modFunc .= '[<a href="'.$this->mypage.'&amp;no='.$no.'&amp;action=sage"'.($fh->value('asage')?' title="'._T('siokara_admin_ufsage').'">s':' title="'._T('siokara_admin_fsage').'">S').'</a>]';
if($ext && $FileIO->imageExists($tim.$ext)) {
$modFunc .= '[<a href="'.$this->mypage.'&amp;no='.$no.'&amp;action=thumb"'.($fh->value('htmb')?' title="'._T('siokara_admin_uhtmb').'">t':' title="'._T('siokara_admin_htmb').'">T').'</a>]';
if($ext == '.gif') $modFunc .= '[<a href="'.$this->mypage.'&amp;no='.$no.'&amp;action=agif"'.($fh->value('agif')?' title="'._T('siokara_admin_agif').'">g':' title="'._T('siokara_admin_uagif').'">G').'</a>]';
}
}
 
function autoHookPostForm(&$form){
global $language;
$form .= '<tr><td class="Form_bg"><b>'._T('siokara_extra_opt').'</b></td><td>[<input type="checkbox" name="anigif" id="anigif" value="on" />'._T('siokara_anigif').']</td></tr>';
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
global $PIO,$FileIO;
$fh = new FlagHelper($post['status']);
if($fh->value('asage')) { // 強制sage
if($arrLabels['{$COM}']) $arrLabels['{$WARN_ENDREPLY}'].='<br/><span class="warn_txt"><small>'._T('siokara_warn_sage').'<br/></small></span>';
else $arrLabels['{$WARN_ENDREPLY}'] = '<span class="warn_txt"><small>'._T('siokara_warn_sage').'<br/></small></span>';
}
if($FileIO->imageExists($post['tim'].$post['ext'])) {
if($fh->value('agif')) { // 動態GIF
$imgURL = $FileIO->getImageURL($post['tim'].$post['ext']);
$arrLabels['{$IMG_SRC}']=preg_replace('/<img src=".*"/U','<img src="'.$imgURL.'"',$arrLabels['{$IMG_SRC}']);
$arrLabels['{$IMG_BAR}'].='<small>['._T('siokara_anigif').']</small>';
}
if($fh->value('htmb')) { // 替換縮圖
$arrLabels['{$IMG_SRC}']=preg_replace('/<img src=".*" style="width: \d+px; height: \d+px;"/U','<img src="nothumb.gif"',$arrLabels['{$IMG_SRC}']);
$arrLabels['{$COM}'].='<br/><br/><span class="warn_txt"><small>'._T('siokara_warn_hidethumb').'<br/></small></span>';
}
}
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status){
global $PIO;
$fh = new FlagHelper($status);
$size = @getimagesize($dest);
 
if(isset($_POST['anigif']) && ($size[2] == 1)) { // 動態GIF
$fh->toggle('agif');
$status = $fh->toString();
}
 
if($isReply) {
$rpost = $PIO->fetchPosts($isReply); // 強制sage
$rfh = new FlagHelper($rpost[0]['status']);
if($rfh->value('asage')) $age = false;
}
 
}
 
function _loadLanguage() {
global $language;
if(PIXMICAT_LANGUAGE != 'zh_TW' && PIXMICAT_LANGUAGE != 'ja_JP' && PIXMICAT_LANGUAGE != 'en_US') $lang = 'en_US';
else $lang = PIXMICAT_LANGUAGE;
 
// builtin language strings
if($lang == 'zh_TW') {
$language['siokara_admin_fsage'] = '強制sage';
$language['siokara_admin_ufsage'] = '解除強制sage';
$language['siokara_admin_htmb'] = '替換縮圖';
$language['siokara_admin_uhtmb'] = '解除替換縮圖';
$language['siokara_admin_agif'] = '替換縮圖為靜態縮圖';
$language['siokara_admin_uagif'] = '解除替換靜態縮圖';
$language['siokara_extra_opt'] = '附加選項';
$language['siokara_anigif'] = '動態GIF';
$language['siokara_warn_sage'] = '此討論串已被強制sage。';
$language['siokara_warn_hidethumb'] = '縮圖已被替換。';
} else if($lang == 'ja_JP'){
$language['siokara_admin_fsage'] = '強制sage';
$language['siokara_admin_ufsage'] = '強制sage解除';
$language['siokara_admin_htmb'] = 'サムネイル差替';
$language['siokara_admin_uhtmb'] = 'サムネイル差替解除';
$language['siokara_admin_agif'] = 'GIFをサムネイル化する';
$language['siokara_admin_uagif'] = 'GIFサムネイル化解除';
$language['siokara_extra_opt'] = '余分なオプション';
$language['siokara_anigif'] = 'GIFアニメ';
$language['siokara_warn_sage'] = 'このスレは管理者によりsage指定されています。理由はお察しください。';
$language['siokara_warn_hidethumb'] = 'この記事の画像は管理者によりサムネイルが差し替えられています。理由はお察しください。<br/>サムネイルをクリックすると元の画像を表示します。';
} else if($lang == 'en_US'){
$language['siokara_admin_fsage'] = 'Force sage';
$language['siokara_admin_ufsage'] = 'unForce sage';
$language['siokara_admin_htmb'] = 'Replace thumbnail with nothumb image';
$language['siokara_admin_uhtmb'] = 'Use orginal thumbnail';
$language['siokara_admin_agif'] = 'Use still image of GIF image';
$language['siokara_admin_uagif'] = 'Use Animated GIF';
$language['siokara_extra_opt'] = 'Extra Options';
$language['siokara_anigif'] = 'Animated GIF';
$language['siokara_warn_sage'] = 'This thread was forced sage by administrator.';
$language['siokara_warn_hidethumb'] = 'The thumbnail was replaced by administrator.';
}
 
// external language file
if(file_exists($langfile=str_replace('.php','.lang.php',__FILE__))) include_once($langfile);
}
 
function ModulePage(){
global $PIO,$FileIO;
if(!adminAuthenticate('check')) die('403 Access denied');
$act=isset($_GET['action'])?$_GET['action']:'';
switch($act) {
case 'sage'; // 強制sage
if($PIO->isThread($_GET['no'])) {
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
$flgh = $PIO->getPostStatus($post[0]['status']);
$flgh->toggle('asage');
$PIO->setPostStatus($post[0]['no'], $flgh->toString());
$PIO->dbCommit();
die('Done. Please go back.');
} else die('[Error] Thread does not exist.');
break;
case 'thumb'; // 替換縮圖
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
if($post[0]['ext']) {
if(!$FileIO->imageExists($post[0]['tim'].$post[0]['ext'])) die('[Error] attachment does not exist.');
$flgh = $PIO->getPostStatus($post[0]['status']);
$flgh->toggle('htmb');
$PIO->setPostStatus($post[0]['no'], $flgh->toString());
$PIO->dbCommit();
die('Done. Please go back.');
} else die('[Error] Post does not have attechment.');
break;
case 'agif'; // 動態GIF
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
if($post[0]['ext'] && $post[0]['ext'] == '.gif') {
if(!$FileIO->imageExists($post[0]['tim'].$post[0]['ext'])) die('[Error] attachment does not exist.');
$flgh = $PIO->getPostStatus($post[0]['status']);
$flgh->toggle('agif');
$PIO->setPostStatus($post[0]['no'], $flgh->toString());
$PIO->dbCommit();
die('Done. Please go back.');
} else die('[Error] Post does not have attechment.');
break;
}
}
 
}
?>
New file
/release/Modules-PIO-v6/mod_recaptcha/howto.txt
@@ -0,0 +1,20 @@
License:
 
The reCAPTCHA PHP Library is provided by reCAPTCHA project. Copyright (c) 2007 reCAPTCHA (http://recaptcha.net)
mod_recaptcha is not a part of Pixmicat! package. So it's not licensed under the Clarified Artistic License. It's in the public domain.
 
中文安裝指引:
 
0. 請先申請免費的 reCAPTCHA 帳號 (http://recaptcha.net/whyrecaptcha.html),取得兩串 Key
1. 從 http://code.google.com/p/recaptcha/downloads/list?q=label:phplib-Latest 下載含 recaptchalib.php 的壓縮包並解壓取出
2. 將 mod_recaptcha.php 和 recaptchalib.php 放到 module/ 目錄
3. 修改 mod_recaptcha.php,填入在第0步驟於 reCAPTCHA 取得的 Public Key 和 Private Key
4. 修改 config.php,在模組載入區塊下加一行 $ModuleList[] = 'mod_recaptcha';
 
English Instruction:
 
0. Please sign up for a FREE account of reCAPTCHA. (http://recaptcha.net/whyrecaptcha.html) And you can get two 40-letter-long keys.
1. Download the "recaptchalib.php" from http://code.google.com/p/recaptcha/downloads/list?q=label:phplib-Latest
2. Put the following files into the module/ directory: "mod_recaptcha.php" and "recaptchalib.php."
3. Use your favorite editor to open the "mod_recaptcha.php" and fill out the public key and the private key you got at step 0.
4. Finally, open the "config.php" and add one line ($ModuleList[] = 'mod_recaptcha';) into the "Modules to be loaded" block.
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_recaptcha/mod_recaptcha.php
@@ -0,0 +1,34 @@
<?php
/*
mod_recaptcha.php
*/
include('recaptchalib.php'); // reCAPTCHA PHP Library
 
class mod_recaptcha{
var $KEY_PUBLIC, $KEY_PRIVATE;
 
function mod_recaptcha(){
$this->KEY_PUBLIC = ''; // Public Key of this site
$this->KEY_PRIVATE = ''; // Private Key of this site
}
 
function getModuleName(){
return 'mod_recaptcha : reCAPTCHA 驗證圖像機制';
}
 
function getModuleVersionInfo(){
return '4th.Release.2 (v071111)';
}
 
/* 在頁面附加 reCAPTCHA 圖像和功能 */
function autoHookPostForm(&$txt){
$txt .= '<tr><th class="Form_bg">驗證碼</th><td>'.recaptcha_get_html($this->KEY_PUBLIC)."<small>(大小寫和符號需留意,兩個文字間用空白分隔)</small></td></tr>\n";
}
 
/* 在接收到送出要求後馬上檢查是否正確 */
function autoHookRegistBegin(&$name, &$email, &$sub, &$com, $upfileInfo, $accessInfo){
$resp = recaptcha_check_answer($this->KEY_PRIVATE, $_SERVER['REMOTE_ADDR'], $_POST['recaptcha_challenge_field'], $_POST['recaptcha_response_field']);
if(!$resp->is_valid){ error('reCAPTCHA 驗證碼錯誤!除大小寫須注意之外,標點符號及兩個單字都需輸入 (以空白分隔)'); } // 檢查
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_dummy/mod_dummy.php
@@ -0,0 +1,64 @@
<?php
class mod_dummy{
var $SELF;
 
/**
* 建構元
*/
function mod_dummy($PMS){
// 自建構元取出 $PMS 變數 (6th.Release 開始加入)
// 使用 hookModuleMethod 註冊 ModulePage,__CLASS__ 代表物件類別名稱 (本例為 mod_dummy)
$PMS->hookModuleMethod('ModulePage', __CLASS__);
// 取得 ModulePage URL,並存在變數裡
$this->SELF = $PMS->getModulePageURL(__CLASS__);
}
 
/**
* 回傳模組名稱方法
*
* @return 模組名稱。建議回傳格式: mod_xxx : 簡短註解
*/
function getModuleName(){
return __CLASS__.' : 展示掛載點功能模組';
}
 
/**
* 回傳模組版本號方法
*
* @return 模組版本號。
*/
function getModuleVersionInfo(){
return 'v110403';
}
 
// 以下為 autoHookXXX 的實驗,可以觀察到各常用掛載點是如何操作
function autoHookToplink(&$link){
$link .= '[<a href="'.$this->SELF.'">統計</a>]'."\n";
}
 
function autoHookPostInfo(&$txt){
$txt .= '<li>目前線上人數:102</li>'."\n";
}
 
function autoHookThreadFront(&$txt){
$txt .= '<div style="text-align: center;"><a href="#">[AD] 這是廣告#01!</a></div>'."\n";
}
function autoHookThreadRear(&$txt){
$txt .= '<div style="text-align: center;"><a href="#">[AD] 這是廣告#02!</a></div>'."\n";
}
 
function autoHookFoot(&$foot){
$foot .= '<span class="warn_txt2">本網站由 雙貓聯合站 提供資源,謹此致謝</span>'."\n";
}
 
/**
* 模組頁面方法
*
* 此方法為瀏覽 ModulePage URL 之後,程式會呼叫的方法。你可以在此印出屬於模組自己的內容,比如說設定項目,列表等等。
*/
function ModulePage(){
echo "Welcome to my world.";
}
}
?>
New file
/release/Modules-PIO-v6/mod_fblike/mod_fblike.php
@@ -0,0 +1,34 @@
<?php
class mod_fblike{
var $site, $url;
function mod_fblike(){
$this->site = TITLE;
$this->url = fullURL().PHP_SELF.'?res=';
}
 
function getModuleName(){
return __CLASS__.' : Facebook Like Button';
}
 
function getModuleVersionInfo(){
return 'v110102';
}
 
function autoHookHead(&$style, $isReply){
global $PIO;
if($isReply){
$p = $PIO->fetchPosts($isReply);
$sub = $p[0]['sub'];
$style .= <<< _HERE_
<meta property="og:site_name" content="{$this->site}" />
<meta property="og:title" content="{$sub}" />
<meta property="og:url" content="{$this->url}{$isReply}" />
_HERE_;
}
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
$arrLabels['{$REPLYBTN}'] .= '&nbsp;<iframe src="http://www.facebook.com/plugins/like.php?href='.urlencode($this->url.$post['no']).'&amp;layout=button_count&amp;width=90%anp;font=arial" scrolling="no" frameborder="0" allowTransparency="true" style="border: medium none; overflow: hidden; height: 20px; width: 90px; vertical-align: text-bottom;"></iframe>';
}
}
?>
New file
/release/Modules-PIO-v6/mod_csrf_prevent/mod_csrf_prevent.php
@@ -0,0 +1,23 @@
<?php
class mod_csrf_prevent{
function getModuleName(){
return __CLASS__.' : 防止偽造跨站請求 (CSRF)';
}
 
function getModuleVersionInfo(){
return 'b110403';
}
 
function autoHookRegistBegin(&$name, &$email, &$sub, &$com, $upfileInfo, $accessInfo, $isReply){
$CSRFdetectd = false;
/* 檢查 HTTP_REFERER (防止跨站 form)
* 1. 無 HTTP_REFERER
* 2. HTTP_REFERER 不是此網域
*/
if(!isset($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], fullURL()) !== 0)
$CSRFdetectd = true;
 
if($CSRFdetectd) error('CSRF detected!');
}
}
?>
New file
/release/Modules-PIO-v6/mod_typepad_antispam/howto.txt
@@ -0,0 +1,16 @@
License:
 
mod_typepad_antispam is not a part of Pixmicat! package. So it's not licensed under the Clarified Artistic License. It's in the public domain.
TypePad AntiSpam is available under an open source license (GPL v2).
 
中文安裝指引:
 
1. 將 mod_typepad_antispam.php 跟隨附圖檔放到 module/ 目錄
2. 修改 mod_typepad_antispam.php 的 $this->api_key,請先到 http://antispam.typepad.com/ 加入會員及申請 API key
3. 修改 config.php,在模組載入區塊下加一行 $ModuleList[] = 'mod_typepad_antispam';
 
English Instruction:
 
1. Put "mod_typepad_antispam.php" and other gif file into the module/ directory.
2. Use your favorite editor to open "mod_typepad_antispam.php" and fill your API key ($this->api_key). If you don't have one, go http://antispam.typepad.com/ to request for free.
3. Finally open "config.php" and add one line ($ModuleList[] = 'mod_typepad_antispam';) into the "Modules to be loaded" block.
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes:

Name: svn:mime-type
+ application/octet-stream

/release/Modules-PIO-v6/mod_typepad_antispam/typepadantispam-logo.gif
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_typepad_antispam/mod_typepad_antispam.php
@@ -0,0 +1,189 @@
<?php
/* mod_typepad_antispam : TypePad AntiSpam Protection BETA
* $Id$
* $Date$
*/
 
class mod_typepad_antispam{
var $THISPAGE, $api_key, $blog, $service_host, $api_host, $plugin_ver, $protocal_ver, $api_port, $recordfile;
 
function mod_typepad_antispam(){
global $PMS;
$this->THISPAGE = $PMS->getModulePageURL(__CLASS__);
$PMS->hookModuleMethod('ModulePage', __CLASS__); // Register ModulePage
 
// TypePad AntiSpam API key 輸入位置 (申請 http://antispam.typepad.com/info/get-api-key.html)
$this->api_key = '1234567890ab';
 
// 下列若無必要請勿修改
# Index page location (http:// included)
$this->blog = fullURL().PHP_SELF2;
# Base hostname for API requests (API key is always prepended to this)
$this->service_host = 'api.antispam.typepad.com';
$this->api_host = $this->api_key.'.'.$this->service_host;
# Plugin version
$this->plugin_ver = '1.0';
# API Protocol version
$this->protocol_ver = '1.1';
# Port for API requests to service host
$this->api_port = 80;
# Spam count file
$this->recordfile = 'mod_typepad_antispam.tmp';
}
 
function getModuleName(){
return 'mod_typepad_antispam : TypePad AntiSpam Protection BETA';
}
 
function getModuleVersionInfo(){
return '4th.Release.3 (v080703)';
}
 
function ModulePage(){
global $PMS;
$dat = '';
 
$PMS->hookModuleMethod('Head', array(&$this, 'hookHeadCSS'));
head($dat);
$dat .= '
<div id="linkbar">
[<a href="'.PHP_SELF2.'">回到版面</a>]
<div class="bar_reply">TypePad AntiSpam</div>
</div>
<div id="container">
<ul>
<li>金鑰狀態: '.($this->_typepadantispam_verify_key() ? 'OK' : 'NG').'</li>
<li>攔截狀態:
<div id="typepadantispamwrap">
<div id="typepadantispamstats">
<a id="tpaa" href="http://antispam.typepad.com/">
<div id="typepadantispam1">
<span id="typepadantispamcount">'.$this->_typepadantispam_spam_count().'</span>
<span id="typepadantispamsc">spam comments</span>
</div>
<div id="typepadantispam2">
<span id="typepadantispambb"></span>
<span id="typepadantispama"></span>
</div>
<div id="typepadantispam2">
<span id="typepadantispambb">blocked by</span><br />
<span id="typepadantispama"><img src="module/typepadantispam-logo.gif" style="border: 0;" /></span>
</div>
</a>
</div>
</div></li>
</ul>
</div>
<hr />';
foot($dat);
echo $dat;
}
 
/* 掛載樣式表 */
function hookHeadCSS(&$style, $isReply){
$style .= '<style type="text/css">
#typepadantispamwrap #tpaa,#tpaa:link,#tpaa:hover,#tpaa:visited,#tpaa:active{text-decoration:none}
#tpaa:hover{border:none;text-decoration:none}
#tpaa:hover #typepadantispam1{display:none}
#tpaa:hover #typepadantispam2,#typepadantispam1{display:block}
#typepadantispam1{padding-top:5px;}
#typepadantispam2{display:none;padding-top:0px;color:#333;}
#typepadantispama{font-size:16px;font-weight:bold;line-height:18px;text-decoration:none;}
#typepadantispamcount{display:block;font:15px Verdana,Arial,Sans-Serif;font-weight:bold;text-decoration:none}
#typepadantispamwrap #typepadantispamstats{background:url(module/typepadantispam.gif) no-repeat top left;border:none;font:11px "Trebuchet MS","Myriad Pro",sans-serif;height:40px;line-height:100%;overflow:hidden;padding:3px 0 8px;text-align:center;width:120px}
</style>
';
}
 
/**
* 對遠端服務伺服器送出要求
* @return array $response[0]: 檔頭, [1]: 內容
*/
function _typepadantispam_http_post($request, $host, $path, $port = 80){
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n";
$http_request .= "Content-Length: ".strlen($request)."\r\n";
$http_request .= "User-Agent: Pixmicat!/".$this->getModuleVersionInfo()." | TypePadAntiSpam/$this->plugin_ver\r\n";
$http_request .= "\r\n";
$http_request .= $request;
 
$response = '';
if(false != ($fs = @fsockopen($host, $port, $errno, $errstr, 10))){
fwrite($fs, $http_request);
while(!feof($fs))
$response .= fgets($fs, 1160); // One TCP-IP packet
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
}
return $response;
}
 
/**
* 檢查 API key 正確性
* @return boolean API key 正確性
*/
function _typepadantispam_verify_key(){
$blog = $this->blog;
$key = $this->api_key;
$response = $this->_typepadantispam_http_post("key=$key&blog=$blog", $this->service_host, "/$this->protocol_ver/verify-key", $this->api_port);
return (is_array($response) && isset($response[1]) && $response[1] == 'valid');
}
 
/**
* 回傳目前阻擋 Spam 數量
* @return int Spam 數量
*/
function _typepadantispam_spam_count(){
return file_exists($this->recordfile) ? intval(file_get_contents($this->recordfile)) : 0;
}
 
/**
* 更新 Spam 阻擋數量
*/
function _typepadantispam_spam_count_update($newInt){
$fp = fopen($this->recordfile, 'w');
flock($fp, LOCK_EX);
fwrite($fp, $newInt);
flock($fp, LOCK_UN);
fclose($fp);
@chmod($this->recordfile, 0666);
}
 
function autoHookLinksAboveBar(&$link, $pageId, $addinfo=false){
if($pageId=='status') $link .= ' [<a href="'.$this->THISPAGE.'">Spam 統計</a>]';
}
 
/**
* 將文章傳送至遠端服務伺服器檢查是否為 Spam
*/
function autoHookRegistBegin(&$name, &$email, &$sub, &$com, $upfileInfo, $accessInfo){
$comment = array();
$comment['blog'] = $this->blog;
$comment['user_ip'] = preg_replace( '/[^0-9., ]/', '', $_SERVER['REMOTE_ADDR']);
$comment['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
$comment['referrer'] = $_SERVER['HTTP_REFERER'];
$comment['comment_type'] = '';
$comment['comment_author'] = $name;
$comment['comment_author_email'] = $email;
$comment['comment_author_url'] = '';
$comment['comment_content'] = $com;
 
// 附加其他 SERVER 環境變數
$ignore = array('HTTP_COOKIE');
foreach($_SERVER as $key => $value)
if(!in_array($key, $ignore)) $comment["$key"] = $value;
 
// URL 編碼
$query_string = '';
foreach($comment as $key => $data)
$query_string .= $key.'='.urlencode(stripslashes($data)).'&';
 
$response = $this->_typepadantispam_http_post($query_string, $this->api_host, "/$this->protocol_ver/comment-check", $this->api_port);
if (isset($response[1]) && 'true' == $response[1]){ // 判斷為 Spam
$this->_typepadantispam_spam_count_update($this->_typepadantispam_spam_count() + 1);
error('經判斷此發言為 Spam');
}
}
}
?>
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes:

Name: svn:mime-type
+ application/octet-stream

/release/Modules-PIO-v6/mod_typepad_antispam/typepadantispam.gif
New file
/release/Modules-PIO-v6/mod_captcha/howto.txt
@@ -0,0 +1,15 @@
License:
 
mod_captcha is not a part of Pixmicat! package. So it's not licensed under the Clarified Artistic License. It's in the public domain.
 
中文安裝指引:
 
1. 將 mod_captcha.php、font1.gdf 放到 module/ 目錄
2. 修改 mod_captcha.php,可自由修改 $this->CAPTCHA_ 前綴的參數
3. 修改 config.php,在模組載入區塊下加一行 $ModuleList[] = 'mod_captcha';
 
English Instruction:
 
1. Put "mod_captcha.php" and "font1.gdf" into the module/ directory.
2. Use your favorite editor to open "mod_captcha.php". You can change the "$this->CAPTCHA_" prefix settings.
3. Finally open "config.php" and add one line ($ModuleList[] = 'mod_captcha';) into the "Modules to be loaded" block.
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes:

Name: svn:mime-type
+ application/octet-stream

/release/Modules-PIO-v6/mod_captcha/font1.gdf
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_captcha/mod_captcha.php
@@ -0,0 +1,134 @@
<?php
/*
mod_captcha.php
 
原始概念來自於各技術討論區,將各種想法混合實做而成。
 
最主要基礎是此頁內容:
http://jmhoule314.blogspot.com/2006/05/easy-php-captcha-tutorial-today-im.html
加上回應的Kris Knigga修改的成果。
*/
 
class mod_captcha{
var $SELF, $CAPTCHA_TMPDIR, $CAPTCHA_WIDTH, $CAPTCHA_HEIGHT, $CAPTCHA_LENGTH, $CAPTCHA_GAP, $CAPTCHA_TEXTY, $CAPTCHA_FONTMETHOD, $CAPTCHA_FONTFACE, $CAPTCHA_ECOUNT;
 
function mod_captcha(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', 'mod_captcha'); // Register ModulePage
$this->SELF = $PMS->getModulePageURL('mod_captcha'); // Self Location
 
$this->CAPTCHA_WIDTH = 150; // 圖片寬
$this->CAPTCHA_HEIGHT = 25; // 圖片高
$this->CAPTCHA_LENGTH = 6; // 明碼字數
$this->CAPTCHA_GAP = 20; // 明碼字元間隔
$this->CAPTCHA_TEXTY = 20; // 字元直向位置
$this->CAPTCHA_FONTMETHOD = 0; // 字體使用種類 (0: GDF (*.gdf) 1: TrueType Font (*.ttf))
$this->CAPTCHA_FONTFACE = array('./module/font1.gdf'); // 使用之字型 (可隨機挑選,惟字型種類需要相同不可混用)
$this->CAPTCHA_ECOUNT = 2; // 圖片混淆用橢圓個數
 
AttachLanguage(array($this, '_loadLanguage')); // 載入語言檔
}
 
function getModuleName(){
return 'mod_captcha : CAPTCHA 驗證圖像機制';
}
 
function getModuleVersionInfo(){
return '4th.Release.4-dev (v090524)';
}
 
/* 在頁面附加 CAPTCHA 圖像和功能 */
function autoHookPostForm(&$form){
global $languages;
$form .= '<tr><td class="Form_bg"><b>'._T('modcaptcha_captcha').'</b></td><td><img src="'.$this->SELF.'" alt="'._T('modcaptcha_captcha_alt').'" id="chaimg" /><small>(<a href="#" onclick="(function(){var i=document.getElementById(\'chaimg\'),s=i.src;i.src=s+\'&amp;\';})();">'._T('modcaptcha_reload').'</a>)</small><br /><input type="text" name="captchacode" />'._T('modcaptcha_enterword').'</td></tr>'."\n";
}
 
/* 在接收到送出要求後馬上檢查明暗碼是否符合 */
function autoHookRegistBegin(&$name, &$email, &$sub, &$com, $upfileInfo, $accessInfo){
global $languages;
@session_start();
$MD5code = isset($_SESSION['captcha_dcode']) ? $_SESSION['captcha_dcode'] : false;
if($MD5code===false || !isset($_POST['captchacode']) || md5(strtoupper($_POST['captchacode'])) !== $MD5code){ // 大小寫不分檢查
unset($_SESSION['captcha_dcode']);
error(_T('modcaptcha_worderror'));
}
}
 
function ModulePage(){
$this->OutputCAPTCHA(); // 生成暗碼、CAPTCHA圖像
}
 
/* 生成CAPTCHA圖像、明碼、暗碼及內嵌用Script */
function OutputCAPTCHA(){
@session_start();
 
// 隨機生成明碼、暗碼
$byteTable = Array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'); // 明碼定義陣列
$LCode = ''; // 明碼
for($i = 0; $i < $this->CAPTCHA_LENGTH; $i++) $LCode .= $byteTable[rand(0, count($byteTable) - 1)]; // 隨機抽碼
$DCode = md5($LCode); // 暗碼 (明碼的MD5)
$_SESSION['captcha_dcode'] = $DCode; // 暗碼存入 Session
 
// 生成暫存圖像
$captcha = ImageCreateTrueColor($this->CAPTCHA_WIDTH, $this->CAPTCHA_HEIGHT);
$randcolR = rand(100, 230); $randcolG = rand(100, 230); $randcolB = rand(100, 230); // 隨機色碼值
$backColor = ImageColorAllocate($captcha, $randcolR, $randcolG, $randcolB); // 背景色
ImageFill($captcha, 0, 0, $backColor); // 填入背景色
$txtColor = ImageColorAllocate($captcha, $randcolR - 40, $randcolG - 40, $randcolB - 40); // 文字色
$rndFontCount = count($this->CAPTCHA_FONTFACE); // 隨機字型數目
 
// 打入文字
for($p = 0; $p < $this->CAPTCHA_LENGTH; $p++){
if($this->CAPTCHA_FONTMETHOD){ // TrueType 字型
// 設定旋轉角度 (左旋或右旋)
if(rand(1, 2)==1) $degree = rand(0, 25);
else $degree = rand(335, 360);
// 圖層, 字型大小, 旋轉角度, X軸, Y軸 (字左下方起算), 字色, 字型, 印出文字
ImageTTFText($captcha, rand(14, 16), $degree, ($p + 1) * $this->CAPTCHA_GAP, $this->CAPTCHA_TEXTY, $txtColor, $this->CAPTCHA_FONTFACE[rand(0, $rndFontCount - 1)], substr($LCode, $p, 1));
}else{ // GDF 字型
$font = ImageLoadFont($this->CAPTCHA_FONTFACE[rand(0, $rndFontCount - 1)]);
// 圖層, 字型, X軸, Y軸 (字左上方起算), 印出文字, 字色
ImageString($captcha, $font, ($p + 1) * $this->CAPTCHA_GAP, $this->CAPTCHA_TEXTY - 18, substr($LCode, $p, 1), $txtColor);
}
}
 
// 混淆用 (畫橢圓)
for($n = 0; $n < $this->CAPTCHA_ECOUNT; $n++){
ImageEllipse($captcha, rand(1, $this->CAPTCHA_WIDTH), rand(1, $this->CAPTCHA_HEIGHT), rand(50, 100), rand(12, 25), $txtColor);
ImageEllipse($captcha, rand(1, $this->CAPTCHA_WIDTH), rand(1, $this->CAPTCHA_HEIGHT), rand(50, 100), rand(12, 25), $backColor);
}
 
// 輸出圖像
header('Content-Type: image/png');
header('Cache-Control: no-cache');
ImagePNG($captcha);
ImageDestroy($captcha);
}
 
function _loadLanguage(){
global $language;
if(PIXMICAT_LANGUAGE != 'zh_TW' && PIXMICAT_LANGUAGE != 'ja_JP' && PIXMICAT_LANGUAGE != 'en_US') $lang = 'en_US';
else $lang = PIXMICAT_LANGUAGE;
 
if($lang=='zh_TW'){
$language['modcaptcha_captcha'] = '發文驗證碼';
$language['modcaptcha_reload'] = '看不懂?重讀';
$language['modcaptcha_enterword'] = '<small>(請輸入你在圖中看到的文字 大小寫不分)</small>';
$language['modcaptcha_captcha_alt'] = 'CAPTCHA 驗證碼圖像';
$language['modcaptcha_worderror'] = '您輸入的驗證碼錯誤!';
}elseif($lang=='ja_JP'){
$language['modcaptcha_captcha'] = '画像認証';
$language['modcaptcha_reload'] = 'リロード';
$language['modcaptcha_enterword'] = '<br /><small>(画像に表示されている文字を入力してください。大文字と小文字は区別されません。)</small>';
$language['modcaptcha_captcha_alt'] = 'CAPTCHA画像';
$language['modcaptcha_worderror'] = '画像認証に失敗しました';
}elseif($lang=='en_US'){
$language['modcaptcha_captcha'] = 'Captcha';
$language['modcaptcha_reload'] = 'Can\'t read? Reload';
$language['modcaptcha_enterword'] = '<small>(Please enter the words you saw. Case-insensitive.)</small>';
$language['modcaptcha_captcha_alt'] = 'CAPTCHA Image';
$language['modcaptcha_worderror'] = 'The words you sent are error!';
}
}
}
?>
New file
/release/Modules-PIO-v6/mod_archiver/archives/archivestyle.xsl
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
<xsl:template match="/">
<html xml:lang="zh-tw">
<head>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="Sat, 1 Jan 2000 00:00:00 GMT" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Language" content="zh-tw" />
<title>Thread <xsl:value-of select="threads/@no" /> : Pixmicat! Archiver</title>
<link rel="stylesheet" type="text/css" href="archivestyle.css" />
<script type="text/javascript">
<![CDATA[
if(typeof ActiveXObject!='undefined'){
document.write('<style type="text/css">.reply { display: inline ; zoom: 1; }</style>');
attachEvent("onload", function (){var divs=document.getElementsByTagName('div');var divs_cnt=divs.length;for(i=0;i<divs_cnt;i++){if(divs[i].className.substr(0,5)=='reply'){divs[i].insertAdjacentHTML('afterEnd','<br />');}}});
}
]]>
</script>
</head>
<body>
 
<div id="contents">
<xsl:apply-templates select="threads" />
<hr />
</div>
 
<div id="footer">
<!-- Pixmicat! -->
<small>- <a href="http://pixmicat.openfoundry.org/" rel="_blank">Pixmicat!</a> -</small>
</div>
 
</body>
</html>
</xsl:template>
 
<xsl:template match="threads">
<xsl:variable name="image_base"><xsl:value-of select="@no" /><xsl:if test="meta/@archivedate != ''">-<xsl:value-of select="meta/@archivedate" /></xsl:if>_files/</xsl:variable>
<div class="threadpost">
<xsl:if test="image != ''"> <!--有圖片-->
<xsl:variable name="image_name"><xsl:value-of select="image" /><xsl:value-of select="image/@ext" /></xsl:variable>
<xsl:variable name="image_url"><xsl:value-of select="$image_base" /><xsl:value-of select="$image_name" /></xsl:variable>
檔名:<a target="_blank"><xsl:attribute name="href"><xsl:value-of select="$image_url" /></xsl:attribute><xsl:value-of select="$image_name" /></a>-(<xsl:value-of select="image/@kbyte" /> KB, <xsl:value-of select="image/@scale" />) <small>[以預覽圖顯示]</small><br />
<a target="_blank">
<xsl:attribute name="href"><xsl:value-of select="$image_url" /></xsl:attribute>
<img class="img">
<xsl:attribute name="title"><xsl:value-of select="image/@kbyte" /> KB</xsl:attribute>
<xsl:attribute name="alt"><xsl:value-of select="image/@kbyte" /> KB</xsl:attribute>
<xsl:attribute name="src"><xsl:value-of select="$image_base" /><xsl:value-of select="image" />s.jpg</xsl:attribute>
</img>
</a>
</xsl:if>
<span class="title"><xsl:value-of select="subject" /></span>
名稱: <span class="name"><xsl:value-of select="name" /></span> [<xsl:value-of select="date" /> <xsl:if test="host"> IP:<xsl:value-of select="host" /></xsl:if>] No.<xsl:value-of select="@no" />
<div class="quote">
<xsl:apply-templates select="comment" />
<xsl:if test="pushpost != ''">
<div class="pushpost"><xsl:apply-templates select="pushpost" /></div>
</xsl:if>
</div>
</div>
<xsl:for-each select="reply">
<div class="reply"><xsl:attribute name="id">r<xsl:value-of select="@no" /></xsl:attribute>
<span class="title"><xsl:value-of select="subject" /></span>
名稱: <span class="name"><xsl:value-of select="name" /></span> [<xsl:value-of select="date" /> <xsl:if test="host"> IP:<xsl:value-of select="host" /></xsl:if>] No.<xsl:value-of select="@no" />
<xsl:if test="image != ''"> <!--有圖片-->
<xsl:variable name="image_name"><xsl:value-of select="image" /><xsl:value-of select="image/@ext" /></xsl:variable>
<xsl:variable name="image_url"><xsl:value-of select="$image_base" /><xsl:value-of select="$image_name" /></xsl:variable>
<br />檔名:<a target="_blank"><xsl:attribute name="href"><xsl:value-of select="$image_url" /></xsl:attribute><xsl:value-of select="$image_name" /></a>-(<xsl:value-of select="image/@kbyte" /> KB, <xsl:value-of select="image/@scale" />) <small>[以預覽圖顯示]</small><br />
<a target="_blank">
<xsl:attribute name="href"><xsl:value-of select="$image_url" /></xsl:attribute>
<img class="img">
<xsl:attribute name="title"><xsl:value-of select="image/@kbyte" /> KB</xsl:attribute>
<xsl:attribute name="alt"><xsl:value-of select="image/@kbyte" /> KB</xsl:attribute>
<xsl:attribute name="src"><xsl:value-of select="$image_base" /><xsl:value-of select="image" />s.jpg</xsl:attribute>
</img>
</a>
</xsl:if>
<div class="quote">
<xsl:apply-templates select="comment" />
<xsl:if test="pushpost != ''">
<div class="pushpost"><xsl:apply-templates select="pushpost" /></div>
</xsl:if>
</div>
<xsl:if test="category != ''"> <!--有類別-->
<div class="category">類別: <xsl:value-of select="category" /></div>
</xsl:if>
</div>
</xsl:for-each>
</xsl:template>
 
<xsl:template match="comment">
<xsl:apply-templates />
</xsl:template>
 
<xsl:template match="br"><br /></xsl:template>
 
</xsl:stylesheet>
New file
/release/Modules-PIO-v6/mod_archiver/archives/archivestyle.css
@@ -0,0 +1,40 @@
@media all{ /* 通用設定 */
html { background: #FFE; color: #800000; } /* 基本網頁背景樣式 */
a:link { color: #00E; } /* 正常連結樣式 */
a:hover { color: #D00; } /* hover時連結樣式 */
a:visited { color: #00E; } /* 已拜訪連結樣式 */
a.qlink { text-decoration: none; } /* 引用用連結樣式 */
small { font-size: 0.8em; } /* 小字樣式(eg.[以預覽圖顯示]) */
hr { clear: left; } /* 分隔線樣式 */
img { border: 0; } /* 圖片顯示樣式 */
 
.threadpost { } /* 討論串首篇樣式 */
.reply { display: table; margin: 0.5ex 1em 0 1em; background: #F0E0D6; } /* 討論串回應樣式 */
.name { color: #117743; font-weight: bold; } /* 文章張貼者名稱樣式 */
.admin_cap { color: #0000FF; } /* 管理員キャップ樣式設定 */
.img { float: left; margin: 1ex 2ex; } /* 討論串圖片顯示樣式 */
.title { color: #CC1105; font-size: 1.125em; font-weight: bold; } /* 討論串標題樣式 */
.nor { font-weight: normal; } /* Trip取消粗體用 */
.quote { margin: 1em 2em; } /* 討論串內文縮排樣式 */
.category {font-size: 0.8em; color: gray;} /* 類別標籤 */
 
#footer { text-align: center; clear: both; } /* 頁尾樣式 */
.pushpost { background-color: #fff; font-size: 0.8em; padding: 10px; } /* 推文 */
}
 
@media screen{ /* 標準顯示(一般顯示器)模式附加規則 */
}
 
@media handheld{ /* 手持設備(手機,PDA等)附加規則 */
html { max-width: 320px; margin: auto; font-size: 9px; } /* 320px為多數PDA的顯示寬度 */
 
.img { margin: 0.5ex 0.5ex; max-width: 125px; } /* 討論串圖片顯示樣式 */
.reply { clear: left; margin: 0.5ex 0 0 0; } /* 討論串回應樣式 */
.quote { margin: 1ex 1ex; } /* 討論串內文縮排樣式 */
}
 
@media print{ /* 列印,預覽列印附加規則 */
html { background: #FFF; color: #000; } /* 網頁改成白底黑字,節省彩色列印成本 */
}
New file
/release/Modules-PIO-v6/mod_archiver/archives/index.php
@@ -0,0 +1,73 @@
<?php
echo '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-tw">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="zh-tw">
<title>Index : Pixmicat! Archiver</title>
<link rel="stylesheet" type="text/css" href="archivestyle.css" />
</head>
<body>
 
<div id="content">
<p>靜態庫存頁面列表:</p>
';
 
/* 取出 XML 檔案討論串資訊 */
function getSubjectAndName($file){
if(!$xml = simplexml_load_file($file, NULL, LIBXML_COMPACT))
return false;
 
$name = $xml->name;
if($xml->name->span) $name .= $xml->name->span; // for Trip
if($xml->name->span->span) $name .= $xml->name->span->span; // for Trip of AdminCap
return array('sub' => $xml->subject, 'name' => $name);
}
 
/* 取得靜態庫存頁面列表 */
$fileList = Array();
function GetArchives($sPath){
global $fileList;
// 打開目錄逐個搜尋XML檔案並加入陣列
$handle = opendir($sPath);
while($file = readdir($handle)){
if($file != '..' && $file != '.' && is_file($sPath.'/'.$file)) // 為檔案
if(strpos($file, '.xml')) $fileList[] = $file;
}
// 排序陣列
closedir($handle);
@sort($fileList);
@reset($fileList);
}
 
GetArchives('.');
$t = array(); $infobar = '';
 
// 列出檔案連結
echo "<ul>\n";
if($fileList_count = count($fileList)){ // 有列表
for($i = 0; $i < $fileList_count; $i++){
$infobar = ($t = getSubjectAndName($fileList[$i])) ? $t['name'].' - '.$t['sub'] : '';
echo ' <li><a href="'.$fileList[$i].'">'.$fileList[$i]."</a> $infobar</li>\n";
}
}else{
echo '<li>目前還沒有靜態庫存頁面可供瀏覽</li>';
}
echo '</ul>
</div>
 
<hr />
';
 
echo <<< __HTML_FOOTER__
 
<div id="footer">
<!-- Pixmicat! -->
<small>- <a href="http://pixmicat.openfoundry.org/" rel="_blank">Pixmicat!</a> -</small>
</div>
 
</body>
</html>
__HTML_FOOTER__;
?>
New file
/release/Modules-PIO-v6/mod_archiver/mod_archiver.php
@@ -0,0 +1,159 @@
<?php
/*
mod_archiver : Pixmicat! Archiver 靜態庫存頁面(精華區)生成
*/
 
class mod_archiver{
var $page;
var $ARCHIVE_ROOT, $MULTI_COPY, $ADMIN_ONLY;
var $PUSHPOST_SEPARATOR, $PROCESS_PUSHPOST;
 
function mod_archiver(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 向系統登記模組專屬獨立頁面
$this->page = $PMS->getModulePageURL(__CLASS__);
 
$this->ARCHIVE_ROOT = './archives/'; // 生成靜態庫存頁面之存放位置
$this->MULTI_COPY = true; // 容許同一串有多份存檔
$this->ADMIN_ONLY = true; // 只容許管理員生成靜態庫存頁面
 
$this->PUSHPOST_SEPARATOR = '[MOD_PUSHPOST_USE]';
$this->PROCESS_PUSHPOST = 1; // 處理推文 (是:1 否:0)
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_archiver : Pixmicat! Archiver 靜態庫存頁面(精華區)生成';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '5th.Release (v100905)';
}
 
/* 自動掛載:頂部連結列 */
function autoHookToplink(&$linkbar, $isReply){
global $PMS;
$linkbar .= '[<a href="'.$this->ARCHIVE_ROOT.'">精華區</a>]'."\n";
}
 
function ModulePage(){
if($this->ADMIN_ONLY && !adminAuthenticate('check')) { // 只容許管理員生成靜態庫存頁面
echo 'Access Denied.';
return;
}
$res = isset($_GET['res']) ? $_GET['res'] : 0; // 欲生成靜態庫存頁面之討論串編號
 
if(!$res || (!$this->MULTI_COPY && glob($this->ARCHIVE_ROOT.$res.'-*.xml'))){
echo('No argument or the archive already existed.'); // 參數不對或XML檔案已存在
}else{
$this->GenerateArchive($res); // 生成靜態庫存頁面
echo 'FINISH.';
}
}
 
function autoHookAdminList(&$modFunc, $post, $isres){
global $PMS;
if(!$isres) $modFunc .= '[<a href="'.$this->page.'&amp;res='.$post['no'].'">存</a>]';
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
if($this->ADMIN_ONLY) return; // 只允許管理員生成
$arrLabels['{$QUOTEBTN}'] .= '&nbsp;[<a href="'.$this->page.'&amp;res='.$post['no'].'">存</a>]';
}
 
/* 取出討論串結構並製成XML結構 */
function GenerateArchive($res){
global $PIO, $FileIO;
$aryNO = $aryNAME = $aryDATE = $arySUBJECT = $aryCOMMENT = $aryPUSHPOST = $aryCATEGORY = $aryIMAGE = array(); // 討論串結構陣列
 
/* 第一部份:先製成討論串結構陣列 */
$tid = $PIO->fetchPostList($res); // 取得特定討論串之編號結構
$post = $PIO->fetchPosts($tid); // 取出資料
$post_count = count($post);
if($post_count==0){ echo 'Not found.'; break; }
for($i = 0; $i < $post_count; $i++){
extract($post[$i]);
$name = preg_replace('/(◆.{10})/', '<span class="nor">$1</span>', $name); // Trip取消粗體
if(USE_CATEGORY) {
$ary_category2 = array(); $ary_category = explode(',', str_replace('&#44;', ',', $category)); $ary_category = array_map('trim', $ary_category);
foreach($ary_category as $c) if($c) $ary_category2[]=$c;
$category = implode(', ', $ary_category2);
} else $category = '';
$push_post = '';
if($this->PROCESS_PUSHPOST == 1) { // 處理推文
//echo $com;
$comArr = explode($this->PUSHPOST_SEPARATOR.'<br />', $com);
if(count($comArr) > 1) { // 有推文
$com = $comArr[0];
$push_post = $comArr[1];
}
}
$aryNO[] = $no; $aryNAME[] = $name; $aryDATE[] = $now; $arySUBJECT[] = $sub; $aryCOMMENT[] = $com; $aryPUSHPOST[] = $push_post; $aryCATEGORY[] = $category; // 置入陣列
if($FileIO->imageExists($tim.$ext)){ // 有貼圖
$size = (int)($FileIO->getImageFilesize($tim.$ext) / 1024);
$aryIMAGE[] = array($size, $imgw.'x'.$imgh, $ext, $tim);
}else $aryIMAGE[] = '';
}
$archiveDate = date('YmdHis');
 
/* 第二部份:生成XML結構 */
$tmp_c = '<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="archivestyle.xsl"?>
<threads no="'.$aryNO[0].'">
<meta creator="'.$this->getModuleVersionInfo().'"'.($this->MULTI_COPY?' archivedate="'.$archiveDate.'"':'').' />
<name>'.$aryNAME[0].'</name>
<date>'.$aryDATE[0].'</date>
<subject>'.$arySUBJECT[0].'</subject>
<comment>'.$aryCOMMENT[0].'</comment>
<pushpost>'.$aryPUSHPOST[0].'</pushpost>
<category>'.$aryCATEGORY[0].'</category>
';
if($aryIMAGE[0]) $tmp_c .= ' <image kbyte="'.$aryIMAGE[0][0].'" scale="'.$aryIMAGE[0][1].'" ext="'.$aryIMAGE[0][2].'">'.$aryIMAGE[0][3].'</image>';
else $tmp_c .= ' <image kbyte="" scale="" ext=""></image>';
for($p = 1; $p < $post_count; $p++){
$tmp_c .= '
<reply no="'.$aryNO[$p].'">
<name>'.$aryNAME[$p].'</name>
<date>'.$aryDATE[$p].'</date>
<subject>'.$arySUBJECT[$p].'</subject>
<comment>'.$aryCOMMENT[$p].'</comment>
<pushpost>'.$aryPUSHPOST[$p].'</pushpost>
<category>'.$aryCATEGORY[$p].'</category>
';
if($aryIMAGE[$p]) $tmp_c .= ' <image kbyte="'.$aryIMAGE[$p][0].'" scale="'.$aryIMAGE[$p][1].'" ext="'.$aryIMAGE[$p][2].'">'.$aryIMAGE[$p][3].'</image>';
else $tmp_c .= ' <image kbyte="" scale="" ext=""></image>';
$tmp_c .= '
</reply>';
}
$tmp_c .= '
</threads>';
 
/* 第三部份:儲存檔案 */
if(!($fp = fopen($this->ARCHIVE_ROOT.$res.'-'.$archiveDate.'.xml', 'w'))) exit('File open error!');
stream_set_write_buffer($fp, 0); // 立刻寫入不用緩衝
fwrite($fp, $tmp_c); // 寫入XML結構
fclose($fp);
// 另開新資料夾保存圖片
$nfolder = $this->ARCHIVE_ROOT.$res.'-'.$archiveDate.'_files/'; // 保存圖檔資料夾
if(!is_dir($nfolder)){ mkdir($nfolder); chmod($nfolder, 0777); } // 建立存放資料夾
for($n = 0; $n < $post_count; $n++){
if($aryIMAGE[$n]){
$img = $aryIMAGE[$n][3].$aryIMAGE[$n][2]; // 原圖
$thumb = $aryIMAGE[$n][3].'s.jpg'; // 預覽圖
if(FILEIO_BACKEND=='normal'){ // 一般後端,獨立判斷避免http wrapper被關閉無法複製的問題
$img2 = IMG_DIR.$aryIMAGE[$n][3].$aryIMAGE[$n][2];
$thumb2 = THUMB_DIR.$aryIMAGE[$n][3].'s.jpg';
}else{
$img2 = $FileIO->getImageURL($aryIMAGE[$n][3].$aryIMAGE[$n][2]);
$thumb2 = $FileIO->getImageURL($aryIMAGE[$n][3].'s.jpg');
}
if($FileIO->imageExists($img)) copy($img2, $nfolder.$img);
if($FileIO->imageExists($thumb)) copy($thumb2, $nfolder.$thumb);
}
}
}
}
?>
New file
/release/Modules-PIO-v6/mod_imgsizelimit/mod_imgsizelimit.php
@@ -0,0 +1,38 @@
<?php
/*
mod_imgsizelimit.php
*/
 
class mod_imgsizelimit{
var $MIN_W, $MIN_H, $MIN_FILESIZE, $MAX_W, $MAX_H;
 
function mod_imgsizelimit(){
$this->MIN_W = 320; // 最小寬度 (0為不限制)
$this->MIN_H = 240; // 最小高度 (0為不限制)
$this->MAX_W = 5000; // 最大寬度 (0為不限制)
$this->MAX_H = 5000; // 最大高度 (0為不限制)
$this->MIN_FILESIZE = 0; // 最小檔案大小 (位元組, 0為不限制)
}
 
function getModuleName(){
return 'mod_imgsizelimit : 限制圖像長寬大小';
}
 
function getModuleVersionInfo(){
return 'v110528';
}
 
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status){
if( ($dest !== '') && (
($this->MIN_W && $this->MIN_W > $imgWH[2]) ||
($this->MIN_H && $this->MIN_H > $imgWH[3]) ||
($this->MAX_W && $imgWH[2] > $this->MAX_W) ||
($this->MAX_H && $imgWH[3] > $this->MAX_H) ||
($this->MIN_FILESIZE && $this->MIN_FILESIZE > filesize($dest)) )
) {
unlink($dest);
error('圖像大小不符限制。');
}
}
}
?>
New file
/release/Modules-PIO-v6/mod_rss/mod_rss.php
@@ -0,0 +1,176 @@
<?php
/*
mod_rss : 提供RSS Feed訂閱服務
By: scribe
*/
 
class mod_rss{
var $FEED_COUNT, $FEED_STATUSFILE, $FEED_CACHEFILE, $FEED_DISPLAYTYPE, $BASEDIR, $SELF;
 
function mod_rss(){
global $PMS;
 
$this->FEED_COUNT = 10; // RSS 產生最大篇數
$this->FEED_UPDATETYPE = 1; // RSS 更新時機 (1: 瀏覽 MODULEPAGE 時更新, 2: 有新文章貼出時更新)
$this->FEED_DISPLAYTYPE = 'T'; // 資料取出形式 (T: 討論串取向, P: 文章取向)
$this->FEED_CACHEFILE = 'rss.xml'; // 資料輸出暫存檔 (靜態快取Feed格式)
 
$this->BASEDIR = fullURL(); // 基底 URL
switch($this->FEED_UPDATETYPE){
case 1: // MODULEPAGE
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 註冊獨立頁面
$this->SELF = $this->BASEDIR.$PMS->getModulePageURL(__CLASS__); // RSS 連結
$this->FEED_STATUSFILE = __CLASS__.'.tmp'; // 資料狀態暫存檔 (檢查資料需不需要更新)
break;
case 2: // Update on RegistAfterCommit
$this->SELF = $this->BASEDIR.$this->FEED_CACHEFILE; // RSS 連結
break;
}
}
 
function getModuleName(){
return __CLASS__.' : 提供RSS Feed訂閱服務';
}
 
function getModuleVersionInfo(){
return '4th.Release.3 (v110330)';
}
 
/* 在頁面加入指向 RSS 的 <link> 標籤*/
function autoHookHead(&$txt, $isReply){
$txt .= '<link rel="alternate" type="application/rss+xml" title="RSS 2.0 Feed" href="'.$this->SELF.'" />'."\n";
}
 
/* 文章儲存後更新 RSS 檔案 ($this->FEED_UPDATETYPE == 2 觸發) */
function autoHookRegistAfterCommit(){
global $PIO;
if($this->FEED_UPDATETYPE == 2){
$PIO->dbPrepare();
$this->GenerateCache(); // 更新 RSS
}
}
 
function autoHookFoot(&$foot){
$foot .= '<div style="position: absolute; top: 10px; left: 10px;"><a href="'.$this->SELF.'">RSS feed</a></div>
';
}
 
/* 模組獨立頁面 */
function ModulePage(){
global $PIO;
 
$PIO->dbPrepare();
if($this->IsDATAUpdated()) $this->GenerateCache(); // 若資料已更新則也更新RSS Feed快取
$this->RedirectToCache(); // 重導向到靜態快取
}
 
/* 檢查資料有沒有更新 */
function IsDATAUpdated(){
global $PIO;
if(isset($_GET['force'])) return true; // 強迫更新RSS Feed
 
$tmp_fsize = $PIO->getLastPostNo('afterCommit');
$tmp_ssize = file_exists($this->FEED_STATUSFILE) ? file_get_contents($this->FEED_STATUSFILE) : 0; // 讀取狀態暫存資料
if($tmp_fsize == $tmp_ssize) return false; // LastNo 相同,沒有更新
 
$fp = fopen($this->FEED_STATUSFILE, 'w');
stream_set_write_buffer($fp, 0); // 立刻寫入不用緩衝
flock($fp, LOCK_EX); // 鎖定
fwrite($fp, $tmp_fsize); // 更新
flock($fp, LOCK_UN); // 解鎖
fclose($fp);
@chmod($this->FEED_STATUSFILE, 0666); // 可讀可寫
return true; // 有更新過
}
 
/* 生成 / 更新靜態快取RSS Feed檔案 */
function GenerateCache(){
global $PIO, $FileIO;
$RFC_timezone = ' '.(TIME_ZONE < 0 ? '-' : '+').substr('0'.abs(TIME_ZONE), -2).'00'; // RFC標準所用之時區格式
 
switch($this->FEED_DISPLAYTYPE){
case 'T':
$plist = $PIO->fetchThreadList(0, $this->FEED_COUNT); // 取出前n筆討論串首篇編號
$plist_count = count($plist);
// 為何這樣取?避免 SQL-like 自動排序喪失時間順序
$post = array();
for($p = 0; $p < $plist_count; $p++){
$post[] = current($PIO->fetchPosts($plist[$p])); // 取出編號文章資料
}
break;
case 'P':
$plist = $PIO->fetchPostList(0, 0, $this->FEED_COUNT); // 取出前n筆文章編號
$post = $PIO->fetchPosts($plist);
break;
}
$post_count = count($post);
// RSS Feed內容
$tmp_c = '<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>'.TITLE.'</title>
<link>'.$this->BASEDIR.'</link>
<description>'.TITLE.'</description>
<language>zh-TW</language>
<generator>'.$this->getModuleName().' '.$this->getModuleVersionInfo().'</generator>
<atom:link href="'.$this->SELF.'" rel="self" type="application/rss+xml" />
';
for($i = 0; $i < $post_count; $i++){
$imglink = ''; // 圖檔
$resto = 0; // 回應
list($no, $resto, $time, $tw, $th, $tim, $ext, $sub, $com) = array(
$post[$i]['no'],
$post[$i]['resto'],
substr($post[$i]['tim'], 0, -3),
$post[$i]['tw'],
$post[$i]['th'],
$post[$i]['tim'],
$post[$i]['ext'],
$post[$i]['sub'],
$post[$i]['com']);
 
// 處理資料
if($ext && $FileIO->imageExists($tim.'s.jpg'))
$imglink = '<img src="'.$FileIO->getImageURL($tim.'s.jpg').'" alt="'.$tim.$ext.'" width="'.$tw.'" height="'.$th.'" /><br />';
$time = gmdate("D, d M Y H:i:s", $time + TIME_ZONE * 60 * 60).$RFC_timezone; // 本地時間RFC標準格式
$reslink = $this->BASEDIR.PHP_SELF.'?res='.($resto ? $resto : $no); // 回應連結
switch($this->FEED_DISPLAYTYPE){
case 'T':
$titleBar = $sub.' No.'.$no.' (Res: '.($PIO->postCount($no) - 1).')'; // 標題 No.編號 (Res:回應數)
break;
case 'P':
$titleBar = $sub.' ('.$no.')'; // 標題 (編號)
break;
}
 
$tmp_c .= '<item>
<title>'.$titleBar.'</title>
<link>'.$reslink.'</link>
<description>
<![CDATA[
'.$imglink.$com.'
]]>
</description>
<comments>'.$reslink.'</comments>
<guid isPermaLink="true">'.$reslink.'#r'.$no.'</guid>
<pubDate>'.$time.'</pubDate>
</item>
';
}
$tmp_c .= '</channel>
</rss>';
$fp = fopen($this->FEED_CACHEFILE, 'w');
flock($fp, LOCK_EX); // 鎖定
fwrite($fp, $tmp_c); // 更新
flock($fp, LOCK_UN); // 解鎖
fclose($fp);
@chmod($this->FEED_CACHEFILE, 0666); // 可讀可寫
}
 
/* 重導向到靜態快取 */
function RedirectToCache(){
header('HTTP/1.1 302 Moved Temporarily'); // 暫時性導向
header('Location: '.$this->BASEDIR.$this->FEED_CACHEFILE);
}
}
?>
New file
/release/Modules-PIO-v6/mod_mobile/mod_mobile.php
@@ -0,0 +1,116 @@
<?php
/*
mod_mobile : 行動版頁面顯示 (唯讀)
By: scribe
*/
 
class mod_mobile{
var $THREADLIST_NUMBER, $thisPage, $displayMode;
 
function mod_mobile(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', 'mod_mobile'); // 向系統登記模組專屬獨立頁面
 
$this->THREADLIST_NUMBER = 10; // 一頁顯示列表個數
$this->thisPage = $PMS->getModulePageURL('mod_mobile'); // 基底位置
$this->displayMode = isset($_COOKIE['dm']) ? $_COOKIE['dm'] : 's'; // 顯示模式 (s/m/l)
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_mobile : 行動版頁面顯示 (唯讀)';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '4th.Release.2 (v090819)';
}
 
/* 自動掛載:頂部連結列 */
function autoHookToplink(&$linkbar, $isReply){
$linkbar .= '[<a href="'.$this->thisPage.'">行動版</a>]'."\n";
}
 
/* 模組獨立頁面 */
function ModulePage(){
global $PIO;
 
$err = ''; // 錯誤資訊
$res = isset($_GET['r']) ? intval($_GET['r']) : 0; // 回應編號
if(isset($_GET['dm'])){ // 是否進入設定模式
$ss = $ms = $ls = '';
switch($this->displayMode){
case 's': $ss = ' selected="selected"'; break;
case 'm': $ms = ' selected="selected"'; break;
case 'l': $ls = ' selected="selected"'; break;
}
$this->mobileHead($err, TITLE.' - 設定');
$err .= '<div>[<a href="'.$this->thisPage.'">回首頁</a>]<br/><form action="'.(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $this->thisPage).'" method="post">顯示模式:<br/><select name="dm"><option value="s"'.$ss.'>精簡 (無圖,裁字)</option><option value="m"'.$ms.'>一般 (無圖,全字)</option><option value="l"'.$ls.'>完整 (有圖,全字)</option></select><br/><input type="submit" value="儲存"/></form></div><div id="f">-Pixmicat!m-</div></body></html>';
}else{
if(isset($_POST['dm'])){ setCookie('dm', ($this->displayMode = $_POST['dm']), time()+604800); }
if($res !== 0){
$pageMax = $page = null; // Not in use
if(!$PIO->isThread($res)){ $err = 'Thread Not Found'; }
else{ $post = $PIO->fetchPosts($PIO->fetchPostList($res)); }
}else{
$pageMax = ceil($PIO->threadCount() / $this->THREADLIST_NUMBER) - 1; // 分頁最大編號
$page = isset($_GET['p']) ? intval($_GET['p']) : 0; // 目前所在分頁
if($page < 0 || $page > $pageMax){ $err = 'Page Out of Range'; } // $page 超過範圍
else{ $post = $PIO->fetchPosts($PIO->fetchThreadList($this->THREADLIST_NUMBER * $page, $this->THREADLIST_NUMBER, true)); } // 編號由大到小排序取出
}
}
if($err){ echo $err; }
else{
$dat = ''; // HTML Buffer
$this->mobileHead($dat, TITLE);
$this->mobileBody($dat, $pageMax, $page, $res, $post);
$this->mobileFoot($dat);
echo $dat;
}
}
 
/* 行動版頁首 */
function mobileHead(&$dat, $title){
$dat .= '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.1//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><meta http-equiv="Cache-Control" content="no-cache"/><title>'.$title.'</title><style type="text/css">.s {color:red;} .n{color:green;} .w{color:gray;}</style></head>
<body>
';
}
 
/* 行動版內容 */
function mobileBody(&$dat, $pageMax, $page, $res, $post){
global $PIO, $FileIO;
$post_count = count($post);
$dat .= '<div id="c">';
// 逐步取資料
for($i = 0; $i < $post_count; $i++){
list($no, $sub, $name, $com, $tim, $ext) = array($post[$i]['no'], $post[$i]['sub'],$post[$i]['name'], $post[$i]['com'], $post[$i]['tim'], $post[$i]['ext']);
// 資料處理
if($this->displayMode==='s'){ $com = str_cut($com, 50); } // 取斷字元
$reply1 = $res ? '<span class="s">'.$sub.'</span>' : '<a href="'.$this->thisPage.'&amp;r='.$no.'">'.$sub.'</a>'; // 回應模式連結
$reply2 = $res ? '' : '<span class="w">('.($PIO->postCount($no) - 1).')</span>'; // 回應數
$img = ($this->displayMode==='l' && $FileIO->imageExists($tim.'s.jpg')) ? '<img src="'.$FileIO->getImageURL($tim.'s.jpg').'" alt="p"/><br/>' : '';
// 輸出
$dat .= '<div>'.$reply1.$reply2.'<span class="n">'.$name.'</span><br/>'.$img.$com.'</div><hr/>'."\n";
}
$dat .= '</div>';
if($page !== null){ // 分頁欄
$dat .= '<div id="p">';
if($page) $dat .= '<a href="'.$this->thisPage.'&amp;p='.($page - 1).'">|&lt;</a> ';
for($i = 0; $i <= $pageMax; $i++){
if($i==$page) $dat .= '[<b>'.$i.'</b>] ';
else $dat .= '[<a href="'.$this->thisPage.'&amp;p='.$i.'">'.$i.'</a>] ';
}
if($page < $pageMax) $dat .= '<a href="'.$this->thisPage.'&amp;p='.($page + 1).'">&gt;|</a>';
$dat .= '</div>';
}
}
 
/* 行動版頁尾 */
function mobileFoot(&$dat){
$dat .= '<div id="f">-Pixmicat!m-<br/><a href="'.$this->thisPage.'&amp;dm=set">顯示模式</a></div></body></html>';
}
}
?>
New file
/release/Modules-PIO-v6/mod_sectrip/mod_sectrip.php
@@ -0,0 +1,66 @@
<?php
class mod_sectrip{
var $secure_salt, $secureTrip;
var $myPage,$urlcount;
 
function mod_sectrip(){
global $PMS;
 
$PMS->hookModuleMethod('ModulePage', 'mod_sectrip'); // 向系統登記模組專屬獨立頁面
$this->myPage = $PMS->getModulePageURL('mod_sectrip'); // 基底位置
 
$secsaltfile='./secsalt.php';
if(!file_exists($secsaltfile)) { // 如沒有 <pmc目錄>/secsalt.php 則自動生成
$fp=fopen($secsaltfile,'wb');
fputs($fp,'<?php $this->secure_salt = \''.md5(uniqid(rand(), true)).'\';?>');
fclose($fp);
}
include_once($secsaltfile); // 讀入sceure trip salt
}
 
function getModuleName(){
return 'mod_sectrip : Secure Tripcode';
}
 
function getModuleVersionInfo(){
return 'v071223';
}
 
function autoHookRegistBegin(&$name, &$email, &$sub, &$com, $upfileInfo, $accessInfo){
$name=preg_replace('/«(.*)»/','($1)',$name); //防止偽冒
if(preg_match('/\!sectrip\s*#(.*)/i',$name,$m)) { // name!sectrip#securetrip
$this->secureTrip=$m[1];
$name=str_replace($m[0],'',$name); // 跳過普通Trip處理
}
}
 
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status){
if($this->secureTrip) { // 如有sectrip
$name .= "<span class='nor'>«".substr(base64_encode(pack("H*",md5($this->secure_salt.$this->secureTrip))),2,16)."»</span>";
}
}
 
function autoHookPostInfo(&$postinfo){
global $language;
$postinfo .= "<li>可使用 <a href='".$this->myPage."' rel='_blank'>Secure Tripcode</a></li>\n";
}
 
function ModulePage(){
$dat='';
head($dat);
$dat.=<<<EOH
<p>Secure Tripcode提供了一個更高安全性的身份認證方案。</p>
<p>Sceure Tripcode使用了伺服器端salt(伺服器自動生成或由管理員自行指定)以及不限制長度的密碼,將有效減少Tripcode的碰撞機率。</p>
<dl><dt>使用方法:</dt><dd>
只要在Tripcode前加上"!sectrip"(不含引號)即可。<br/>
例如: Name#mypass → Name!sectrip#mypass<br/>
顯示將有改變: <strong>Name</strong>◆39DOV4DpKY → <strong>Name</strong>«ifS1AJ05UCt/Onmt»
</dd></dl>
<hr/>
EOH;
foot($dat);
echo $dat;
}
 
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_adminenhance/mod_adminenhance.php
@@ -0,0 +1,266 @@
<?php
class mod_adminenhance{
var $mypage;
var $ipfile, $imgfile;
 
function mod_adminenhance(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__);
$this->mypage = $PMS->getModulePageURL(__CLASS__);
$this->ipfile = '.ht_blacklist'; $this->imgfile = '.ht_md5list';
}
 
function getModuleName(){
return 'mod_adminenhance : 管理工具增強組合包';
}
 
function getModuleVersionInfo(){
return '5th.Release (v100318)';
}
 
/* 從資料檔抓出資料 */
function _parseBlackListFile($fname, $only1st=false){
if(!is_file($fname)) return array();
$l = file($fname);
$r = array(); $autodelno = array();
$tmp = '';
$now = time();
for($i = 0, $len = count($l); $i < $len; $i++){
$tmp = explode("\t", rtrim($l[$i]));
if(isset($tmp[3]) && $tmp[3] != '0'){ // 封鎖時段已過
if($tmp[2] + intval($tmp[3]) * 86400 < $now){
$autodelno[] = $i;
continue;
}
}
$r[] = $only1st ? $tmp[0] : $tmp;
}
if(count($autodelno)) $this->_arrangeRecord($this->ipfile, $autodelno, ''); // 進行清除動作
return $r;
}
 
/* 重新整理記錄檔內容 (同步進行刪除及新增動作) */
function _arrangeRecord($fname, $arrDel, $newline){
$line = is_file($fname) ? file($fname) : array();
if(is_array($arrDel)) foreach($arrDel as $delid) unset($line[$delid]); // 刪除
$line = implode('', $line).$newline;
$fp = fopen($fname, 'w');
fwrite($fp, $line);
fclose($fp);
}
 
/* 在前端管理顯示 Hostname */
function _showHostString(&$arrLabels, $post, $isReply){
$arrLabels['{$NOW}'] .= " <u>{$post['host']}</u>";
}
 
/* 封鎖黑名單管理頁面插入CSS & JS */
function _hookHeadCSS(&$style, $isReply){
$style .= '<style type="text/css">
.dos_list_short {
height: 150px;
width: 800px;
overflow: auto;
background: #e9f5ff;
border: 1px solid #666;
}
</style>
<script type="text/javascript">
// <![CDATA[
function add(form){
var op = form.operate.value, ndata = form.newdata.value, nperiod = form.newperiod.value, ndesc = form.newdesc.value;
$.post("'.str_replace('&amp;', '&', $this->mypage).'", {operate: op, newdata: ndata, newperiod: nperiod, newdesc: ndesc, ajax: true}, function(d){
var l, lastno = (l = $("input:checkbox:last", form).get(0)) ? parseInt(l.value) + 1 : 0;
$("table", form).append(d.replace("#NO#", lastno));
form.newdata.value = form.newdesc.value = "";
});
return false;
}
// ]]>
</script>
';
}
 
function autoHookRegistBegin(){
global $BANPATTERN, $BAD_FILEMD5;
// 載入封鎖黑名單定義檔
if(is_file($this->ipfile)) $BANPATTERN = array_merge($BANPATTERN, array_map('rtrim', $this->_parseBlackListFile($this->ipfile, true)));
if(is_file($this->imgfile)) $BAD_FILEMD5 = array_merge($BAD_FILEMD5, array_map('rtrim', $this->_parseBlackListFile($this->imgfile, true)));
}
 
function autoHookAdminFunction($action, &$param, $funcLabel, &$message){
global $PIO, $PMS;
if($action=='add'){
// Manual hook: showing hostname of users
$PMS->hookModuleMethod('ThreadPost', array(&$this, '_showHostString'));
$PMS->hookModuleMethod('ThreadReply', array(&$this, '_showHostString'));
 
$param[] = array('mod_adminenhance_thstop', 'AE: 停止/恢復討論串');
$param[] = array('mod_adminenhance_banip', 'AE: IP 加到黑名單 (鎖 Class C)');
$param[] = array('mod_adminenhance_banimg', 'AE: 圖檔 MD5 加到黑名單');
return;
}
 
switch($funcLabel){
case 'mod_adminenhance_thstop':
$infectThreads = array();
foreach($PIO->fetchPosts($param) as $th){
if($th['resto']) continue; // 是回應
$infectThreads[] = $th['no'];
$flgh = $PIO->getPostStatus($th['status']);
$flgh->toggle('TS');
$PIO->setPostStatus($th['no'], $flgh->toString());
}
$PIO->dbCommit();
$message .= '停止/恢復討論串 (No.'.implode(', ', $infectThreads).') 完成<br />';
break;
case 'mod_adminenhance_banip':
$fp = fopen($this->ipfile, 'a');
foreach($PIO->fetchPosts($param) as $th){
if(($IPaddr = gethostbyname($th['host'])) != $th['host']) $IPaddr .= '/24';
fwrite($fp, $IPaddr."\t\t".time()."\t0\n");
}
fclose($fp);
$message .= 'IP 黑名單更新完成<br />';
break;
case 'mod_adminenhance_banimg':
$fp = fopen($this->imgfile, 'a');
foreach($PIO->fetchPosts($param) as $th){
if($th['md5chksum']) fwrite($fp, $th['md5chksum']."\n");
}
fclose($fp);
$message .= '圖檔黑名單更新完成<br />';
break;
default:
}
}
 
function autoHookLinksAboveBar(&$link, $pageId, $addinfo=false){
if($pageId == 'admin' && $addinfo == true)
$link .= '[<a href="'.$this->mypage.'">封鎖黑名單管理</a>]';
}
 
function ModulePage(){
global $PMS;
if(!adminAuthenticate('check')) die('[Error] Access Denied.');
 
// 進行新增、刪除等動作
if(isset($_POST['operate'])){
$op = $_POST['operate'];
// 新增資料
$ndata = isset($_POST['newdata']) ? (get_magic_quotes_gpc() ? stripslashes($_POST['newdata']) : $_POST['newdata']) : ''; // 資料內容
$nperiod = isset($_POST['newperiod']) ? intval($_POST['newperiod']) : 0; // 封鎖天數
$ndesc = isset($_POST['newdesc']) ? CleanStr($_POST['newdesc']) : ''; // 註解
// 刪除資料
$del = isset($_POST['del']) ? $_POST['del'] : null;
$newline = '';
$ismodified = ($ndata != '' || $del != null); // 是否需要修改檔案內容
if($ismodified){
switch($op){
case 'ip':
$file = $this->ipfile;
if($ndata != '') $newline = $ndata."\t".$ndesc."\t".time()."\t".$nperiod."\n";
break;
case 'img':
$file = $this->imgfile;
if($ndata != '') $newline = $ndata."\t".$ndesc."\n";
break;
}
$this->_arrangeRecord($file, $del, $newline); // 同步進行刪除及更新
}
if(isset($_POST['ajax'])){ // AJAX 要求在此即停止,一般要求則繼續印出頁面
$extend = ($op=='ip') ? '<td>'.date('Y/m/d H:m:s', time())." ($nperiod)</td>" : ''; // IP黑名單資訊比圖檔多
echo '<tr><td>'.htmlspecialchars($ndata).'</td><td>'.$ndesc.'</td>'.$extend.'<td><input type="checkbox" name="del[]" value="#NO#" /></td></tr>';
return;
}
}
 
$dat = '';
$PMS->hookModuleMethod('Head', array(&$this, '_hookHeadCSS'));
head($dat);
$dat .= '<div class="bar_admin">封鎖黑名單管理</div>
<div id="content">
<form action="'.$this->mypage.'" method="post">
<div id="ipconfig"><input type="hidden" name="operate" value="ip" />
IP 黑名單<br />
Pattern: <input type="text" name="newdata" size="30" />
Period: <input type="text" name="newperiod" size="5" value="0" />Day(s)
Desc: <input type="text" name="newdesc" size="30" />
<input type="submit" value="新增" onclick="return add(this.form);" /><br />
<div class="dos_list_short">
<table border="0" width="100%">
<tr><td>Pattern</td><td>Description</td><td>Add Date (Period)</td><td>Delete</td></tr>
';
foreach($this->_parseBlackListFile($this->ipfile) as $i => $l){
$dat .= '<tr><td>'.htmlspecialchars($l[0]).'</td><td>'.(isset($l[1]) ? $l[1] : '').'</td>'.
'<td>'.(isset($l[2]) ? date('Y/m/d H:m:s', $l[2]) : '-').(isset($l[3]) ? ' ('.$l[3].')' : ' (0)').'</td>'.
'<td><input type="checkbox" name="del[]" value="'.$i.'" /></td></tr>'."\n";
}
$dat .= '</table>
</div>
<input type="submit" value="刪除" />
</div>
</form>
 
<form action="'.$this->mypage.'" method="post">
<div id="imgconfig"><input type="hidden" name="operate" value="img" />
圖檔 MD5 黑名單<br />
MD5: <input type="text" name="newdata" size="30" />
Desc: <input type="text" name="newdesc" size="30" />
<input type="hidden" name="newperiod" value="0" />
<input type="submit" value="新增" onclick="return add(this.form);" /><br />
<div class="dos_list_short">
<table border="0" width="100%">
<tr><td>MD5</td><td>Description</td><td>Delete</td></tr>
';
foreach($this->_parseBlackListFile($this->imgfile) as $i => $l){
$dat .= '<tr><td>'.htmlspecialchars($l[0]).'</td><td>'.(isset($l[1]) ? $l[1] : '').'</td><td><input type="checkbox" name="del[]" value="'.$i.'" /></td></tr>'."\n";
}
$dat .= '</table>
</div>
<input type="submit" value="刪除" />
</div>
</form>
<hr />
<div id="help"><pre>
說明
 
Pattern:
 
可封鎖特定IP/Hostname發文。以使用者的IP位置或Host名稱進行判斷,所以兩種形式都可以使用。
例如 127.0.0.1 (IP) 和 localhost (Host) 代表的都是相同的電腦。
接受下列格式
 
- 完全相符
即是完全一模一樣的情況下才封鎖。
範例:
127.0.0.1 (127.0.0.1 O;127.0.0.2 X)
localhost (localhost O;local X)
 
- 萬用字元
可接受 * , ? 來代替一段未知的字元 (如同大家熟知的使用方式),這樣一來可匹配的情況將增加。
範例:
192.168.0.* (192.168.0.3 O;192.168.1.3 X)
local* (localhost O;remotehost X)
 
- 正規表達式
使用Regular Expression來進行匹配,可作出更多樣、更適合的條件。注意使用時需要使用 / 斜線將表達式括住。
範例:
/127\.0\.0\.[0-9]{2}/ (127.0.0.28 O;127.0.0.1 X)
/^.+\.proxy\.com$/ (gate1.proxy.com O;proxy2.com.tw X)
 
- CIDR Notation
使用 Classless Addressing 這種更有彈性的方式切割子網路,其表示法稱作 CIDR,以一段IP位置加上Mask來劃分子網路 (注意此表示法僅能使用 IP)。
範例:
192.168.0.1/20 (192.168.7.243 O;192.168.18.144 X)
 
Period:
 
設定封鎖期限,在過期時可以自動刪除解鎖,以天為單位。如果想永久封鎖 (系統不自動回收,需手動解鎖) 則將此值設為 0 (0 表示無期限)。</pre>
</div>
</div>';
foot($dat);
echo $dat;
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_showhide/mod_showhide.php
@@ -0,0 +1,16 @@
<?php
class mod_showhide{
function getModuleName(){
return 'mod_showhide : 自由隱藏顯示討論串';
}
 
function getModuleVersionInfo(){
return '4th.Release.3 (v080519)';
}
 
function autoHookHead(&$txt, $isReply){
$txt .= '<script type="text/javascript" src="module/jquery-latest.pack.js"></script>
<script type="text/javascript" src="module/mod_showhide.pack.js"></script>'."\n";
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_showhide/mod_showhide.pack.js
@@ -0,0 +1 @@
Array.prototype.indexOf||(Array.prototype.indexOf=function(a){var b,c=this.length;for(b=0;b<c;b++)if(this[b]===a)return b;return-1});var TmodShowhide={hideList:[],isChange:!1,init:function(){var a=getCookie("hideList");location.href.indexOf(".php?res=")===-1&&(jQuery("div.threadpost").each(function(){if(!!this.id){var a='<div class="threadStructure" id="t'+this.id+'" />';jQuery(this).wrap(a).parent().append(jQuery(this.parentNode).nextUntil("hr"))}}),a!==""&&(TmodShowhide.hideList=a.split(","),jQuery("div.threadStructure").each(function(){TmodShowhide.hideList.indexOf(this.id)!==-1&&jQuery(this).hide()})),jQuery("div.threadStructure").each(function(){jQuery(this).before('[<a href="javascript:void(0);" onclick="TmodShowhide.switchThread(\''+this.id+'\');" title="Hide/Show this thread">+ / -</a>]<br />')}))},switchThread:function(a){var b=TmodShowhide.hideList.indexOf(a);TmodShowhide.isChange=!0,b!==-1?(TmodShowhide.hideList.splice(b,1),jQuery("div.threadStructure#"+a).show("slow")):(TmodShowhide.hideList.push(a),jQuery("div.threadStructure#"+a).hide("slow"))},unload:function(){TmodShowhide.isChange&&setCookie("hideList",TmodShowhide.hideList.join(","))}};jQuery(TmodShowhide.init),jQuery(window).unload(TmodShowhide.unload)
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_showhide/mod_showhide.js
@@ -0,0 +1,69 @@
if (!Array.prototype.indexOf) { // Inplemented in JavaScript 1.6
Array.prototype.indexOf = function (item) {
var i, len = this.length;
for (i = 0; i < len; i++) {
if (this[i] === item) {
return i;
}
}
return -1;
};
}
 
var TmodShowhide = {
hideList: [], // 隱藏討論串列表
isChange: false, // 是否有更動需回存
/* 載入討論串隱藏列表並實行隱藏 */
init: function () {
var t = getCookie('hideList');
// 回應模式不動作
if (location.href.indexOf('.php?res=') !== -1) {
return;
}
jQuery('div.threadpost').each(function () {
if (!this.id) {
return;
}
var outerDiv = '<div class="threadStructure" id="t' + this.id + '" />';
jQuery(this).wrap(outerDiv).parent().append(jQuery(this.parentNode).nextUntil('hr'));
});
if (t !== '') {
//alert('getCookie');
TmodShowhide.hideList = t.split(',');
jQuery('div.threadStructure').each(function () {
//alert('loop:'+this.id);
if (TmodShowhide.hideList.indexOf(this.id) !== -1) {
jQuery(this).hide();
} // 隱藏討論串
});
}
// 加上控制按鈕
jQuery('div.threadStructure').each(function () {
jQuery(this).before('[<a href="javascript:void(0);" onclick="TmodShowhide.switchThread(\'' + this.id + '\');" title="Hide/Show this thread">+ / -</a>]<br />');
});
//alert('OK:'+TmodShowhide.hideList);
},
/* 切換文章顯示與否 */
switchThread: function (no) {
var t = TmodShowhide.hideList.indexOf(no);
TmodShowhide.isChange = true;
if (t !== -1) {
TmodShowhide.hideList.splice(t, 1);
jQuery('div.threadStructure#' + no).show('slow');
} else {
TmodShowhide.hideList.push(no);
jQuery('div.threadStructure#' + no).hide('slow');
}
//alert('s:'+TmodShowhide.hideList);
},
/* 回存 */
unload: function () {
if (TmodShowhide.isChange) {
setCookie('hideList', TmodShowhide.hideList.join(','));
}
//alert('bye');
}
};
 
jQuery(TmodShowhide.init); // 註冊載入事件
jQuery(window).unload(TmodShowhide.unload); // 註冊結束事件
New file
/release/Modules-PIO-v6/mod_showhide/howto.txt
@@ -0,0 +1,16 @@
License:
 
jQuery is licensed under MIT License. Copyright (c) 2007 John Resig, http://jquery.com/
mod_showhide is not a part of Pixmicat! package. So it's not licensed under the Clarified Artistic License. It's in the public domain.
 
中文安裝指引:
 
1. 下載 jquery-latest.pack.js (jQuery: http://jquery.com/) 儲存
2. 將 mod_showhide.php, mod_showhide.pack.js, jquery-latest.pack.js 放到 module/ 目錄
3. 修改 config.php,在模組載入區塊下加一行 $ModuleList[] = 'mod_showhide';
 
English Instruction:
 
1. Download the "jquery-latest.pack.js" from the jQuery website (http://jquery.com/).
2. Put the following files into the module/ directory: "mod_showhide.php", "mod_showhide.pack.js" and "jquery-latest.pack.js."
3. Use your favorite editor to open the "config.php" and add one line ($ModuleList[] = 'mod_showhide';) into the "Modules to be loaded" block.
New file
/release/Modules-PIO-v6/mod_catalog/mod_catalog.php
@@ -0,0 +1,105 @@
<?php
/*
mod_catalog : 以相簿模式列出圖檔方便瀏覽及抓取
By: scribe (Adopted from Pixmicat!-Festival)
*/
 
class mod_catalog{
var $CATALOG_NUMBER;
 
function mod_catalog(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', 'mod_catalog'); // 向系統登記模組專屬獨立頁面
 
$this->CATALOG_NUMBER = 20; // 相簿模式一頁最多顯示個數 (視文章是否有貼圖而有實際變動)
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_catalog : 以相簿模式列出圖檔';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '4th.Release.2 (v071109)';
}
 
/* 自動掛載:頂部連結列 */
function autoHookToplink(&$linkbar, $isReply){
global $PMS;
$linkbar .= '[<a href="'.$PMS->getModulePageURL('mod_catalog').'">相簿模式</a>]'."\n";
}
 
/* 掛載樣式表 */
function hookHeadCSS(&$style, $isReply){
$style .= '<style type="text/css">
div.list { float: left; margin: 5px; width: '.MAX_RW.'px; height: '.MAX_RH.'px; } /* (相簿模式) div 框格設定 */
</style>
';
}
 
/* 模組獨立頁面 */
function ModulePage(){
global $PMS, $PIO, $FileIO;
 
$thisPage = $PMS->getModulePageURL('mod_catalog'); // 基底位置
$dat = ''; // HTML Buffer
$listMax = $PIO->postCount(); // 文章總筆數
$pageMax = ceil($listMax / $this->CATALOG_NUMBER) - 1; // 分頁最大編號
$page = isset($_GET['page']) ? intval($_GET['page']) : 0; // 目前所在分頁頁數
if($page < 0 || $page > $pageMax) exit('Page out of range.'); // $page 超過範圍
$plist = $PIO->fetchPostList(0, $this->CATALOG_NUMBER * $page, $this->CATALOG_NUMBER); // 取得定位正確的 N 筆資料號碼
$post = $PIO->fetchPosts($plist); // 取出資料
$post_count = count($post);
 
$PMS->hookModuleMethod('Head', array(&$this, 'hookHeadCSS'));
head($dat);
$dat .= '<div id="contents">
[<a href="'.PHP_SELF2.'?'.time().'">回到版面</a>]
<div class="bar_reply">相簿模式</div>
';
// 逐步取資料
for($i = 0; $i < $post_count; $i++){
list($imgw, $imgh, $tw, $th, $tim, $ext) = array($post[$i]['imgw'], $post[$i]['imgh'],$post[$i]['tw'], $post[$i]['th'], $post[$i]['tim'], $post[$i]['ext']);
if($FileIO->imageExists($tim.$ext)){
$dat .= '<div class="list"><a href="'.$FileIO->getImageURL($tim.$ext).'" rel="_blank"><img src="'.$FileIO->getImageURL($tim.'s.jpg').'" style="'.$this->OptimizeImageWH($tw, $th).'" title="'.$imgw.'x'.$imgh.'" alt="'.$tim.$ext.'" /></a></div>'."\n";
}
}
 
$dat .= '</div>
 
<hr />
 
<div id="page_switch">
<table border="1" style="float: left;"><tr>
';
if($page) $dat .= '<td><a href="'.$thisPage.'&amp;page='.($page - 1).'">上一頁</a></td>';
else $dat .= '<td style="white-space: nowrap;">第一頁</td>';
$dat .= '<td>';
for($i = 0; $i <= $pageMax; $i++){
if($i==$page) $dat .= '[<b>'.$i.'</b>] ';
else $dat .= '[<a href="'.$thisPage.'&amp;page='.$i.'">'.$i.'</a>] ';
}
$dat .= '</td>';
if($page < $pageMax) $dat .= '<td><a href="'.$thisPage.'&amp;page='.($page + 1).'">下一頁</a></td>';
else $dat .= '<td style="white-space: nowrap;">最後一頁</td>';
$dat .= '
</tr></table>
</div>
 
';
foot($dat);
echo $dat;
}
 
/* 最佳化圖顯示尺寸 */
function OptimizeImageWH($w, $h){
if($w > MAX_RW || $h > MAX_RH){
$W2 = MAX_RW / $w; $H2 = MAX_RH / $h;
$tkey = ($W2 < $H2) ? $W2 : $H2;
$w = ceil($w * $tkey); $h = ceil($h * $tkey);
}
return 'width: '.$w.'px; height: '.$h.'px;';
}
}
?>
New file
/release/Modules-PIO-v6/mod_shoutbox/mod_shoutbox.php
@@ -0,0 +1,292 @@
<?php
/*
mod_shoutbox.php
*/
class mod_shoutbox{
var $MESG_LOG,$MESG_CACHE,$JSON_CACHE,$LOG_MAX,$MES_PER_PAGE,$MESSAGE_MAX,$EMOTIONS;
var $myPage,$lastno,$logcount;
function mod_shoutbox(){
global $PMS, $PIO, $FileIO;
 
$PMS->hookModuleMethod('ModulePage', 'mod_shoutbox'); // 向系統登記模組專屬獨立頁面
$this->myPage = $PMS->getModulePageURL('mod_shoutbox'); // 基底位置
 
$this->MESG_LOG = './shoutbox.log'; // shoutbox紀錄檔位置
$this->MESG_CACHE = './shoutbox.cc'; // shoutbox快取檔位置
$this->JSON_CACHE = './shoutbox.json'; // shoutbox JSON快取檔位置
$this->LOG_MAX = 500; // shoutbox 最大紀錄行數
$this->MESSAGE_MAX = 50; // shoutbox 單一訊息最大長度
$this->MES_PER_PAGE = 5; // shoutbox 一頁顯示筆數
 
$this->EMOTIONS = array("|∀゚ )","(´゚Д゚`)","(;´Д`)ハァァ~","|д゚ )ノ","(`・ω・)","|-` ).。o0","(=゚ω゚)="); // 表情
}
 
function getModuleName(){
return 'mod_shoutbox : 即時留言';
}
 
function getModuleVersionInfo(){
return 'v071119';
}
 
function autoHookHead(&$dat,$isRes){
$mypage='http://'.$_SERVER['HTTP_HOST'].preg_replace('/'.basename($_SERVER['PHP_SELF']).'$/', '', $_SERVER['PHP_SELF']).str_replace('&amp;','&',$this->myPage);
$ifheight=($this->MES_PER_PAGE+11)."em";
$dat .= <<< _EOF_
<style type="text/css"><!--/*--><![CDATA[/*><!--*/
#shoutboxform form {display:inline;}
#shoutbox.show {display:block;position:absolute;top:3em;left:0; border: 2px #F0E0D6 solid; width: 65%;height: $ifheight; overflow:auto; margin:0; padding:0;}
#shoutbox.hide {display:none;}
#shoutbox_main {margin:0 0 0 0.4em;padding:0}
.shoutInput {padding:0;margin:0;border:1px solid #888;}
.shoutBtn {padding:0;margin:0;background-color:#ccc;border:1px solid #888;}
.shout {font-size:9pt}
.shout .e {font-weight:bold}
.shout .d {color:gray}
/*]]>*/--></style>
<script type="text/javascript"><!--//--><![CDATA[//><!--
function gID(s) { return document.getElementById(s); }
/* 建立XMLHttpRequest物件 */
function JSONXMLHttpReq(){
var objxml = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try{
objxml = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
objxml = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e2){ objxml = false; }
}
@end @*/
if(!objxml && typeof XMLHttpRequest!='undefined') {
objxml = new XMLHttpRequest();
if(objxml.overrideMimeType) objxml.overrideMimeType('text/plain');
}
return objxml;
}
var xhttpjson=JSONXMLHttpReq();
 
function getLatestMessage(){
if(xhttpjson){
xhttpjson.open('GET','$mypage'+'&action=latest', true);
xhttpjson.onreadystatechange = ParseLatestMessage;
xhttpjson.send(null);
}
}
function ParseLatestMessage(){
if(xhttpjson.readyState==4){ // 讀取完成
var returnObj = eval('('+xhttpjson.responseText+')');
if(returnObj.message) {
gID("latestshout").innerHTML='<span class="e">'+returnObj.emotion+'</span>&gt; <span class="m">'+returnObj.message+'</span> <span class="d">('+returnObj.date+')</span>';
}
}
}
 
function ToggleShoutBox() {
if(gID('shoutbox').className=='hide') {
gID('shoutbox').src='$mypage';
gID('shoutbox').className='show';
}else{
gID('shoutbox').src='about:blank';
gID('shoutbox').className='hide';
}
}
function realsubmit() {
if(gID('shout_mesg').value) {
gID('real_shout_mesg').value=gID('shout_mesg').value;
gID('real_shout_emo').value=gID('shout_emo').value;
gID('realshoutboxform').submit();
gID('shout_mesg').value='';
setTimeout("getLatestMessage()",1000);
}
return false;
}
//--><!]]></script>
_EOF_;
}
 
/* 自動掛載:頂部連結列 */
function autoHookToplink(&$linkbar, $isReply){
$linkbar = '<div class="shout" style="float:left;" id="latestshout"></div>
<script type="text/javascript"><!--//--><![CDATA[//><!--
getLatestMessage();
setInterval("getLatestMessage()",30000);
//--><!]]></script>
 
<iframe id="shoutbox" class="hide" name="shoutbox" frameborder="0"></iframe>
<form action="'.$this->myPage.'" method="POST" id="realshoutboxform" style="display:none" target="shoutbox"><input type="hidden" name="action" value="shout"/><input type="hidden" name="emotion" id="real_shout_emo" value=""/><input type="hidden" name="message" id="real_shout_mesg" value=""/></form>
<span id="shoutboxform">[<a href="javascript:ToggleShoutBox();">Shoutbox</a> <form action="'.$this->myPage.'" method="POST" id="shoutboxform" target="shoutbox" onsubmit="return realsubmit();"><input type="hidden" name="action" value="shout"/><select name="emotion" id="shout_emo" class="shoutInput">'.$this->_getEmotionHTML().'</select>&gt;<input type="text" name="message" value="" id="shout_mesg" size="18" class="shoutInput"/><input type="submit" name="submit" value="喊" class="shoutBtn"/></form>]</span>'."\n".$linkbar;
}
 
function _getEmotionHTML() {
$html='';$ecnt=count($this->EMOTIONS);
for($i=0;$i<$ecnt;$i++) {
$html.="<option value='$i'".(!$i?' selected="selected"':'').'>'.$this->EMOTIONS[$i]."</option>\n";
}
return $html;
}
 
function _latestMessage() {
if(file_exists($this->JSON_CACHE)) readfile($this->JSON_CACHE);
else {
if($logs=@file($this->MESG_LOG)) { // mesgno,date,emo,mesg,ip = each $logs, order desc
if(isset($logs[0])) {
list(,$date,$emo,$mes,)=explode(',',$logs[0]);
echo $this->_rebuildJSON($date,$emo,$mes);
}
} else return "{}"; // return null object
}
}
 
function _loadCache() {
if(!$this->lastno) {
if($logs=@file($this->MESG_CACHE)) { // 有快取
$this->lastno=trim($logs[0]);
$this->logcount=trim($logs[1]);
return true;
} else { // 無快取
return $this->_rebuildCache();
}
} else return true;
}
 
function _rebuildJSON($date,$emo,$mes) {
$json='{"emotion":"'.addslashes($emo).'","message":"'.addslashes($mes).'","date":"'.gmdate("Y-m-d H:i:s",$date+TIME_ZONE*3600).'"}';
$this->_write($this->JSON_CACHE,$json);
return $json;
}
 
function _rebuildCache() {
if($logs=@file($this->MESG_LOG)) { // mesgno,date,emo,mesg,ip = each $logs, order desc
if(!$this->lastno) if(isset($logs[0])) $this->lastno = intval(substr($logs[0],strpos($logs[0],',')));
$this->logcount = count($logs);
$this->_writeCache();
return true;
} else {
$this->_writeCache();
return false;
}
}
 
function _writeCache() {
$this->_write($this->MESG_CACHE,intval($this->lastno)."\n".intval($this->logcount)."\n");
}
 
function _write($file,$data) {
$rp = fopen($file, "w");
flock($rp, LOCK_EX); // 鎖定檔案
@fputs($rp,$data);
flock($rp, LOCK_UN); // 解鎖
fclose($rp);
chmod($file,0666);
}
 
function _post() {
$emo=isset($_POST['emotion'])?intval($_POST['emotion']):0;
$mesg=isset($_POST['message'])?$_POST['message']:'';
$mesg=CleanStr($mesg);
if(!$mesg) error("請填入內文");
if(preg_match("/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/",$mesg)) error('eMail禁止');
if(strlen($mesg)>$this->MESSAGE_MAX) error(_T('regist_commenttoolong'));
$mesg = str_replace("\n"," ",$mesg); // 消除換行
$mesg = str_replace(',','&#44;',$mesg); // 轉換","
 
$this->_loadCache();
 
$logs=@file($this->MESG_LOG);
if($logs===false) $logs=array();
if(($this->logcount+1) > $this->LOG_MAX) @array_splice($logs,$this->LOG_MAX-2); // chop by index
 
// 檢查重複
if($logs[0]) {
list(,,,$lmsg,)=explode(',',$logs[0]);
if($lmsg == $mesg) return;
}
$logs=(++$this->lastno).",".($now=time()).",".$this->EMOTIONS[$emo].",$mesg,$_SERVER[REMOTE_ADDR],\n".implode('',$logs);
$this->_write($this->MESG_LOG,$logs);
 
$this->_rebuildJSON($now,$this->EMOTIONS[$emo],$mesg);
$this->_rebuildCache();
}
 
function _showMessages($from,$to) {
global $PTE;
$dat='';$pagebar='';$gotmesg=false;
$dat .= $PTE->ParseBlock('REALSEPARATE',array()).'<div class="shout"><form action="'.$this->myPage.'" method="POST"><input type="hidden" name="action" value="delete" />';
if($logs=@file($this->MESG_LOG)) { // mesgno,date,emo,mesg,ip = each $logs, order desc
$mcnt=count($logs);
for($i=$from;$i<$to;$i++) {
if(!isset($logs[$i])) continue;
$gotmesg=true;
list($mno,$date,$emo,$mesg,)=explode(',',$logs[$i]);
if(!$dat) $dat=$PTE->ParseBlock('REALSEPARATE',array()).'<form action="'.$this->myPage.'" method="POST"><input type="hidden" name="action" value="delete" />';
$dat.="<input type='checkbox' name='$mno' value='delete' /><span class='e'>$emo</span>&gt; <span class='m'>$mesg</span> <span class='d'>(".gmdate("Y-m-d H:i:s",$date+TIME_ZONE*3600).')</span><br/>';
}
 
// 換頁列
$pages=intval(($mcnt-1)/$this->MES_PER_PAGE);
$thispage=$from/$this->MES_PER_PAGE;
$pagebar='<div style="float:left;clear:right;">[ ';
for($i=0;$i<=$pages;$i++) {
if($i==$thispage) $pagebar.="<strong>$i</strong> ";
else $pagebar.='<a href="'.$this->myPage.'&page='.$i.'">'.$i.'</a> ';
}
$pagebar.=']</div>';
}
if(!$gotmesg) $dat.="沒有信息。";
$dat .= $PTE->ParseBlock('REALSEPARATE',array()).$pagebar.'<div align="right">PASS:<input type="password" name="pwd" value="" size="8" class="shoutInput"/><input type="submit" name="delete" value="'._T('del_btn').'" class="shoutBtn"/></div></form>';
return $dat;
}
 
function _deleteMessage($no,$pass) {
if($pass!=ADMIN_PASS) return;
$found=false;
if($logs=@file($this->MESG_LOG)) { // mesgno,date,emo,mesg,ip = each $logs, order desc
$countlogs=count($logs);
foreach($no as $n) {
for($i=0;$i<$countlogs;$i++) {
list($mno,)=explode(',',$logs[$i]);
if($mno==$n) {
$logs[$i]=''; // deleted
$found=true;
break;
}
}
}
if($found) {
$newlogs=implode('',$logs);
$this->_write($this->MESG_LOG,$newlogs);
$newloglines=explode("\n",$newlogs);
if(count($newloglines)) {
list(,$now,$emo,$mesg,) = explode(',',$newloglines[0]);
$this->_rebuildJSON($now,$emo,$mesg);
}
$this->_rebuildCache();
}
}
}
 
function ModulePage(){
global $PMS, $PTE;
$action=isset($_REQUEST['action'])?$_REQUEST['action']:'';
$page=isset($_REQUEST['page'])?intval($_REQUEST['page']):0;
if($action == 'latest') {$this->_latestMessage(); return;}
if($action == 'shout') $this->_post();
if($action == 'delete' && isset($_POST['pwd'])) {
$delno=array();
while($item = each($_POST)) if($item[1]=='delete') array_push($delno, $item[0]);
if(count($delno)) $this->_deleteMessage($delno,$_POST['pwd']);
}
$pte_vals = array('{$TITLE}'=>TITLE,'{$RESTO}'=>'');
$dat = $PTE->ParseBlock('HEADER',$pte_vals);
$this->autoHookHead($dat,0); // add my headers
$dat .= "</head><body id='shoutbox_main'>";
$dat.='Shoutbox<br/><form action="'.$this->myPage.'" method="POST"><input type="hidden" name="action" value="shout"/><select name="emotion" id="shout_emo" class="shoutInput">'.$this->_getEmotionHTML().'</select>&gt;<input type="text" name="message" value="" id="shout_mesg" size="18" class="shoutInput"/><input type="submit" name="submit" value="喊" class="shoutBtn"/></form>';
$dat.=$this->_showMessages($page * $this->MES_PER_PAGE,($page+1) * $this->MES_PER_PAGE);
echo $dat."</body></html>";
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_paint/mod_paint.php
@@ -0,0 +1,419 @@
<?php
/* mod_paint : PaintBBS & Shi-Painter Bridge
* $Id$
* $Date$
*/
 
// PHP4 file_put_contents Define
// Source: http://www.php.net/manual/en/function.file-put-contents.php#68329
if(!function_exists('file_put_contents') && !defined('FILE_APPEND')){
define('FILE_APPEND', 1);
function file_put_contents($n, $d, $flag = false){
$mode = ($flag == FILE_APPEND || strtoupper($flag) == 'FILE_APPEND') ? 'a' : 'w';
$f = @fopen($n, $mode);
if($f === false) return false;
if(is_array($d)) $d = implode($d);
$bytes_written = fwrite($f, $d);
fclose($f);
return $bytes_written;
}
}
 
class mod_paint{
var $THISPAGE, $TMPFolder, $PMAX_W, $PMAX_H, $SECURITY, $PAINT_RESTRICT, $PaintComponent, $TIME_UNIT;
function mod_paint(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__);
$this->THISPAGE = $PMS->getModulePageURL(__CLASS__);
// 可設定項目
$this->TMPFolder = './tmp/'; // 圖檔暫存目錄
$this->PMAX_W = 500; $this->PMAX_H = 500; // 繪圖最大長寬尺寸
$this->SECURITY = array('CLICK'=> 1, 'TIMER'=> 1, 'URL' => PHP_SELF2); // 安全設定
$this->PAINT_RESTRICT = array('POST'=>true, 'REPLY'=>true); // 繪圖模式是否可使用 (POST:發文, REPLY:回應)
$this->PaintComponent = array( // 各組件所在位置
'Base'=>'./paint/', // 其他資源檔基底目錄
'PaintBBS'=>'./paint/PaintBBS.jar',
'ShiPainter'=>'./paint/spainter_all.jar',
'PCHViewer'=>'./paint/PCHViewer.jar'
);
$this->TIME_UNIT = array('TIME'=>'作畫時間:', 'D'=> '日', 'H'=>'時', 'M'=>'分', 'S'=>'秒'); // 時間單位
}
 
function getModuleName(){
return 'mod_paint : PaintBBS &amp; しぃペインター(Pro) 支援模組';
}
 
function getModuleVersionInfo(){
return '4th.Release.3 (v090310)';
}
 
/* Hook to ThreadFront */
function autoHookThreadFront(&$txt, $isReply){
$txt .= '<form action="'.$this->THISPAGE.'&amp;action=paint" method="post">
<div style="text-align: center;">
程式<select name="Papplet"><option value="0">PaintBBS</option><option value="1">しぃペインター</option><option value="2">しぃペインターPro</option></select>
寬<input type="text" name="PimgW" value="200" size="3" />x高<input type="text" name="PimgH" value="200" size="3" />
<input type="submit" value="作畫" />
<input type="checkbox" value="true" name="Panime" id="Panime" checked="checked" /><label for="Panime">作畫記錄</label>'.($isReply ? '<input type="hidden" name="resto" value="'.$isReply.'" />' : '').'
<br /><a href="'.$this->THISPAGE.'&amp;action=post'.($isReply ? '&amp;resto='.$isReply : '').'">使用先前繪圖</a>
</div>
</form>'."\n";
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
$pchBase = './'.IMG_DIR.$post['tim'];
$pchType = '';
if(file_exists($pchBase.'.pch')){ $pchFile = $post['tim'].'.pch'; }
elseif(file_exists($pchBase.'.spch')){ $pchFile = $post['tim'].'.spch'; $pchType = '&amp;type=spch'; }
else{ return; }
$pchLink = $this->THISPAGE.'&amp;action=viewpch&amp;file='.$post['tim'].$post['ext'].$pchType;
$paintTime = '';
if(preg_match('/_PCH:([0-9]+)_/', $post['status'], $paintTime)){
$paintTime = intval($paintTime[1]);
$ptime = '';
if($paintTime >= 86400){
$D = intval($paintTime/86400);
$ptime .= $D.$this->TIME_UNIT['D'];
$paintTime -= $D * 86400;
}
if($paintTime >= 3600){
$H = intval($paintTime/3600);
$ptime .= $H.$this->TIME_UNIT['H'];
$paintTime -= $H * 3600;
}
if($paintTime >= 60){
$M = intval($paintTime/60);
$ptime .= $M.$this->TIME_UNIT['M'];
$paintTime -= $M * 60;
}
if($paintTime){
$ptime .= $paintTime.$this->TIME_UNIT['S'];
}
$paintTime = ' - '.$this->TIME_UNIT['TIME'].$ptime.' ';
}else{ $paintTime = ''; }
$arrLabels['{$IMG_BAR}'] .= '<small>'.$paintTime.'<a href="'.$pchLink.'">[動畫]</a></small>';
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
/* 將繪圖與文章暗中連結起來 */
function autoHookPostForm(&$form){
if(strpos($_SERVER['REQUEST_URI'], str_replace('&amp;', '&', $this->THISPAGE).'&action=post')!==false){ // 符合插入頁面條件
$userCode = str_replace(array('/','?'), '_', substr(crypt(md5($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'].IDSEED),'id'), -12)); // 使用者識別碼 (IP + UserAgent)
$imgItem = '<select name="paintImg">';
foreach(glob($this->TMPFolder.'*_'.$userCode.'.*') as $item){
if(preg_match('/\.(jpg|png)$/', $item)) $imgItem .= '<option>'.basename($item).'</option>';
}
$imgItem .= '</select>';
$form .= '<tr><td class="Form_bg"><b>附加繪圖</b></td><td>'.$imgItem.'<input type="hidden" name="PaintSend" value="true" /></td></tr>';
}
}
 
/* 處理繪圖跟文章的連結 */
function autoHookRegistBegin(&$name, &$email, &$sub, &$com, $upfileInfo, $accessInfo){
if(!isset($_POST['paintImg'])) return; // 沒選圖檔
if(isset($_POST['PaintSend'])){ // 繪圖模式送來的儲存
$upfileInfo['file'] = $this->TMPFolder.$_POST['paintImg'];
$upfileInfo['name'] = $_POST['paintImg'];
$upfileInfo['status'] = 0;
}
}
 
/* 處理 PCH 檔 (如果有的話) 和暫存清除 */
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status){
if(!isset($_POST['paintImg'])) return; // 沒選圖檔
if(isset($_POST['PaintSend'])){ // 繪圖模式送來的儲存
unlink($this->TMPFolder.$_POST['paintImg']); // 刪除暫存圖檔
$pchOldfile = str_replace(strrchr($_POST['paintImg'], '.'), '', $_POST['paintImg']); // 暫存 PCH 動畫檔案名 (不含副檔名)
$pchNewfile = './'.IMG_DIR.str_replace(strrchr($dest, '.'), '', basename($dest)); // 本機儲存 PCH 動畫檔案路徑 (不含副檔名)
$datFile = $this->TMPFolder.$pchOldfile.'.dat'; // Dat 資訊檔
$PaintSecond = file_get_contents($datFile); $status .= '_PCH:'.$PaintSecond.'_'; // 於狀態增設作畫時間旗標
unlink($datFile);
if(file_exists($this->TMPFolder.$pchOldfile.'.pch')){ $pchOldfile = $this->TMPFolder.$pchOldfile.'.pch'; $pchNewfile .= '.pch'; }
elseif(file_exists($this->TMPFolder.$pchOldfile.'.spch')){ $pchOldfile = $this->TMPFolder.$pchOldfile.'.spch'; $pchNewfile .= '.spch'; }
else{ return; }
copy($pchOldfile, $pchNewfile); unlink($pchOldfile);
}
}
 
/* 中控頁面: 根據 Action 執行指定動作 */
function ModulePage(){
/*
TODO:
- Continue Painting (or Discard this function?)
*/
$Action = isset($_GET['action']) ? $_GET['action'] : '';
switch($Action){
case 'paint':
$this->Action_deleteOldTemp(); // 清除舊暫存 (放於此處可以達成觸發又不會太頻繁)
$this->Action_Paint(); break;
case 'save':
$this->Action_Save(); break;
case 'post':
$this->Action_Post(); break;
case 'viewpch':
$this->Action_ViewPCH(); break;
default:
echo 'Welcome to my world.';
}
}
 
/* 印出繪圖頁面 */
function Action_Paint(){
$nowTime = time();
$resto = isset($_POST['resto']) ? intval($_POST['resto']) : 0; // 回應編號
if($resto != 0){ // 回應
if(!$this->PAINT_RESTRICT['REPLY']) error('Replying with a painting is Not allowed.');
$resto = '&amp;resto='.$resto;
}else{
if(!$this->PAINT_RESTRICT['POST']) error('Posting with a painting is Not allowed.');
$resto = '';
}
$Papplet = isset($_POST['Papplet']) ? $_POST['Papplet'] : '0';
$Panime = isset($_POST['Panime']) ? $_POST['Panime'] : false;
$PimgW = isset($_POST['PimgW']) ? intval($_POST['PimgW']) : 200; if($PimgW < 100){ $PimgW = 100; } if($PimgW > $this->PMAX_W){ $PimgW = $this->PMAX_W; }
$PimgH = isset($_POST['PimgH']) ? intval($_POST['PimgH']) : 200; if($PimgH < 100){ $PimgH = 100; } if($PimgH > $this->PMAX_H){ $PimgH = $this->PMAX_H; }
$AppletW = $PimgW + 150; if($AppletW < 400){ $AppletW = 400; } // Applet Width
$AppletH = $PimgH + 170; if($AppletH < 420){ $AppletH = 420; } // Applet Height
$userCode = str_replace(array('/','?'), '_', substr(crypt(md5($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'].IDSEED),'id'), -12)); // 使用者識別碼 (IP + UserAgent)
$AppletHeader = "user={$userCode},time=".$nowTime; // Applet send_header
switch($Papplet){
case '2': // ShiPainterPro
case '1': // ShiPainter
$ShiSwitch = array(1=>'normal', 2=>'pro');
$PappletJar = $this->PaintComponent['ShiPainter'];
$PappletCode = 'c.ShiPainter.class';
$PappletParams = '<param name="dir_resource" value="'.$this->PaintComponent['Base'].'" />
<param name="tt.zip" value="tt_def.zip" />
<param name="res.zip" value="res.zip" />
<param name="tools" value="'.$ShiSwitch[intval($Papplet)].'" />
<param name="layer_count" value="3" />
<param name="quality" value="1" />';
if($AppletW < 500){ $AppletW = 500; }
if($AppletH < 500 && $Papplet=='2'){ $AppletH = 500; }
break;
default: // PaintBBS
$PappletJar = $this->PaintComponent['PaintBBS'];
$PappletCode = 'pbbs.PaintBBS.class';
$PappletParams = '';
}
 
$dat = '';
head($dat);
$dat .= '
<div id="linkbar">
[<a href="'.PHP_SELF2.'">回到版面</a>]
<div class="bar_reply">繪圖模式</div>
</div>
<div id="container" style="text-align: center">
<applet code="'.$PappletCode.'" archive="'.$PappletJar.'" name="paintbbs" width="'.$AppletW.'" height="'.$AppletH.'" mayscript="mayscript">
'.$PappletParams.'
<param name="image_width" value="'.$PimgW.'" />
<param name="image_height" value="'.$PimgH.'" />
<param name="image_jpeg" value="true" />
<param name="image_size" value="60" />
<param name="compress_level" value="15" />
<param name="undo" value="90" />
<param name="undo_in_mg" value="45" />
<param name="poo" value="false" />
<param name="send_advance" value="true" />
<param name="tool_advance" value="true" />
<param name="thumbnail_width" value="100%" />
<param name="thumbnail_height" value="100%" />
<param name="url_save" value="'.$this->THISPAGE.'&amp;action=save" />
<param name="url_exit" value="'.$this->THISPAGE.'&amp;action=post'.$resto.'" />';
if($Panime) $dat .= '
<param name="thumbnail_type" value="animation" />';
$dat .= '
<param name="send_header" value="'.$AppletHeader.'" />
<param name="security_click" value="'.$this->SECURITY['CLICK'].'" />
<param name="security_timer" value="'.$this->SECURITY['TIMER'].'" />
<param name="security_url" value="'.$this->SECURITY['URL'].'" />
<param name="security_post" value="false" />
 
<param name="image_bkcolor" value="#FFFFFF" />
<param name="color_text" value="#333333" />
<param name="color_bk" value="#FFFFFF" />
<param name="color_bk2" value="#DDDDDD" />
<param name="color_icon" value="#FFFFFF" />
<param name="color_iconselect" value="#999999" />
<param name="color_bar" value="#999999" />
<param name="color_frame" value="#666666" />
<param name="tool_color_button" value="#FFFFFF" />
<param name="tool_color_button2" value="#FFFFFF" />
<param name="tool_color_text" value="#333333" />
<param name="tool_color_bar" value="#FFFFFF" />
<param name="tool_color_frame" value="#666666" />
</applet>
<br />
'.$this->TIME_UNIT['TIME'].'<input type="text" id="count" />
<script type="text/javascript">
// <![CDATA[
stime = new Date();
setInterval(function(){
now = new Date();
s = Math.floor((now.getTime() - stime.getTime())/1000);
disp = "";
if(s >= 86400){
d = Math.floor(s/86400);
disp += d+"'.$this->TIME_UNIT['D'].'";
s -= d*86400;
}
if(s >= 3600){
h = Math.floor(s/3600);
disp += h+"'.$this->TIME_UNIT['H'].'";
s -= h*3600;
}
if(s >= 60){
m = Math.floor(s/60);
disp += m+"'.$this->TIME_UNIT['M'].'";
s -= m*60;
}
document.getElementById("count").value = disp+s+"'.$this->TIME_UNIT['S'].'";
}, 1000);
// ]]>
</script>
</div>
<hr />';
foot($dat);
echo $dat;
}
 
/* 處理 Applet 送來的 Raw Data 並分析儲存 */
function Action_Save(){
$nowTime = time(); // 現在時間
$RAWInput = fopen('php://input', 'rb');
$RAWData = '';
while (!feof($RAWInput)) $RAWData .= fread($RAWInput, 8192);
fclose($RAWInput);
$userHeaderLength = intval(substr($RAWData, 1, 8)); // User HEADER Length
$userHeader = explode(',', substr($RAWData, 9, $userHeaderLength)); // User Header
foreach($userHeader as $h){
$h = explode('=', $h);
$$h[0] = $h[1]; // 分配變數 ($user = XXX, $time = XXX)
}
$datData = ($nowTime - $time);
$filename = $nowTime.'_'.$user; // 檔名
file_put_contents($this->TMPFolder.$filename.'.dat', $datData); // Recognize Data (作畫秒數)
 
$imgLength = intval(substr($RAWData, 9 + $userHeaderLength, 8)); // Image Data Length
$imgData = substr($RAWData, 19 + $userHeaderLength, $imgLength); // Image Data
$imgType = substr($imgData, 1, 5); // Image Type (Probably PNG\r\n)
file_put_contents($this->TMPFolder.$filename.(($imgType=="PNG\r\n") ? '.png' : '.jpg'), $imgData);
 
$pchLength = intval(substr($RAWData, 19 + $userHeaderLength + $imgLength, 8)); // PCH Length
if($pchLength > 0){
$pchType = substr($RAWData, 0, 1); // PCH Type
$pchData = substr($RAWData, 19 + $userHeaderLength + $imgLength + 8, $pchLength); // PCH BINARY DATA
file_put_contents($this->TMPFolder.$filename.($pchType=='S' ? '.s' : '.').'pch', $pchData);
}
}
 
/* 發文頁面 */
function Action_Post(){
$resto = isset($_GET['resto']) ? intval($_GET['resto']) : 0; // 回應編號
$userCode = str_replace(array('/','?'), '_', substr(crypt(md5($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'].IDSEED),'id'), -12)); // 使用者識別碼 (IP + UserAgent)
$imgList = '';
$imgs = glob($this->TMPFolder.'*_'.$userCode.'.*');
if(count($imgs) == 0) error('目前沒有屬於您的繪圖存在,請先作畫');
foreach($imgs as $l){
if(preg_match('/\.(jpg|png)$/', $l)) $imgList .= '<div style="float: left; margin: 1em; border: solid grey 1px"><img src="'.$l.'" /><br />'.basename($l).'</div>'."\n";
}
 
$dat = '';
head($dat);
form($dat, $resto, false); // 發文表單不摺疊
$dat .= '<script type="text/javascript">try{ $g("fupfile").disabled = true; showform(); }catch(e){}</script>
 
<div id="imglist">
'.$imgList.'
</div>';
 
foot($dat);
echo $dat;
}
 
/* 顯示動畫 */
function Action_ViewPCH(){
$imgfile = isset($_GET['file']) ? './'.IMG_DIR.$_GET['file'] : false; // 圖檔名
if(!file_exists($imgfile)) error('File Not Found.');
$size = getimagesize($imgfile);
$imgW = $size[0]; $imgH = $size[1]; // 繪圖版面大小
$appletW = $imgW; if($appletW < 200){ $appletW = 200; } // Applet 大小
$appletH = $imgH + 26; if($appletH < 226){ $appletH = 226; }
 
$name = str_replace(strrchr($imgfile, '.'), '', $imgfile); // 去除副檔名
$type = isset($_GET['type']) ? $_GET['type'] : 'pch'; // pch or spch
$pchName = $name.'.'.$type; // 動畫檔案位置
$pchSize = filesize($pchName);
 
switch($type){
case 'pch': // PaintBBS PCH File
$PappletCode = 'pch.PCHViewer.class';
$PappletJar = $this->PaintComponent['PCHViewer'].','.$this->PaintComponent['PaintBBS'];
$PappletParams = '';
break;
case 'spch': // ShiPainter SPCH File
$PappletCode = 'pch2.PCHViewer.class';
$PappletJar = $this->PaintComponent['PCHViewer'].','.$this->PaintComponent['ShiPainter'];
$PappletParams = '<param name="res.zip" value="res.zip" />
<param name="tt.zip" value="tt_def.zip" />
<param name="tt_size" value="31" />';
break;
default:
error('File Not support');
}
 
$dat = '';
head($dat);
$dat .= '
<div id="linkbar">
[<a href="'.PHP_SELF2.'">回到版面</a>]
<div class="bar_reply">動畫播放模式</div>
</div>
<div id="container" style="text-align: center">
<applet name="pch" code="'.$PappletCode.'" archive="'.$PappletJar.'" width="'.$appletW.'" height="'.$appletH.'" mayscript="mayscript">
'.$PappletParams.'
<param name="image_width" value="'.$imgW.'" />
<param name="image_height" value="'.$imgH.'" />
<param name="pch_file" value="'.$pchName.'" />
<param name="speed" value="10" />
<param name="buffer_progress" value="false" />
<param name="buffer_canvas" value="false" />
 
<param name="color_back" value="#FFFFFF" />
<param name="color_text" value="#333333" />
<param name="color_icon" value="#FFFFFF" />
<param name="color_bar" value="#AAAAAA" />
<param name="color_bar_select" value="#999999" />
<param name="color_frame" value="#666666" />
</applet>
<p>-<a href="'.$pchName.'">Download</a>-<br />('.$pchSize.' bytes)</p>
</div>
<hr />';
foot($dat);
echo $dat;
}
 
/* 刪除舊暫存 */
function Action_deleteOldTemp(){
global $FileIO;
 
if(!is_dir($this->TMPFolder)){ mkdir($this->TMPFolder); @chmod($this->TMPFolder, 0777); }
// 檢查暫存是否過舊無人認領,超過一段時間就砍
$nowTime = time();
$files = glob($this->TMPFolder.'*');
foreach($files as $f){
if($nowTime - intval($f) > 86400){ unlink($f); } // 超過一天未處理則刪除
}
// 作畫動畫檔相依性檢查
$files2 = array_merge(glob(IMG_DIR.'*.pch'), glob(IMG_DIR.'*.spch'));
foreach($files2 as $ff){
$fff = basename($ff, strrchr($ff, '.'));
if(!$FileIO->imageExists($fff.'.png') && !$FileIO->imageExists($fff.'.jpg')){ unlink($ff); } // 作畫動畫原始圖檔已刪
}
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id

/release/Modules-PIO-v6/mod_pm/mod_pm.php
@@ -0,0 +1,282 @@
<?php
/* mod_pm : Personal Messages for Trips (Pre-Alpha)
* $Id$
*/
class mod_pm{
var $MESG_LOG,$MESG_CACHE;
var $myPage,$trips,$lastno;
function mod_pm(){
global $PMS, $PIO, $FileIO;
 
$PMS->hookModuleMethod('ModulePage', 'mod_pm'); // 向系統登記模組專屬獨立頁面
$this->myPage = $PMS->getModulePageURL('mod_pm'); // 基底位置
$this->trips = array();
 
$this->MESG_LOG = './tripmesg.log'; // PM紀錄檔位置
$this->MESG_CACHE = './tripmesg.cc'; // PM快取檔位置
}
 
function getModuleName(){
return 'mod_pm';
}
 
function getModuleVersionInfo(){
return 'mod_pm : Personal Messages for Trip (Pre-Alpha)';
}
 
/* 自動掛載:頂部連結列 */
function autoHookToplink(&$linkbar, $isReply){
$linkbar .= '[<a href="'.$this->myPage.'">收件箱</a>] [<a href="'.$this->myPage.'&amp;action=write">發PM</a>]'."\n";
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
if(preg_match('|(<a.*">)?(.*)<span class\="nor">'._T('trip_pre').'(.{10})</span>(<span.*</span>)(</a>)?|', $arrLabels['{$NAME}'], $matches)) {
if($matches[3]) { // Trip found
if($matches[2]) { // has name
$arrLabels['{$NAME}']=$matches[1].$matches[2].($matches[1]?'</a>':'').'<span class="nor"><a href="'.$this->myPage.'&amp;action=write&amp;t='.$matches[3].'" style="text-decoration: overline underline" title="PM">'._T('trip_pre').'</a>'.$matches[1].$matches[3].($matches[1]?'</a>':'')."</span>".$matches[4];
} else {
$arrLabels['{$NAME}']='<span class="nor"><a href="'.$this->myPage.'&amp;action=write&amp;t='.$matches[3].'" style="text-decoration: overline underline" title="PM">'._T('trip_pre').'</a>'.$matches[1].$matches[3].($matches[1]?'</a>':'')."</span>".$matches[4];
}
}
}
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
function _tripping($str) {
$salt = preg_replace('/[^\.-z]/', '.', substr($str.'H.', 1, 2));
$salt = strtr($salt, ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
return substr(crypt($str, $salt), -10);
}
 
function _latestPM() {
$htm = '<table style="border:3pt outset white;background:#efefef" cellpadding="0" cellspacing="0">
<tr style="background:#000033;color:white"><td align="center">
<b>◆10日以内的投函一覧◆</b></td></tr>
<tr><td>
<div style="width:300;height:200;overflow-y:scroll">
<table style="width:100%;font-size:9pt">
<tr style="background:#005500;color:white">
<th>到着時間</th>
<th>Trip</th>
<th>信息數</th></tr>';
$this->_loadCache();
 
foreach($this->trips as $t => $v) { //d=last update date, c=count
if($v['d']<time()-864000) break; // out of range (10 days)
$htm.='<tr><td>'.date('Y-m-d H:i:s',$v['d']).($v['d']>time()-86400?' <span style="font-size:0.8em;color:#f44;">(new!)</span>':'').'</td><td class="name">'._T('trip_pre').substr($t,0,5)."...</td><td align='center'>$v[c] "._T('info_basic_threads')."</td></tr>";
}
return $htm.'</table></div></td></tr></table>';
}
 
function _loadCache() {
if(!$this->trips) {
if($logs=@file($this->MESG_CACHE)) { // 有快取
$this->lastno=trim($logs[0]);
$this->trips=unserialize($logs[1]);
return true;
} else { // 無快取
return $this->_rebuildCache();
}
} else return true;
}
 
function _rebuildCache() {
$this->trips = array();
if($logs=@file($this->MESG_LOG)) { // mesgno,trip,date,from,topic,mesg = each $logs, order desc
if(!$this->lastno) if(isset($logs[0])) $this->lastno = intval(substr($logs[0],strpos($logs[0],','))); // last no
foreach($logs as $log) {
list($mno,$trip,$pdate,)=explode(',',trim($log));
if(isset($this->trips[$trip])) {
$this->trips[$trip]['c']++;
// if($this->trips[$trip]['d']<$pdate) $this->trips[$trip]['d'] = $pdate;
} else {
$this->trips[$trip]=array('c'=>1,'d'=>$pdate);
}
}
 
// Sort in order
foreach ($this->trips as $key => $row) {
$c[$key] = $row['c'];
$d[$key] = $row['d'];
}
array_multisort($d, SORT_DESC, $c, SORT_ASC, $this->trips);
 
$this->_writeCache();
 
return true;
} else {
$this->_writeCache();
return false;
}
}
 
function _writeCache() {
$this->_write($this->MESG_CACHE,$this->lastno."\n".serialize($this->trips));
}
 
function _write($file,$data) {
$rp = fopen($file, "w");
flock($rp, LOCK_EX); // 鎖定檔案
@fputs($rp,$data);
flock($rp, LOCK_UN); // 解鎖
fclose($rp);
chmod($file,0666);
}
 
function _postPM($from,$to,$topic,$mesg) {
if(!preg_match('/^[0-9a-zA-Z\.\/]{10}$/',$to)) error("Trip有誤");
$from=CleanStr($from); $to=CleanStr($to); $topic=CleanStr($topic); $mesg=CleanStr($mesg);
if(!$from) if(ALLOW_NONAME) $from = DEFAULT_NONAME;
if(!$topic) $topic = DEFAULT_NOTITLE;
if(!$mesg) error("請填入內文");
if(preg_match('/(.*?)[##](.*)/u', $from, $regs)){ // トリップ(Trip)機能
$from = $nameOri = $regs[1]; $cap = strtr($regs[2], array('&amp;'=>'&'));
$from = $from.'<span class="nor">'._T('trip_pre').$this->_tripping($cap)."</span>";
}
$from = str_replace(_T('admin'), '"'._T('admin').'"', $from);
$from = str_replace(_T('deletor'), '"'._T('deletor').'"', $from);
$from = str_replace('&'._T('trip_pre'), '&amp;'._T('trip_pre'), $from); // 避免 &#xxxx; 後面被視為 Trip 留下 & 造成解析錯誤
$mesg = str_replace(',','&#44;',$mesg); // 轉換","
$mesg = str_replace("\n",'<br/>',$mesg); //nl2br不行
 
$this->_loadCache();
 
$logs=(++$this->lastno).",$to,".time().",$from,$topic,$mesg,$_SERVER[REMOTE_ADDR],\n".@file_get_contents($this->MESG_LOG);
$this->_write($this->MESG_LOG,$logs);
 
$this->_rebuildCache();
}
 
function _getPM($trip) {
global $PTE,$PMS;
$dat='';
$trip=substr($trip,1);
$tripped=$this->_tripping($trip);
if($logs=@file($this->MESG_LOG)) { // mesgno,trip,date,from,topic,mesg,ip = each $logs, order desc
foreach($logs as $log) {
list($mno,$totrip,$pdate,$from,$topic,$mesg,$ip)=explode(',',trim($log));
if($totrip==$tripped) {
if(!$dat) $dat=$PTE->ParseBlock('REALSEPARATE',array()).'<form action="'.$this->myPage.'" method="POST"><input type="hidden" name="action" value="delete" /><input type="hidden" name="trip" value="'.$trip.'" />';
$arrLabels = array('{$NO}'=>$mno, '{$SUB}'=>$topic, '{$NAME}'=>$from, '{$NOW}'=>date('Y-m-d H:i:s',$pdate)." IP:".preg_replace('/\d+$/','*',$ip), '{$COM}'=>$mesg, '{$QUOTEBTN}'=>"No.$mno", '{$REPLYBTN}'=>'', '{$IMG_BAR}'=>'', '{$IMG_SRC}'=>'', '{$WARN_OLD}'=>'', '{$WARN_BEKILL}'=>'', '{$WARN_ENDREPLY}'=>'', '{$WARN_HIDEPOST}'=>'', '{$NAME_TEXT}'=>_T('post_name'), '{$RESTO}'=>1);
$PMS->useModuleMethods('ThreadPost', array(&$arrLabels, array(), 0)); // "ThreadPost" Hook Point
$dat .= $PTE->ParseBlock('THREAD',$arrLabels);
$dat .= $PTE->ParseBlock('REALSEPARATE',array());
}
}
}
if(!$dat) $dat="沒有信息。";
else $dat.='<input type="submit" name="delete" value="'._T('del_btn').'" /></form>';
return $dat;
}
 
function _deletePM($no,$trip) {
$tripped=$this->_tripping($trip);
$found=false;
if($logs=@file($this->MESG_LOG)) { // mesgno,trip,date,from,topic,mesg = each $logs, order desc
$countlogs=count($logs);
foreach($no as $n) {
for($i=0;$i<$countlogs;$i++) {
list($mno,$totrip,)=explode(',',$logs[$i]);
if($totrip==$tripped && $mno==$n) {
$logs[$i]=''; // deleted
$found=true;
break;
}
}
}
if($found) {
$newlogs=implode('',$logs);
$this->_write($this->MESG_LOG,$newlogs);
$this->_rebuildCache();
}
}
}
 
function ModulePage(){
global $PMS, $PIO, $FileIO;
$trip=isset($_REQUEST['t'])?$_REQUEST['t']:'';
$action=isset($_REQUEST['action'])?$_REQUEST['action']:'';
$dat='';
 
if($action != 'postverify') {
head($dat);
echo $dat.'[<a href="'.PHP_SELF2.'?'.time().'">'._T('return').'</a>]';
}
if($action == 'write') {
echo '<div class="bar_reply">發送私人信息</div>
<div style="text-align: center;">
<form id="pmform" action="'.$this->myPage.'" method="POST">
<input type="hidden" name="action" value="post" />
<table cellpadding="1" cellspacing="1" id="postform_tbl" style="margin: 0px auto; text-align: left;">
<tr><td class="Form_bg"><b>由</b></td><td><input type="text" name="from" value="" size="28" />(Trip可)</td></tr>
<tr><td class="Form_bg"><b>至</b></td><td>'._T('trip_pre').'<input type="text" name="t" value="'.$trip.'" maxlength="10" size="14" /></td></tr>
<tr><td class="Form_bg"><b>'._T('form_topic').'</b></td><td><input type="text" name="topic" size="28" value="" /></td></tr>
<tr><td class="Form_bg"><b>'._T('form_comment').'</b></td><td><textarea cols="40" rows="5" name="content"></textarea></td></tr>
<tr><td colspan="2" align="right"><input type="submit" name="submit" value="'._T('form_submit_btn').'"/></td></tr>
</table>
</form>
</div>
<script type="text/javascript">
$g("pmform").from.value=getCookie("namec");
</script>
';
} elseif($action == 'post') {
echo '<div class="bar_reply">確認送出私人信息</div>
<div style="text-align: center;">
<form id="pmform" action="'.$this->myPage.'" method="POST">
<input type="hidden" name="action" value="postverify" />
<table cellpadding="1" cellspacing="1" id="postform_tbl" style="margin: 0px auto; text-align: left;">
<tr><td colspan="2">請確認將會送出的私人信息。按['._T('form_submit_btn').']繼續。</td></tr>
<tr><td class="Form_bg"><b>由</b></td><td><input type="text" name="from" value="'.$_POST['from'].'" size="28" /></td></tr>
<tr><td class="Form_bg"><b>至</b></td><td>'._T('trip_pre').'<input type="text" name="t" value="'.$_POST['t'].'" maxlength="10" size="14" /></td></tr>
<tr><td class="Form_bg"><b>'._T('form_topic').'</b></td><td><input type="text" name="topic" size="28" value="'.$_POST['topic'].'" /></td></tr>
<tr><td class="Form_bg"><b>'._T('form_comment').'</b></td><td><textarea cols="40" rows="5" name="content">'.$_POST['content'].'</textarea></td></tr>
<tr><td colspan="2" align="right"><input type="submit" name="submit" value="'._T('form_submit_btn').'"/></td></tr>
</table>
</form>
</div>';
} elseif($action == 'postverify') {
$this->_postPM($_POST['from'],$_POST['t'],$_POST['topic'],$_POST['content']);
if(preg_match('/(.*?)[##](.*)/u', $_POST['from'], $regs)){ // トリップ(Trip)機能
$_POST['from'] = $nameOri = $regs[1]; $cap = strtr($regs[2], array('&amp;'=>'&'));
$_POST['from'] = $_POST['from'].'<span class="nor">'._T('trip_pre').$this->_tripping($cap)."</span>";
}
head($dat);
echo $dat.'[<a href="'.PHP_SELF2.'?'.time().'">'._T('return').'</a>]';
echo '<div class="bar_reply">已送出私人信息</div>
<table cellpadding="1" cellspacing="1" id="postform_tbl" style="margin-left:1.5em">
<tr><td colspan="2">已送出。</td></tr>
<tr><td class="Form_bg"><b>由</b></td><td class="name">'.$_POST['from'].'</td></tr>
<tr><td class="Form_bg"><b>至</b></td><td>'._T('trip_pre').$_POST['t'].'</td></tr>
<tr><td class="Form_bg"><b>'._T('form_topic').'</b></td><td>'.$_POST['topic'].'</td></tr>
<tr><td class="Form_bg"><b>'._T('form_comment').'</b></td><td><blockquote>'.$_POST['content'].'</blockquote></td></tr>
</table>';
} else {
echo '<div class="bar_reply">收件箱</div>';
if($action == 'delete' && isset($_POST['trip'])) {
$delno=array();
while($item = each($_POST)) if($item[1]=='delete') array_push($delno, $item[0]);
if(count($delno)) $this->_deletePM($delno,$_POST['trip']);
}
echo $this->_latestPM();
echo '【檢查收件箱】<form id="pmform" action="'.$this->myPage.'" method="POST">
<input type="hidden" name="action" value="check" />
<label>Trip:<input type="text" name="trip" value="" size="28" /></label><input type="submit" name="submit" value="'._T('form_submit_btn').'"/>(以"#"為首)
</form>
<script type="text/javascript">
$g("pmform").trip.value=getCookie("namec").replace(/^[^#]*#/,"#");
</script>';
if($action == 'check' && isset($_POST['trip']) && substr($_POST['trip'],0,1) == '#') echo $this->_getPM($_POST['trip']);
 
}
$dat='';
foot($dat);
echo $dat;
}
}
?>
New file
/release/Modules-PIO-v6/mod_robottrap/.htaccess
@@ -0,0 +1,10 @@
# Place in the same folder as pixmicat.php
 
RewriteEngine On
RewriteRule src/11266284o2168.jpg pixmicat.php?mode=module&load=mod_robottrap
RewriteRule src/113145915o542.jpg pixmicat.php?mode=module&load=mod_robottrap
RewriteRule imglist.htm pixmicat.php?mode=module&load=mod_robottrap
RewriteRule allimage.htm pixmicat.php?mode=module&load=mod_robottrap
 
Order Allow,Deny
Allow from all
New file
/release/Modules-PIO-v6/mod_robottrap/mod_robottrap.php
@@ -0,0 +1,53 @@
<?php
/*
mod_robottrap : 機器人及砍站程式陷阱程式
由 scribe 略改自しおからphpスクリプト的「畫像一括ダウンロードロボット‧排除用トラップ」
*/
 
class mod_robottrap{
var $DENYLIST_FILE;
 
function mod_robottrap(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', 'mod_robottrap'); // 向系統登記模組專屬獨立頁面
 
$this->DENYLIST_FILE = './denylist.txt'; // 封鎖名單列表檔案
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_robottrap : 機器人及砍站程式陷阱程式';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '4th.Release.2 (v071111)';
}
 
/* 自動掛載陷阱點 */
function autoHookThreadFront(&$dat, $isReply){
$dat .= '<a href="imglist.htm"></a><a href="src/11266284o2168.jpg"></a>'."\n";
}
 
/* 自動掛載陷阱點 */
function autoHookThreadRear(&$dat, $isReply){
$dat .= '<a href="allimage.htm"></a><a href="src/113145915o542.jpg"></a>'."\n";
}
 
/* 加入封鎖名單 */
function ModulePage(){
$fp = fopen('./.htaccess', 'a');
$denyip = 'Deny from '.$_SERVER['REMOTE_ADDR']."\n"; // 加入一行新封鎖設定
fwrite($fp, $denyip);
fclose($fp);
 
$fp = fopen($this->DENYLIST_FILE, 'a');
$denytime = gmdate('y/m/d H:i:s', time() + TIME_ZONE * 3600);
$denytxt = $denytime."\t".$_SERVER['REMOTE_ADDR']."\t".gethostbyaddr($_SERVER['REMOTE_ADDR'])."\t".$_SERVER['HTTP_USER_AGENT']."\n"; // 加入一行新記錄
fwrite($fp, $denytxt);
fclose($fp);
 
echo 'Denied from '.$_SERVER['REMOTE_ADDR']."\n";
}
}
?>
New file
/release/Modules-PIO-v6/mod_readonly/mod_readonly.php
@@ -0,0 +1,30 @@
<?php
/*
mod_readonly.php
*/
 
class mod_readonly{
var $READONLY, $ALLOWREPLY;
 
function mod_readonly(){
$this->READONLY = true; // 設置唯讀 (無法發文及回應)
$this->ALLOWREPLY = false; // 開放回應
}
 
function getModuleName(){
return 'mod_readonly : 版面唯讀';
}
 
function getModuleVersionInfo(){
return '4th.Release.2 (v071111)';
}
 
function autoHookRegistBegin(&$name, &$email, &$sub, &$com, $upfileInfo, $accessInfo){
$pwd = isset($_POST['pwd']) ? $_POST['pwd'] : '';
$resto = isset($_POST['resto']) ? $_POST['resto'] : 0;
 
if($this->ALLOWREPLY && $resto) return; // 開放回應
if($this->READONLY && $pwd != ADMIN_PASS && ($name != CAP_NAME && $pwd != CAP_PASS)){ error('唯讀模式下不能寫入新文章'); } // 檢查是否唯讀
}
}
?>
New file
/release/Modules-PIO-v6/mod_ipfilter/mod_ipfilter.php
@@ -0,0 +1,110 @@
<?php
class mod_ipfilter{
var $SELF;
 
function mod_ipfilter(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__);
$this->SELF = $PMS->getModulePageURL(__CLASS__);
}
 
function getModuleName(){
return __CLASS__.' : 搜尋 IP';
}
 
function getModuleVersionInfo(){
return 'b110403';
}
 
function autoHookLinksAboveBar(&$link, $pageId, $addinfo=false){
if($pageId == 'admin' && $addinfo == true)
$link .= '[<a href="'.$this->SELF.'">搜尋 IP</a>]';
}
 
function ModulePage(){
global $PMS, $PIO, $FileIO;
if(!adminAuthenticate('check')) die('[Error] Access Denied.');
 
$content = '';
// POST
if(strtoupper($_SERVER['REQUEST_METHOD']) == 'POST'){
// 刪除
$del = isset($_POST['del']) ? $_POST['del'] : null;
if($del != null){
$files = $PIO->removePosts($del);
$delta_totalsize = 0;
if(count($files)) $delta_totalsize -= $FileIO->deleteImage($files);
if($delta_totalsize != 0) total_size($delta_totalsize);
foreach($del as $n){
if($oldCaches = glob('./cache/'.$n.'-*')){
foreach($oldCaches as $o) @unlink($o);
}
}
}
 
// 對 host 作 search
$filter = isset($_POST['filter']) ? CleanStr($_POST['filter']) : '';
if($filter != ''){
$res = $PIO->searchPost($filter, '`host`', 'AND');
foreach ($res as $p){
$no = $p['no']; $now = $p['now']; $host = $p['host'];
$com = htmlspecialchars(str_cut(str_replace('<br />',' ', $p['com']), 50));
$content .= <<< HERE
<tr>
<td><input type="checkbox" name="del[]" value="$no" /></td>
<td>$no</td>
<td>$now</td>
<td>$com</td>
<td>$host</td>
</tr>
HERE;
}
// 沒結果
if(count($res) == 0) $content = '<tr><td rows="5">Not Found</td></tr>';
}
// AJAX 要求在此即停止,一般要求則繼續印出頁面
if(isset($_POST['ajax'])){
echo $content;
return;
}
}
 
// 顯示表單
$dat = '';
head($dat);
$dat .= '<div class="bar_admin">搜尋 IP</div>
<div id="content">
<form action="'.$this->SELF.'" method="post">
<div id="ipconfig">
Filter: <input type="text" name="filter" size="30" />
<input type="submit" value="搜尋" onclick="return search(this.form);" /><br />
<table border="0" width="100%">
<tr><th>Delete</th><th>No.</th><th>Date</th><th>Comment</th><th>Host</th></tr>
'.$content.'
</table>
<input type="submit" value="刪除" />
</div>
</form>
<hr />
</div>
<script type="text/javascript">
// <![CDATA[
function search(form){
var f = form.filter.value;
$.post("'.str_replace('&amp;', '&', $this->SELF).'", {filter: f, ajax: true}, function(d){
$("table", form)
// Remove all items except header
.find("tr:gt(0)").remove()
// Fill the results
.end().append(d);
});
return false;
}
// ]]>
</script>
';
foot($dat);
echo $dat;
}
}
?>
New file
/release/Modules-PIO-v6/mod_userrepair/mod_userrepair.php
@@ -0,0 +1,55 @@
<?php
class mod_userrepair {
var $SELF;
 
function mod_userrepair(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 向系統登記模組專屬獨立頁面
$this->SELF = $PMS->getModulePageURL(__CLASS__); // 本頁面連結
}
 
function autoHookThreadFront(&$txt,$isReply){
if(!$isReply) $txt.='<div style="text-align: right">[<a href="'.$this->SELF.'" rel="nofollow">討論串不見了?按一下這裡吧。</a>]</div>';
else $txt.='<div style="text-align: right">[<a href="'.$this->SELF.'&amp;res='.$isReply.'" rel="nofollow">文章不見了?按一下這裡吧。</a>]</div>';
}
 
/* 模組獨立頁面 */
function ModulePage(){
global $PIO;
if(!isset($_GET['res'])) {
if(!file_exists('./.userrepair')||isset($_GET['force'])) {
touch('./.userrepair');
$PIO->dbMaintanence('repair',$PIO->dbMaintanence('repair'));
updatelog(); // 重導向到靜態快取
unlink('./.userrepair');
header('HTTP/1.1 302 Moved Temporarily');
header('Location: '.fullURL().PHP_SELF2.'?'.time());
} else {
error('已經有其他人在修復中。<p>[<a href="'.$this->SELF.'&amp;force=1">強制執行</a>]</p>');
}
} else {
if(!file_exists('./.userrepair')||isset($_GET['force'])) {
touch('./.userrepair');
$no=intval($_GET['res']);
deleteCache(array($no));
unlink('./.userrepair');
header('HTTP/1.1 302 Moved Temporarily');
header('Location: '.fullURL().PHP_SELF.'?res='.$no);
} else {
error('已經有其他人在修復中。<p>[<a href="'.$this->SELF.'&amp;res='.$_GET['res'].'&amp;force=1">強制執行</a>]</p>');
}
}
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_userrepair : 使用者自行修復';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return 'Pixmicat! User Repair Module v090526';
}
 
}
?>
New file
/release/Modules-PIO-v6/mod_edit/mod_edit.php
@@ -0,0 +1,181 @@
<?php
class mod_edit{
var $mypage;
var $shown_in_page;
 
function mod_edit(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 向系統登記模組專屬獨立頁面
$this->mypage = $PMS->getModulePageURL(__CLASS__);
$this->shown_in_page = false; // 是否顯示編輯功能於前端頁面供使用者自行修改
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_edit : 文章編輯功能';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '4th.Release.3 (v080519)';
}
 
function autoHookAdminList(&$modFunc, $post, $isres){
$modFunc .= '[<a href="'.$this->mypage.'&amp;no='.$post['no'].'" title="Edit">E</a>]';
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
if($this->shown_in_page) $arrLabels['{$REPLYBTN}'] .= ' [<a href="'.$this->mypage.'&amp;no='.$post['no'].'">編輯</a>]';
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
if($this->shown_in_page) $arrLabels['{$QUOTEBTN}'] .= ' [<a href="'.$this->mypage.'&amp;no='.$post['no'].'">編輯</a>]';
}
 
function _EditPostInfo(&$txt){
$txt = '<li><span style="font-size:110%;font-weight:bold;">不用更換的欄位請留空。</span></li>'.$txt;
}
 
function ModulePage(){
global $PIO, $FileIO, $PMS, $language, $BAD_STRING, $BAD_FILEMD5, $BAD_IPADDR, $LIMIT_SENSOR;
 
if(!isset($_GET['no'])) die('[Error] not enough parameter.');
if(!isset($_POST['mode'])){ // 顯示表單
if(!$this->shown_in_page && !adminAuthenticate('check')) die('[Error] Access Denied.');
 
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
extract($post[0]);
$PMS->loadModules('mod_bbcode'); //嘗試載入mod_bbcode
if($bbcode=$PMS->getModuleInstance('mod_bbcode')) $bbcode->_html2bb($com);
$name=preg_replace('|<span.*?>(.*?)</span>|','\1',$name);
$dat='';
head($dat);
$PMS->hookModuleMethod('PostInfo', array($this,'_EditPostInfo'));
form($dat, $resto, false, $this->mypage.'&amp;no='.$_GET['no'], $name, $email, $sub, str_replace('<br />', "\n", $com), substr(str_replace('&#44;', ',', $category),1,-1), 'edit');
foot($dat);
echo $dat;
} else { // 儲存
if($_SERVER['REQUEST_METHOD'] != 'POST') error(_T('regist_notpost')); // 非正規POST方式
$post = $PIO->fetchPosts($_GET['no']);
$newValues = array();
 
if(!count($post)) die('[Error] Post does not exist.');
 
$name = isset($_POST[FT_NAME]) ? $_POST[FT_NAME] : '';
$email = isset($_POST[FT_EMAIL]) ? $_POST[FT_EMAIL] : '';
$sub = isset($_POST[FT_SUBJECT]) ? $_POST[FT_SUBJECT] : '';
$com = isset($_POST[FT_COMMENT]) ? $_POST[FT_COMMENT] : '';
$pwd = isset($_POST['pwd']) ? $_POST['pwd'] : '';
$category = isset($_POST['category']) ? $_POST['category'] : '';
$resto = isset($_POST['resto']) ? $_POST['resto'] : 0;
$upfile = '';
$upfile_path = '';
$upfile_name = false;
$upfile_status = 4;
$pwdc = isset($_COOKIE['pwdc']) ? $_COOKIE['pwdc'] : '';
 
if($resto && !$PIO->isThread($resto)) die('[Error] Thread was deleted.');
$is_admin = $haveperm = ($pwd==ADMIN_PASS) || adminAuthenticate('check');
$PMS->useModuleMethods('Authenticate', array($pwd,'useredit',&$haveperm));
 
if($pwd=='' && $pwdc!='') $pwd = $pwdc;
$pwd_md5 = substr(md5($pwd),2,8);
$host = gethostbyaddr(getREMOTE_ADDR());
if(!($pwd_md5==$post[0]['pwd'] || $host==$post[0]['host'] || $haveperm)) die('[Error] Access denied.');
 
// 欄位陷阱
$FTname = isset($_POST['name']) ? $_POST['name'] : '';
$FTemail = isset($_POST['email']) ? $_POST['email'] : '';
$FTsub = isset($_POST['sub']) ? $_POST['sub'] : '';
$FTcom = isset($_POST['com']) ? $_POST['com'] : '';
$FTreply = isset($_POST['reply']) ? $_POST['reply'] : '';
if($FTname != 'spammer' || $FTemail != 'foo@foo.bar' || $FTsub != 'DO NOT FIX THIS' || $FTcom != 'EID OG SMAPS' || $FTreply != '') error(_T('regist_nospam'));
 
// 封鎖:IP/Hostname/DNSBL 檢查機能
$ip = getREMOTE_ADDR(); $host = gethostbyaddr($ip); $baninfo = '';
if(BanIPHostDNSBLCheck($ip, $host, $baninfo)) error(_T('regist_ipfiltered', $baninfo));
// 封鎖:限制出現之文字
foreach($BAD_STRING as $value){
if(strpos($com, $value)!==false || strpos($sub, $value)!==false || strpos($name, $value)!==false || strpos($email, $value)!==false){
error(_T('regist_wordfiltered'));
}
}
$PMS->useModuleMethods('RegistBegin', array(&$name, &$email, &$sub, &$com, array('file'=>&$upfile, 'path'=>&$upfile_path, 'name'=>&$upfile_name, 'status'=>&$upfile_status), array('ip'=>$ip, 'host'=>$host))); // "RegistBegin" Hook Point
 
// 檢查是否輸入櫻花日文假名
$chkanti = array($name, $email, $sub, $com);
foreach($chkanti as $anti) if(anti_sakura($anti)) error(_T('regist_sakuradetected'));
 
// 檢查表單欄位內容並修整
if(strlen($name) > 100) error(_T('regist_nametoolong'));
if(strlen($email) > 100) error(_T('regist_emailtoolong'));
if(strlen($sub) > 100) error(_T('regist_topictoolong'));
if(strlen($resto) > 10) error(_T('regist_longthreadnum'));
 
$email = CleanStr($email); $email = str_replace("\r\n", '', $email);
$sub = CleanStr($sub); $sub = str_replace("\r\n", '', $sub);
$resto = CleanStr($resto); $resto = str_replace("\r\n", '', $resto);
// 名稱修整
$name = CleanStr($name);
$name = str_replace(_T('trip_pre'), _T('trip_pre_fake'), $name); // 防止トリップ偽造
$name = str_replace(CAP_SUFFIX, _T('cap_char_fake'), $name); // 防止管理員キャップ偽造
$name = str_replace("\r\n", '', $name);
$nameOri = $name; // 名稱
if(preg_match('/(.*?)[##](.*)/u', $name, $regs)){ // トリップ(Trip)機能
$name = $nameOri = $regs[1]; $cap = strtr($regs[2], array('&amp;'=>'&'));
$salt = preg_replace('/[^\.-z]/', '.', substr($cap.'H.', 1, 2));
$salt = strtr($salt, ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
$name = $name._T('trip_pre').substr(crypt($cap, $salt), -10);
}
if(CAP_ENABLE && preg_match('/(.*?)[##](.*)/', $email, $aregs)){ // 管理員キャップ(Cap)機能
$acap_name = $nameOri; $acap_pwd = strtr($aregs[2], array('&amp;'=>'&'));
if($acap_name==CAP_NAME && $acap_pwd==CAP_PASS){
$name = '<span class="admin_cap">'.$name.CAP_SUFFIX.'</span>';
$is_admin = true;
$email = $aregs[1]; // 去除 #xx 密碼
}
}
if(!$is_admin){ // 非管理員
$name = str_replace(_T('admin'), '"'._T('admin').'"', $name);
$name = str_replace(_T('deletor'), '"'._T('deletor').'"', $name);
}
$name = str_replace('&◆', '&amp;◆', $name); // 避免 &#xxxx; 後面被視為 Trip 留下 & 造成解析錯誤
// 內文修整
if((strlen($com) > COMM_MAX) && !$is_admin) error(_T('regist_commenttoolong'));
$com = CleanStr($com, $is_admin); // 引入$is_admin參數是因為當管理員キャップ啟動時,允許管理員依config設定是否使用HTML
$com = str_replace("\r\n","\n", $com);
$com = str_replace("\r","\n", $com);
$com = ereg_replace("\n(( | )*\n){3,}", "\n", $com);
if(!BR_CHECK || substr_count($com,"\n") < BR_CHECK) $com = nl2br($com); // 換行字元用<br />代替
$com = str_replace("\n",'', $com); // 若還有\n換行字元則取消換行
if($category && USE_CATEGORY){ // 修整標籤樣式
$category = explode(',', $category); // 把標籤拆成陣列
$category = '&#44;'.implode('&#44;', array_map('trim', $category)).'&#44;'; // 去空白再合併為單一字串 (左右含,便可以直接以,XX,形式搜尋)
}else{ $category = ''; }
 
$age = false; $dest = '';
$W = $post[0]['tw']; $H = $post[0]['th']; $imgW = $post[0]['imgw']; $imgH = $post[0]['imgh']; $status = $post[0]['status'];
$PMS->useModuleMethods('RegistBeforeCommit', array(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $resto, array($W, $H, $imgW, $imgH), &$status)); // "RegistBeforeCommit" Hook Point
 
if($name != $post[0]['name'] && $_POST[FT_NAME]) $newValues['name'] = $name;
if($email != $post[0]['email'] && $_POST[FT_EMAIL]) $newValues['email'] = $email;
if($sub != $post[0]['sub'] && $_POST[FT_SUBJECT]) $newValues['sub'] = $sub;
if($com != $post[0]['com'] && $_POST[FT_COMMENT]) $newValues['com'] = $com;
if($category != $post[0]['category'] && $_POST['category']) $newValues['category'] = $category;
 
$PIO->updatePost($_GET['no'], $newValues);
$PIO->dbCommit();
 
$parentNo = $post[0]['resto'] ? $post[0]['resto'] : $post[0]['no'];
$threads = array_flip($PIO->fetchThreadList());
$threadPage = floor($threads[$parentNo] / PAGE_DEF);
if(STATIC_HTML_UNTIL == -1 || $threadPage <= STATIC_HTML_UNTIL) updatelog(0, $threadPage, true); // 僅更新討論串出現那頁
deleteCache(array($parentNo)); // 刪除討論串舊快取
 
header('HTTP/1.1 302 Moved Temporarily');
header('Location: '.fullURL().PHP_SELF2.'?'.time());
}
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_neta/mod_neta.php
@@ -0,0 +1,53 @@
<?php
class mod_neta{
var $NETA_LABEL;
 
function mod_neta(){
$this->NETA_LABEL = '[NETABARE_ARI]';
}
 
function getModuleName(){
return 'mod_neta : 劇情洩漏隱藏';
}
 
function getModuleVersionInfo(){
return '5th.Release.2-dev (v100921)';
}
 
function autoHookHead(&$dat){
$dat .= '<script type="text/javascript">
// <![CDATA[
jQuery(function($){
$(\'div.threadpost, div.reply\').find(\'span[id^=neta] > a\').bind(\'click\', function(){
$(this).parent().parent().find(\'*[id^=neta]\')
.filter(\'span\').hide().end()
.filter(\'div\').slideDown();
return false;
});
});
// ]]>
</script>
';
}
 
function autoHookPostInfo(&$postinfo){
$postinfo .= '<li><b>要捏他,請在內文使用<span style="color:blue;">'.$this->NETA_LABEL.'</span>標籤註明劇情洩漏!</b></li>'."\n";
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
$this->netaCollapse($arrLabels, $post, $isReply);
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->netaCollapse($arrLabels, $post, $isReply);
}
 
function netaCollapse(&$arrLabels, $post, $isReply){
$tmp_len = strlen($this->NETA_LABEL.'<br />');
if(($tmp_pos = strpos($arrLabels['{$COM}'], $this->NETA_LABEL.'<br />')) !== false){
$arrLabels['{$COM}'] = substr_replace($arrLabels['{$COM}'], '<div class="hide" id="netacoll'.$arrLabels['{$NO}'].'">', $tmp_pos, $tmp_len).'</div>';
$arrLabels['{$WARN_BEKILL}'] .= '<span class="warn_txt2" id="netabar'.$arrLabels['{$NO}'].'">這篇文章可能含有劇情洩漏,要閱讀全文請按下<a href="#">此處</a>展開。<br /></span>'."\n";
}
}
}
?>
New file
/release/Modules-PIO-v6/mod_eggpoll/mod_eggpoll.php
@@ -0,0 +1,238 @@
<?php
class mod_eggpoll{
var $mypage,$conn,$rankDB,$rankNames,$rankAlphas,$rankColors,$rankMin,$shrinkThread,$addBR,$oneSidedCount,$daysThreshold;
 
function mod_eggpoll(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 向系統登記模組專屬獨立頁面
$this->mypage = $PMS->getModulePageURL(__CLASS__);
$this->rankDB = 'eggpoll.db'; // poll database
$this->rankNames = array('噓爆','噓','中立','推','大推');
$this->rankAlphas = array('30','60','100','100','100');
$this->rankColors = array('#f00','#a00','','#274','#4b7');
$this->rankMin = 3; // 開始評價的最少票數
$this->oneSidedCount = 5; // 一面倒評價的最少票數
$this->shrinkThread = true; // 摺疊開版文時是否摺疊整個串 (festival.tpl用)
$this->daysThreshold = 14; // 詳細投票記錄保留日數
$this->addBR = 2; // #postform_main - #threads 之間插入空行? (0=不插入/1=在#postform_main後/2=在#threads前)
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_eggpoll : 文章評分機制';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '5th.Release-dev (v100521)';
}
 
function autoHookHead(&$txt, $isReply){
global $language;
$txt .= '<!--script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script-->
<style type="text/css">
.eggpoll {font-size: 0.8em;}
.eggpoll .rankup, .eggpoll .rankdown { color:#fff; cursor:pointer; }
.eggpoll .rankup { background-color: #c66; }
.eggpoll .rankdown { background-color: #66c; }
.eggpoll .rtoggle { display:none; }
.eggpoll .rtoggle, .eggpoll .rtoggled { color:blue; cursor:pointer; padding:0 0.27em; font-weight:bold; border: 1px solid blue; }
</style>
<script type="text/javascript">
var postNos = new Array();
var RankTexts = ["'.implode('","',$this->rankNames).'"];
var RankAlphas = ["'.implode('","',$this->rankAlphas).'"];
var RankColors = ["'.implode('","',$this->rankColors).'"];
var shrinkThread = '.$this->shrinkThread.';
// <![CDATA[
function mod_eggpollRank(no,rank){
$("span#ep"+no+">.rankup, span#ep"+no+">.rankdown").hide();
$.ajax({
url: "'.str_replace('&amp;', '&', $this->mypage).'&no="+no+"&rank="+rank,
type: "GET",
success: function(rv){
if(rv.substr(0, 4)!=="+OK "){
$("span#ep"+no+">.rankup, span#ep"+no+">.rankdown").css("display","inline");
alert(rv);
return false;
}
rv = $.parseJSON(rv.substr(4));
updateAppearance(rv.polls[0].no,rv.polls[0].rank,1);
},
error: function(){
$("span#ep"+no+">.rankup, span#ep"+no+">.rankdown").css("display","inline");
alert("Network error.");
}
});
}
function mod_eggpollToggle(o,no){
if(o.className=="rtoggle") {
o.className="rtoggled";
$("div#r"+no+">.quote, div#r"+no+"+div.quote, div#g"+no+">.quote, div#r"+no+" a>img").slideToggle();
if(shrinkThread) $("div#g"+no).height("auto");
} else {
o.className="rtoggle";
$("div#r"+no+">.quote, div#r"+no+"+div.quote, div#g"+no+">.quote, div#r"+no+" a>img").slideUp();
if(shrinkThread) $("div#g"+no).animate({height:"1.35em"});
}
}
function updateAppearance(no,rank,voted) {
if(RankAlphas[rank] != "null") {
$("div#r"+no+", div#r"+no+"+div.quote, div#g"+no+">.quote").fadeTo("fast",parseInt(RankAlphas[rank])/100);
}
$("span#ep"+no+">.ranktext").html(RankTexts[rank]);
$("span#ep"+no+">.ranktext").css("color",RankColors[rank]);
if(rank==0) {
$("span#ep"+no+">.rtoggle").show();
$("div#r"+no+">.quote, div#r"+no+"+div.quote, div#g"+no+">.quote, div#r"+no+" a>img").slideUp();
if(shrinkThread) $("div#g"+no).animate({height:"1.35em"});
}
if(voted) {
$("span#ep"+no+">.rankup, span#ep"+no+">.rankdown").hide();
}
}
function getPollValues() {
'.($this->addBR==1?'$("#postform_main").after("<br/>");':($this->addBR==2?'$("#threads").before("<br/>");':'')).'
$.getJSON("'.str_replace('&amp;', '&', $this->mypage).'&get="+postNos,function(data) {
$.each(data.polls, function(i,poll){
updateAppearance(poll.no,poll.rank,poll.voted);
});
});
}
// ]]>
</script>';
}
 
function autoHookFoot(&$foot){
global $language;
$foot .= '<script type="text/javascript">if(postNos.length)getPollValues();</script>';
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
global $language, $PIO;
$arrLabels['{$QUOTEBTN}'] .= '&nbsp;<script type="text/javascript">postNos.push('.$post['no'].');</script><span class="eggpoll" id="ep'.$post['no'].'"><span class="rankup" onclick="mod_eggpollRank('.$post['no'].',1)">+</span><span class="rankdown" onclick="mod_eggpollRank('.$post['no'].',0)">-</span><span class="ranktext">'.$this->rankNames[2].'</span> <a class="rtoggle" onclick="mod_eggpollToggle(this,'.$post['no'].')">↕</a></span>';
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
function _calcRank($up,$down) {
$total = $up+$down;
if(!$total) return 2; //prevent divide by zero
$u = $up / $total;
$d = 1 - $u;
if($down == 0) {
if($up >= $this->oneSidedCount) return 4;
else if($up >= $this->oneSidedCount/2) return 3;
else return 2;
} else if($up == 0) {
if($down >= $this->oneSidedCount) return 0;
else if($down >= $this->oneSidedCount/2) return 1;
else return 2;
} else {
if($u >= 0.65) return 4;
else if($u >= 0.55) return 3;
else if($d >= 0.65) return 0;
else if($d >= 0.55) return 1;
else return 2;
}
}
 
function _getPollValues($no) {
$ip = getREMOTE_ADDR(); $datestr = gmdate('Ymd',time()+TIME_ZONE*60*60); $voted = array(); $first = true;
$qry = 'SELECT no,ip,date FROM eggpoll_detail WHERE ip = "'.$ip.'" AND date = "'.$datestr.'" AND no IN('.$no.')';
$rs = sqlite_query($this->conn,$qry);
while($row = sqlite_fetch_array($rs)) { $voted[$row['no']]=1; }
 
$qry = 'SELECT * FROM eggpoll_votes WHERE no IN('.$no.')';
$rs = sqlite_query($this->conn,$qry);
echo '{
"polls" : [';
while($row = sqlite_fetch_array($rs)) {
if(!$first) echo ',';
echo '{ "no" : '.$row['no'].',
"rank" : '.$this->_calcRank($row['up'],$row['down']).',
"voted" : '.(isset($voted[$row['no']]) ? 1 : 0).' }';
if($first) $first=false;
}
echo ']
}';
}
 
function ModulePage(){
global $PIO, $PTE, $language; $sqlerr = ''; $nodb = false;
if(!file_exists($this->rankDB)) $nodb = true;
$this->conn = sqlite_popen($this->rankDB,0666,$sqlerr);
if($nodb) {
$str = "CREATE TABLE [eggpoll_votes] (
[no] INTEGER PRIMARY KEY NOT NULL,
[up] INTEGER DEFAULT '0' NOT NULL,
[down] INTEGER DEFAULT '0' NOT NULL
);
CREATE TABLE [eggpoll_detail] (
[no] INTEGER NOT NULL,
[option] INTEGER DEFAULT '0' NOT NULL,
[ip] TEXT NOT NULL,
[date] TEXT NOT NULL
);
CREATE INDEX eggpoll_detail_index_ip_date ON eggpoll_detail(ip,date);";
sqlite_exec($this->conn,$str,$sqlerr);
if($sqlerr) echo $sqlerr;
}
 
if(isset($_GET['get'])) {
$this->_getPollValues($_GET['get']);
}
else if(isset($_GET['no'])&&isset($_GET['rank'])){
$ip = getREMOTE_ADDR(); $tim = time()+TIME_ZONE*60*60;
$datestr = gmdate('Ymd',$tim); $deldate = gmdate('Ymd',strtotime('-'.$this->daysThreshold.' days',$tim));
$no = intval($_GET['no']); $rank = intval($_GET['rank']);
 
// 查IP
$baninfo = '';
$host = gethostbyaddr($ip);
if(BanIPHostDNSBLCheck($ip, $host, $baninfo)) die(_T('regist_ipfiltered', $baninfo));
 
$post = $PIO->fetchPosts($no);
if(!count($post)) die('[Error] Post does not exist.'); // 被評之文章不存在
 
// 檢查是否已經投票
$qry = 'SELECT no,ip,date FROM eggpoll_detail WHERE ip = "'.$ip.'" AND date = "'.$datestr.'" AND no ="'.$no.'"';
$rs = sqlite_query($this->conn,$qry);
if(sqlite_num_rows($rs)) die('[Error] Already voted.');
 
// 刐除舊詳細評價
$qry = 'SELECT date FROM eggpoll_detail WHERE date < "'.$deldate.'" LIMIT 1';
$rs = sqlite_query($this->conn,$qry);
if(sqlite_num_rows($rs)) {
$str = 'DELETE FROM eggpoll_detail WHERE date < "'.$deldate.'"';
sqlite_exec($this->conn,$str,$sqlerr);
sqlite_exec($this->conn,'VACUUM',$sqlerr);
}
 
$str = 'INSERT INTO eggpoll_detail (no,option,ip,date) VALUES ('.$no.','.$rank.',"'.$ip.'","'.$datestr.'")';
sqlite_exec($this->conn,$str,$sqlerr);
if($sqlerr) echo $sqlerr;
 
$qry = 'SELECT * FROM eggpoll_votes WHERE no ='.$no;
$rs = sqlite_query($this->conn,$qry);
if(!sqlite_num_rows($rs)) {
$str = 'INSERT INTO eggpoll_votes (no,up,down) VALUES ('.$no.($rank?',1,0)':',0,1)');
} else {
if($rank)
$str = 'UPDATE eggpoll_votes SET up = up+1 WHERE no='.$no;
else
$str = 'UPDATE eggpoll_votes SET down = down+1 WHERE no='.$no;
}
sqlite_exec($this->conn,$str,$sqlerr);
if($sqlerr) echo $sqlerr;
 
echo '+OK ';
$this->_getPollValues($no);
}
}
 
}
?>
New file

Property changes:

Name: svn:keywords
+ Id

/release/Modules-PIO-v6/mod_exif/mod_exif.php
@@ -0,0 +1,477 @@
<?php
/* mod_exif : EXIF information (Pre-Alpha)
* $Id$
* exif.php from http://www.rjk-hosting.co.uk/programs/prog.php?id=4
*/
class mod_exif{
var $myPage;
function mod_exif(){
global $PMS, $PIO, $FileIO;
 
$PMS->hookModuleMethod('ModulePage', 'mod_exif'); // 向系統登記模組專屬獨立頁面
$this->myPage = $PMS->getModulePageURL('mod_exif'); // 基底位置
}
 
function getModuleName(){
return 'mod_exif : EXIF資訊';
}
 
function getModuleVersionInfo(){
return 'v071119';
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
if(FILEIO_BACKEND=='normal') { // work for normal File I/O only
if($arrLabels['{$IMG_BAR}']!='') {
preg_match('/rel\="_blank">(.*)<\/a>/', $arrLabels['{$IMG_BAR}'], $matches);
$arrLabels['{$IMG_BAR}'] .= '<small> <a href="'.$this->myPage.'&amp;file='.$matches[1].'">[EXIF]</a></small>';
}
}
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
function ModulePage(){
global $PMS, $FileIO;
$file=isset($_GET['file'])?$_GET['file']:'';
if($file && $FileIO->imageExists($file)){
$pfile=IMG_DIR.'/'.$file;
if(function_exists("exif_read_data")) {
// echo "DEBUG: Using exif_read_data<br/>";
$exif_data = exif_read_data($pfile,0,true);
if(isset($exif_data['FILE'])) unset($exif_data['FILE']);
if(isset($exif_data['COMPUTED'])) unset($exif_data['COMPUTED']);
echo !count($exif_data) ? "No EXIF data found.<br />" : "Image contains EXIF data:<br /><br />";
echo "<table border='1'>";
foreach($exif_data as $key=>$section) {
foreach($section as $name=>$val) {
echo "<tr><th align='right'>$key.$name:</th><td>$val</td></tr>";
}
}
echo "</table>";
} else {
// echo "DEBUG: Using built-in exif library<br/>";
$exif=new exif($pfile);
echo !count($exif->exif_data) ? "No EXIF data found.<br />" : "Image contains EXIF data:<br /><br />";
echo "<table border='1'>";
foreach($exif->exif_data as $key=>$val)
echo "<tr><th align='right'>$key:</th><td>$val</td></tr>";
echo "</table>";
}
}
echo "<br /><a href='javascript:history.go(-1)'>[Back]</a>";
}
}
 
class exif{
/* Exif reader v 1.2
By Richard James Kendall
Bugs to richard@richardjameskendall.com
Free to use, please acknowledge me
*/
// holds the formatted data read from the EXIF data area
var $exif_data = array();
 
// holds the number format used in the EXIF data (1 == moto, 0 == intel)
var $align;
 
// holds the lengths and names of the data formats
var $format_length = array(0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8);
var $format_type = array("", "BYTE", "STRING", "USHORT", "ULONG", "URATIONAL", "SBYTE", "UNDEFINED", "SSHORT", "SLONG", "SRATIONAL", "SINGLE", "DOUBLE");
 
// data for EXIF enumeations
var $Orientation = array("", "Normal (0 deg)", "Mirrored", "Upsidedown", "Upsidedown & Mirrored", "Mirror horizontal and rotate 270 CW","Rotate 90 CW","Mirror horizontal and rotate 90 CW","Rotate 270 CW");
var $ResUnit = array("", "inches", "inches", "cm", "mm", "um");
var $YCbCrPos = array("", "Centre of Pixel Array", "Datum Points");
var $ExpProg = array("", "Manual", "Program", "Apeture Priority", "Shutter Priority", "Program Creative", "Program Action", "Portrait", "Landscape");
var $LightSource = array("Unknown", "Daylight", "Fluorescent", "Tungsten (incandescent)", "Flash", "Fine Weather", "Cloudy Weather", "Share", "Daylight Fluorescent", "Day White Fluorescent", "Cool White Fluorescent", "White Fluorescent", "Standard Light A", "Standard Light B", "Standard Light C", "D55", "D65", "D75", "D50", "ISO Studio Tungsten");
var $MeterMode = array("Unknown", "Average", "Centre Weighted", "Spot", "Multi-Spot", "Pattern", "Partial");
var $RenderingProcess = array("Normal Process", "Custom Process");
var $ExposureMode = array("Auto", "Manual", "Auto Bracket");
var $WhiteBalance = array("Auto", "Manual");
var $SceneCaptureType = array("Standard", "Landscape", "Portrait", "Night Scene");
var $GainControl = array("None", "Low Gain Up", "High Gain Up", "Low Gain Down", "High Gain Down");
var $Contrast = array("Normal", "Soft", "Hard");
var $Saturation = array("Normal", "Low Saturation", "High Saturation");
var $Sharpness = array("Normal", "Soft", "Hard");
var $SubjectDistanceRange = array("Unknown", "Macro", "Close View", "Distant View");
var $FocalPlaneResUnit = array("", "inches", "inches", "cm", "mm", "um");
var $SensingMethod = array("", "Not Defined", "One-chip Colour Area Sensor", "Two-chip Colour Area Sensor", "Three-chip Colour Area Sensor", "Colour Sequential Area Sensor", "Trilinear Sensor", "Colour Sequential Linear Sensor");
var $CalibrationIlluminant1,$CalibrationIlluminant2;
var $Flash = array(0x0 => "No Flash", 0x1 => "Fired", 0x5 => "Fired, Return not detected", 0x7 => "Fired, Return detected", 0x8 => "On, Did not fire", 0x9 => "On", 0xd => "On, Return not detected", 0xf => "On, Return detected", 0x10 => "Off", 0x14 => "Off, Did not fire, Return not detected", 0x18 => "Auto, Did not fire", 0x19 => "Auto, Fired", 0x1d => "Auto, Fired, Return not detected", 0x1f => "Auto, Fired, Return detected", 0x20 => "No flash function", 0x30 => "Off, No flash function", 0x41 => "Fired, Red-eye reduction", 0x45 => "Fired, Red-eye reduction, Return not detected", 0x47 => "Fired, Red-eye reduction, Return detected", 0x49 => "On, Red-eye reduction", 0x4d => "On, Red-eye reduction, Return not detected", 0x4f => "On, Red-eye reduction, Return detected", 0x50 => "Off, Red-eye reduction", 0x58 => "Auto, Did not fire, Red-eye reduction", 0x59 => "Auto, Fired, Red-eye reduction", 0x5d => "Auto, Fired, Red-eye reduction, Return not detected", 0x5f => "Auto, Fired, Red-eye reduction, Return detected");
 
// gets one byte from the file at handle $fp and converts it to a number
function fgetord($fp) {
return ord(fgetc($fp));
}
 
function gcd($a, $b) {
if ($a < $b) {
$gcd = $this->gcd($b, $a);
}else{
assert($a > 0);
assert($b >= 0);
while ($b != 0) {
$t = $a % $b;
$a = $b;
$b = $t;
}
$gcd = $a;
}
return $gcd;
}
 
function fractionSimply($n,$d) {
$g=($n>-1 && $n > -1)?$this->gcd($n, $d):1;
return array($n/$g,$d/$g);
}
 
function fractionToMixed($n,$d) {
$m = $n % $d;
return array(($n-$m)/$d,$m,$d);
}
 
// takes $data and pads it from the left so strlen($data) == $shouldbe
function pad($data, $shouldbe, $put) {
if (strlen($data) == $shouldbe) {
return $data;
} else {
$padding = "";
for ($i = strlen($data);$i < $shouldbe;$i++) {
$padding .= $put;
}
return $padding . $data;
}
}
 
// converts a number from intel (little endian) to motorola (big endian format)
function ii2mm($intel) {
$mm = "";
for ($i = 0;$i <= strlen($intel);$i+=2) {
$mm .= substr($intel, (strlen($intel) - $i), 2);
}
return $mm;
}
 
// gets a number from the EXIF data and converts if to the correct representation
function getnumber($data, $start, $length, $align) {
$a = bin2hex(substr($data, $start, $length));
if (!$align) {
$a = $this->ii2mm($a);
}
return hexdec($a);
}
 
// gets a rational number (num, denom) from the EXIF data and produces a decimal
function getrational($data, $align, $type) {
$a = bin2hex($data);
if (!$align) {
$a = $this->ii2mm($a);
}
if ($align == 1) {
$n = hexdec(substr($a, 0, 8));
$d = hexdec(substr($a, 8, 8));
} else {
$d = hexdec(substr($a, 0, 8));
$n = hexdec(substr($a, 8, 8));
}
if ($type == "S" && $n > 2147483647) {
$n = $n - 4294967296;
}
if ($n == 0) {
return 0;
}
if ($d != 0) {
$ra=$this->fractionSimply($n,$d);
return ($n / $d).($ra[1]!=1&&$ra[1]!=$d?' ('.$ra[0]."/".$ra[1].')':'').($d!=1?' ['.$n."/".$d.']':'');
} else {
return $n."/".$d;
}
}
 
// opens the JPEG file and attempts to find the EXIF data
function exif($file) {
$this->CalibrationIlluminant1=$this->CalibrationIlluminant2=$this->LightSource;
$this->align=0;
 
$fp = fopen($file, "rb");
$a = $this->fgetord($fp);
if ($a != 255 || $this->fgetord($fp) != 216) {
return false;
}
$ef = false;
while (!feof($fp)) {
$section_length = 0;
$section_marker = 0;
$lh = 0;
$ll = 0;
for ($i = 0;$i < 7;$i++) {
$section_marker = $this->fgetord($fp);
if ($section_marker != 255) {
break;
}
if ($i >= 6) {
return false;
}
}
if ($section_marker == 255) {
return false;
}
$lh = $this->fgetord($fp);
$ll = $this->fgetord($fp);
$section_length = ($lh << 8) | $ll;
$data = chr($lh) . chr($ll);
$t_data = fread($fp, $section_length - 2);
$data .= $t_data;
switch ($section_marker) {
case 225:
fclose($fp);
return $this->extractEXIFData(substr($data, 2), $section_length);
$ef = true;
break;
}
}
fclose($fp);
}
 
// reads the EXIF header and if it is intact it calls readEXIFDir to get the data
function extractEXIFData($data, $length) {
if (substr($data, 0, 4) == "Exif") {
if (substr($data, 6, 2) == "II") {
$this->align = 0;
} else {
if (substr($data, 6, 2) == "MM") {
$this->align = 1;
} else {
return false;
}
}
$a = $this->getnumber($data, 8, 2, $this->align);
if ($a != 0x2a) {
return false;
}
$first_offset = $this->getnumber($data, 10, 4, $this->align);
if ($first_offset < 8 || $first_offset > 16) {
return false;
}
$this->readEXIFDir(substr($data, 14), 8, $length - 6);
return true;
} else {
return false;
}
}
 
// takes an EXIF tag id and returns the string name of that tag
function tagid2name($id) {
switch ($id) {
case 0x000b: return "ACDComment"; break;
case 0x00fe: return "ImageType"; break;
case 0x0106: return "PhotometicInterpret"; break;
case 0x010e: return "ImageDescription"; break;
case 0x010f: return "Make"; break;
case 0x0110: return "Model"; break;
case 0x0112: return "Orientation"; break;
case 0x0115: return "SamplesPerPixel"; break;
case 0x011a: return "XRes"; break;
case 0x011b: return "YRes"; break;
case 0x011c: return "PlanarConfig"; break;
case 0x0128: return "ResUnit"; break;
case 0x0131: return "Software"; break;
case 0x0132: return "DateTime"; break;
case 0x013b: return "Artist"; break;
case 0x013f: return "WhitePoint"; break;
case 0x0211: return "YCbCrCoefficients"; break;
case 0x0213: return "YCbCrPos"; break;
case 0x0214: return "RefBlackWhite"; break;
case 0x1000: return "RelatedImageFileFormat"; break;
case 0x1001: return "RelatedImageWidth"; break;
case 0x1002: return "RelatedImageLength"; break;
case 0x8298: return "Copyright"; break;
case 0x829a: return "ExposureTime"; break;
case 0x829d: return "FNumber"; break;
case 0x8822: return "ExpProg"; break;
case 0x8825: return "GPSInfo"; break;
case 0x8827: return "ISOSpeedRating"; break;
case 0x9003: return "DTOpticalCapture"; break;
case 0x9004: return "DTDigitised"; break;
case 0x9102: return "CompressedBitsPerPixel"; break;
case 0x9201: return "ShutterSpeed"; break;
case 0x9202: return "ApertureWidth"; break;
case 0x9203: return "Brightness"; break;
case 0x9204: return "ExposureBias"; break;
case 0x9205: return "MaxApetureWidth"; break;
case 0x9206: return "SubjectDistance"; break;
case 0x9207: return "MeterMode"; break;
case 0x9208: return "LightSource"; break;
case 0x9209: return "Flash"; break;
case 0x920a: return "FocalLength"; break;
case 0x920b: return "FlashEnergy"; break;
case 0x9213: return "ImageHistory"; break;
case 0x9214: return "SubjectLocation"; break;
case 0x9217: return "SensingMethod"; break;
case 0x927c: return "MakerNote"; break;
case 0x9286: return "UserComment"; break;
case 0x9290: return "SubsecTime"; break;
case 0x9291: return "SubsecTimeOrig"; break;
case 0x9292: return "SubsecTimeDigi"; break;
case 0x9c9b: return "XPTitle"; break;
case 0x9c9c: return "XPComment"; break;
case 0x9c9d: return "XPAuthor"; break;
case 0x9c9e: return "XPKeywords"; break;
case 0x9c9f: return "XPSubject"; break;
case 0xa000: return "FlashPixVersion"; break;
case 0xa001: return "ColourSpace"; break;
case 0xa002: return "ImageWidth"; break;
case 0xa003: return "ImageHeight"; break;
case 0xa005: return "InteropOffset"; break;
case 0xa20e: return "FocalPlaneXRes"; break;
case 0xa20f: return "FocalPlaneYRes"; break;
case 0xa210: return "FocalPlaneResUnit"; break;
case 0xa214: return "SubjectLocation"; break;
case 0xa217: return "SensingMethod"; break;
case 0xa300: return "ImageSource"; break;
case 0xa301: return "SceneType"; break;
case 0xa401: return "RenderingProcess"; break;
case 0xa402: return "ExposureMode"; break;
case 0xa403: return "WhiteBalance"; break;
case 0xa404: return "DigitalZoomRatio"; break;
case 0xa405: return "FocalLength35mm"; break;
case 0xa406: return "SceneCaptureType"; break;
case 0xa407: return "GainControl"; break;
case 0xa408: return "Contrast"; break;
case 0xa409: return "Saturation"; break;
case 0xa40a: return "Sharpness"; break;
case 0xa40c: return "SubjectDistanceRange"; break;
case 0xa500: return "Gamma"; break;
case 0xbc02: return "Transfomation"; break;
case 0xc65a: return "CalibrationIlluminant1"; break;
case 0xc65b: return "CalibrationIlluminant2"; break;
default: return "(0x".dechex($id).")"; break;
}
}
 
// takes a (U/S)(SHORT/LONG) checks if an enumeration for this value exists and if it does returns the enumerated value for $tvalue
function enumvalue($tname, $tvalue) {
if (isset($this->$tname)) {
$tmp = $this->$tname;
return $tmp[$tvalue];
} else {
return $tvalue;
}
}
 
// takes a tag id along with the format, data and length of the data and deals with it appropriatly
function dealwithtag($tag, $format, $data, $length, $align) {
$w = false;
$val = "";
switch ($this->format_type[$format]) {
case "STRING":
$val = trim(substr($data, 0, $length));
$w = true;
break;
case "ULONG":
case "SLONG":
$val = $this->enumvalue($this->tagid2name($tag), $this->getnumber($data, 0, 4, $align));
$w = true;
break;
case "USHORT":
case "SSHORT":
switch ($tag) {
case 0x9214:
break;
case 0xa001:
$tmp = $this->getnumber($data, 0, 2, $align);
if ($tmp == 1) {
$val = "sRGB";
$w = true;
} else if ($tmp == 2) {
$val = "Adobe RGB";
$w = true;
} else {
$val = "Uncalibrated";
$w = true;
}
break;
default:
$val = $this->enumvalue($this->tagid2name($tag), $this->getnumber($data, 0, 2, $align));
$w = true;
break;
}
break;
case "URATIONAL":
$val = $this->getrational(substr($data, 0, 8), $align, "U");
$w = true;
break;
case "SRATIONAL":
$val = $this->getrational(substr($data, 0, 8), $align, "S");
$w = true;
break;
case "UNDEFINED":
switch ($tag) {
case 0xa300:
$tmp = $this->getnumber($data, 0, 2, $align);
if ($tmp == 3) {
$val = "Digital Camera";
$w = true;
} else {
$val = "Unknown";
$w = true;
}
break;
case 0xa301:
$tmp = $this->getnumber($data, 0, 2, $align);
if ($tmp == 3) {
$val = "Directly Photographed";
$w = true;
} else {
$val = "Unknown";
$w = true;
}
break;
}
break;
}
if ($w) {
$this->exif_data[$this->tagid2name($tag)] = $val;
}
}
 
// reads the tags from and EXIF IFD and if correct deals with the data
function readEXIFDir($data, $offset_base, $exif_length) {
$value_ptr = 0;
$sofar = 2;
$data_in = "";
$number_dir_entries = $this->getnumber($data, 0, 2, $this->align);
for ($i = 0;$i < $number_dir_entries;$i++) {
$sofar += 12;
$dir_entry = substr($data, 2 + 12 * $i);
$tag = $this->getnumber($dir_entry, 0, 2, $this->align);
$format = $this->getnumber($dir_entry, 2, 2, $this->align);
$components = $this->getnumber($dir_entry, 4, 4, $this->align);
if (($format - 1) >= 12) {
return false;
}
$byte_count = $components * $this->format_length[$format];
if ($byte_count > 4) {
$offset_val = ($this->getnumber($dir_entry, 8, 4, $this->align)) - $offset_base;
if (($offset_val + $byte_count) > $exif_length) {
return false;
}
$data_in = substr($data, $offset_val);
} else {
$data_in = substr($dir_entry, 8);
}
if ($tag == 0x8769) {
$tmp = ($this->getnumber($data_in, 0, 4, $this->align)) - 8;
$this->readEXIFDir(substr($data, $tmp), $tmp + 8 , $exif_length);
} else {
$this->dealwithtag($tag, $format, $data_in, $byte_count, $this->align);
}
}
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_opentag/wordcloud.class.php
@@ -0,0 +1,351 @@
<?php
 
/************************************************************\
*
* wordCloud Copyright 2007 Derek Harvey
* www.lotsofcode.com
*
* This file is part of wordCloud.
*
* wordCloud v2 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wordCloud v2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with wordCloud; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
\************************************************************/
class wordCloud
{
var $version = '2.0';
var $wordsArray = array();
/*
* PHP 5 Constructor
*
* @param array $words
*
* @return void
*/
function __construct($words = false)
{
// If we are trying to parse some works, in any format / type
if ($words !== false) {
// If we have a string
if (is_string($words)) {
$this->addString($words);
} elseif (count($words)) {
foreach ($words as $key => $value) {
$this->addWord($value);
}
}
}
return;
}
/*
* PHP 4 Constructor
*
* @param array $words
*
* @return void
*/
function wordCloud($words = false)
{
return $this->__construct($words);
}
/*
* Convert a string into a cloud
*
* @param string $string
* @return void
*/
function addString($string)
{
// remove all other chars apart from a-z
$string = preg_replace('[^a-z]', '', strip_tags(strtolower($string)));
$words = array();
$words = explode(' ', $string);
if (count($words)) {
foreach ($words as $key => $value) {
$this->addWord($value);
}
}
}
/*
* Display user friendly message, for debugging mainly
*
* @param string $string
* @param array $value
*
* @return bool
*/
function notify($string, $value)
{
echo '<pre>';
print_r($string);
print_r($value);
echo '</pre>';
return false;
}
/*
* Assign word to array
*
* @param string $word
*
* @return string
*/
function addWord($wordAttributes = array())
{
if (is_string($wordAttributes)) {
$wordAttributes = array('word' => $wordAttributes);
}
if (!array_key_exists('size', $wordAttributes)) {
$wordAttributes = array_merge($wordAttributes, array('size' => 1));
}
if (!array_key_exists('word', $wordAttributes)) {
return $this->notify('no word attribute', print_r($wordAttributes, true));
}
$word = strtolower($wordAttributes['word']);
if (empty($this->wordsArray[$word])) {
$this->wordsArray[$word] = array();
}
if (!empty($this->wordsArray[$word]['size']) && !empty($wordAttributes['size'])) {
$wordAttributes['size'] = ($this->wordsArray[$word]['size'] + $wordAttributes['size']);
} elseif (!empty($this->wordsArray[$word]['size'])) {
$wordAttributes['size'] = $this->wordsArray[$word]['size'];
}
$this->wordsArray[$word] = $wordAttributes;
return $this->wordsArray[$word];
}
/*
* Shuffle associated names in array
*
* @return array $this->wordsArray
*/
function shuffleCloud()
{
$keys = array_keys($this->wordsArray);
shuffle($keys);
if (count($keys) && is_array($keys)) {
$tmpArray = $this->wordsArray;
$this->wordsArray = array();
foreach ($keys as $key => $value)
$this->wordsArray[$value] = $tmpArray[$value];
}
return $this->wordsArray;
}
/*
* Get the class range using a percentage
*
* @returns int $class
*/
function getClassFromPercent($percent)
{
if ($percent >= 99)
$class = 9;
elseif ($percent >= 70)
$class = 8;
elseif ($percent >= 60)
$class = 7;
elseif ($percent >= 50)
$class = 6;
elseif ($percent >= 40)
$class = 5;
elseif ($percent >= 30)
$class = 4;
elseif ($percent >= 20)
$class = 3;
elseif ($percent >= 10)
$class = 2;
elseif ($percent >= 5)
$class = 1;
else
$class = 0;
return $class;
}
/*
* Sets a limit for the amount of clouds
*
* @param string $limit
*
* @returns string $this->limitAmount
*/
function setLimit($limit)
{
if (!empty($limit)) {
$this->limitAmount = $limit;
}
return $this->limitAmount;
}
/*
* Gets the limited amount of clouds
*
* @returns string $wordCloud
*/
function limitCloud()
{
$i = 1;
foreach ($this->wordsArray as $key => $value) {
if ($this->limitAmount < $i) {
$wordsArray[$value['word']] = $value;
}
$i++;
}
$this->wordsArray = array();
$this->wordsArray = $wordsArray;
return $this->wordsArray;
}
/*
* Finds the maximum value of an array
*
* @param string $word
*
* @returns void
*/
function removeWord($word)
{
$this->removeWords[] = strtolower($word);
}
/*
* Removes tags from the whole array
*
* @returns array $this->wordsArray
*/
function removeWords()
{
foreach ($this->wordsArray as $key => $value) {
if (!in_array($value['word'], $this->removeWords)) {
$wordsArray[$value['word']] = $value;
}
}
$this->wordsArray = array();
$this->wordsArray = $wordsArray;
return $this->wordsArray;
}
/*
* Assign the order field and order direction of the cloud
*
* @param array $field
* @param string $sortway
*
* @returns void
*/
function orderBy($field, $direction = 'ASC')
{
return $this->orderBy = array('field' => $field, 'direction' => $direction);
}
/*
* Orders the cloud by a specific field
*
* @param array $unsortedArray
* @param string $sortField
* @param string $sortWay
*
* @returns array $unsortedArray
*/
function orderCloud($unsortedArray, $sortField, $sortWay = 'SORT_ASC')
{
$sortedArray = array();
foreach ($unsortedArray as $uniqid => $row) {
foreach ($row as $key => $value) {
$sortedArray[$key][$uniqid] = strtolower($value);
}
}
if ($sortWay) {
array_multisort($sortedArray[$sortField], constant($sortWay), $unsortedArray);
}
return $unsortedArray;
}
/*
* Finds the maximum value of an array
*
* @returns string $max
*/
function getMax()
{
$max = 0;
if (!empty($this->wordsArray)) {
$p_size = 0;
foreach ($this->wordsArray as $cKey => $cVal) {
$c_size = $cVal['size'];
if ($c_size > $p_size) {
$max = $c_size; /* @Thanks Morticus */
$p_size = $c_size;
}
}
}
return $max;
}
/*
* Create the HTML code for each word and apply font size.
*
* @returns string/array $return
*/
function showCloud($returnType = 'html')
{
if (empty($this->orderBy)) {
$this->shuffleCloud();
} else {
$orderDirection = strtolower($this->orderBy['direction']) == 'desc' ? 'SORT_DESC' : 'SORT_ASC';
$this->wordsArray = $this->orderCloud($this->wordsArray, $this->orderBy['field'], $orderDirection);
}
if (!empty($this->limitAmount)) {
$this->limitCloud();
}
if (!empty($this->removeWords)) {
$this->removeWords();
}
$this->max = $this->getMax();
if (is_array($this->wordsArray)) {
$return = ($returnType == 'html' ? '' : ($returnType == 'array' ? array() : ''));
foreach ($this->wordsArray as $word => $arrayInfo) {
$sizeRange = $this->getClassFromPercent(($arrayInfo['size'] / $this->max) * 100);
$arrayInfo['range'] = $sizeRange;
if ($returnType == 'array') {
$return [$word] = $arrayInfo;
} elseif ($returnType == 'html') {
$return .= "<span class='word size{$sizeRange}'> &nbsp; {$arrayInfo['word']} &nbsp; </span>";
}
}
return $return;
}
}
}
?>
New file
/release/Modules-PIO-v6/mod_opentag/howto.txt
@@ -0,0 +1,15 @@
License:
 
wordcloud.class.php is part of wordCloud v2 (http://www.lotsofcode.com/php/tag-cloud-v2.htm).
wordCloud is licensed under GNU General Public License. Copyright ©2007 Derek Harvey.
Because of using wordCloud, mod_opentag is also licensed under GPL. But this module is not a part of Pixmicat!.
 
中文安裝指引:
 
1. 將所有檔案放到 module/ 目錄
2. 修改 config.php,在模組載入區塊下加一行 $ModuleList[] = 'mod_opentag';
 
English Instruction:
 
1. Put all the files into the module/ directory.
2. Use your favorite editor to open the "config.php" and add one line ($ModuleList[] = 'mod_opentag';) into the "Modules to be loaded" block.
New file
/release/Modules-PIO-v6/mod_opentag/mod_opentag.php
@@ -0,0 +1,139 @@
<?php
class mod_opentag{
var $mypage;
 
function mod_opentag(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 向系統登記模組專屬獨立頁面
$this->mypage = $PMS->getModulePageURL(__CLASS__);
}
 
/* Get the name of module */
function getModuleName(){
return 'mod_opentag : 開放標籤編輯';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '4th.Release.4-dev (v100113)';
}
 
function autoHookHead(&$txt, $isReply){
$txt .= '<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
// <![CDATA[
jQuery(function($){
$("div.category a.change").click(function(){
var tag = "";
var no = this.href.match(/&no=([0-9]+)/) ? RegExp.$1 : 0;
var obj = $(this);
obj.siblings("a").each(function(){ tag += "," + $(this).text(); });
obj.parent().html("<input type=\'text\' id=\'attrTag" + no + "\' size=\'28\' /><input type=\'button\' value=\'Tag!\' id=\'sendTag" + no + "\' />");
$g("attrTag" + no).value = tag.substr(1);
$("#sendTag" + no).click(function(){
var tmpthis = this;
$.post("'.str_replace('&amp;', '&', $this->mypage).'&no=" + no, {ajaxmode: true, tag: this.previousSibling.value}, function(newTag){
newTag = $.map(newTag.split(","), function(n){
return n.link("pixmicat.php?mode=category&amp;c=" + encodeURI(n));
});
tmpthis.parentNode.innerHTML = newTag.join(", ");
});
});
return false;
});
});
// ]]>
</script>';
}
 
function autoHookToplink(&$linkbar, $isReply){
$linkbar .= '[<a href="'.$this->mypage.'&amp;action=tagcloud">標籤雲</a>]'."\n";
}
 
function autoHookThreadPost(&$arrLabels, $post, $isReply){
if(USE_CATEGORY) $arrLabels['{$CATEGORY}'] = '<span>'.$arrLabels['{$CATEGORY}'].' [<a href="'.$this->mypage.'&amp;no='.$post['no'].'" class="change">變更</a>]</span>';
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
function ModulePage(){
global $PIO, $PTE;
 
if(isset($_GET['action'])){ // 標籤雲
require './module/wordcloud.class.php';
$pte_vals = array('{$TITLE}'=>TITLE, '{$RESTO}'=>'');
$dat = $PTE->ParseBlock('HEADER', $pte_vals);
$dat .= '<style type="text/css">
.word { padding: 4px 4px 4px 4px; letter-spacing: 3px; text-decoration: none; font-weight: normal; }
.size9 { color: #000 !important; font-size: 200%; }
.size8 { color: #111 !important; font-size: 170%; }
.size7 { color: #222 !important; font-size: 150%; }
.size6 { color: #333 !important; font-size: 120%; }
.size5 { color: #444 !important; font-size: 110%; }
.size4 { color: #555 !important; font-size: 100%; }
.size3 { color: #666 !important; font-size: 90%; }
.size2 { color: #777 !important; font-size: 80%; }
.size1 { color: #888 !important; font-size: 70%; }
.size0 { color: #999 !important; font-size: 60%; }
</style>
</head>
<body id="main">';
 
$p = $PIO->fetchPosts($PIO->fetchPostList());
$cloud = new wordCloud();
foreach($p as $pp){
if($pp['category']){
$pp['category'] = substr(str_replace(array(',', '&#44;'), ' ', $pp['category']), 1, -1);
$cloud->addString($pp['category']);
}
}
 
$myCloud = $cloud->showCloud('array');
if(is_array($myCloud)){
foreach ($myCloud as $key => $value){
$dat .= '<a href="./pixmicat.php?mode=category&c='.urlencode($value['word']).'" class="word size'.$value['range'].'">'.$value['word'].'</a>'."\n";
}
}
echo $dat."</body></html>";
return;
}
if(!isset($_GET['no'])) die('[Error] not enough parameter.');
if(!isset($_POST['tag'])) {
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
$pte_vals = array('{$TITLE}'=>TITLE, '{$RESTO}'=>'');
$dat = $PTE->ParseBlock('HEADER', $pte_vals);
$dat .= '</head><body id="main">';
$dat .= '<form action="'.$this->mypage.'&amp;no='.$_GET['no'].'" method="POST">Tag: <input type="text" name="tag" value="'.htmlentities(substr(str_replace('&#44;', ',', $post[0]['category']),1,-1), ENT_QUOTES, 'UTF-8').'" size="28" /><input type="submit" name="submit" value="Tag!" /></form>';
echo $dat."</body></html>";
} else {
$Tag = CleanStr($_POST['tag']);
if($_SERVER['REQUEST_METHOD'] != 'POST') error(_T('regist_notpost')); // 非正規POST方式
$post = $PIO->fetchPosts($_GET['no']);
$parentNo = $post[0]['resto'] ? $post[0]['resto'] : $post[0]['no'];
$threads = array_flip($PIO->fetchThreadList());
$threadPage = floor($threads[$parentNo] / PAGE_DEF);
if(!count($post)) die('[Error] Post does not exist.');
if(USE_CATEGORY && $Tag){ // 修整標籤樣式
$ss = method_exists($PIO, '_replaceComma') ? '&#44;' : ','; // Dirty implement
$category = explode(',', $Tag); // 把標籤拆成陣列
$category = $ss.implode($ss, array_map('trim', $category)).$ss; // 去空白再合併為單一字串 (左右含,便可以直接以,XX,形式搜尋)
}else{ $category = ''; }
 
$PIO->updatePost($_GET['no'], array('category'=>$category));
$PIO->dbCommit();
if(STATIC_HTML_UNTIL == -1 || $threadPage <= STATIC_HTML_UNTIL) updatelog(0, $threadPage, true); // 僅更新討論串出現那頁
deleteCache(array($parentNo)); // 刪除討論串舊快取
 
if(isset($_POST['ajaxmode'])){
echo $Tag;
}else{
header('HTTP/1.1 302 Moved Temporarily');
header('Location: '.fullURL().PHP_SELF2.'?'.time());
}
}
}
}
?>
New file
/release/Modules-PIO-v6/mod_atom/mod_atom.php
@@ -0,0 +1,177 @@
<?php
/*
mod_atom : 提供Atom Feed訂閱服務
By: scribe + Alica (atom)
*/
 
class mod_atom{
var $FEED_COUNT, $FEED_STATUSFILE, $FEED_CACHEFILE, $FEED_DISPLAYTYPE, $BASEDIR, $SELF;
 
function mod_atom(){
global $PMS;
 
$this->FEED_COUNT = 10; // Feed 產生最大篇數
$this->FEED_UPDATETYPE = 1; // Feed 更新時機 (1: 瀏覽 MODULEPAGE 時更新, 2: 有新文章貼出時更新)
$this->FEED_DISPLAYTYPE = 'T'; // 資料取出形式 (T: 討論串取向, P: 文章取向)
$this->FEED_CACHEFILE = 'feed.atom'; // 資料輸出暫存檔 (靜態快取Feed格式)
 
$this->BASEDIR = fullURL(); // 基底 URL
switch($this->FEED_UPDATETYPE){
case 1: // MODULEPAGE
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 註冊獨立頁面
$this->SELF = $this->BASEDIR.$PMS->getModulePageURL(__CLASS__); // Feed 連結
$this->FEED_STATUSFILE = __CLASS__.'.tmp'; // 資料狀態暫存檔 (檢查資料需不需要更新)
break;
case 2: // Update on RegistAfterCommit
$this->SELF = $this->BASEDIR.$this->FEED_CACHEFILE; // Feed 連結
break;
}
}
 
function getModuleName(){
return __CLASS__.' : 提供Atom Feed訂閱服務';
}
 
function getModuleVersionInfo(){
return '6th.Release (v110331)';
}
 
/* 在頁面加入指向 Feed 的 <link> 標籤*/
function autoHookHead(&$txt, $isReply){
$txt .= '<link rel="alternate" type="application/atom+xml" title="Atom 1.0 Feed" href="'.$this->SELF.'" />'."\n";
}
 
/* 文章儲存後更新 Feed 檔案 ($this->FEED_UPDATETYPE == 2 觸發) */
function autoHookRegistAfterCommit(){
global $PIO;
if($this->FEED_UPDATETYPE == 2){
$PIO->dbPrepare();
$this->GenerateCache(); // 更新 Feed
}
}
 
function autoHookFoot(&$foot){
$foot .= '<div style="position: absolute; top: 10px; left: 10px;"><a href="'.$this->SELF.'">Atom Feed</a></div>
';
}
 
/* 模組獨立頁面 */
function ModulePage(){
global $PIO;
 
$PIO->dbPrepare();
if($this->IsDATAUpdated()) $this->GenerateCache(); // 若資料已更新則也更新Feed快取
$this->RedirectToCache(); // 重導向到靜態快取
}
 
/* 檢查資料有沒有更新 */
function IsDATAUpdated(){
global $PIO;
if(isset($_GET['force'])) return true; // 強迫更新Feed
 
$tmp_fsize = $PIO->getLastPostNo('afterCommit');
$tmp_ssize = file_exists($this->FEED_STATUSFILE) ? file_get_contents($this->FEED_STATUSFILE) : 0; // 讀取狀態暫存資料
if($tmp_fsize == $tmp_ssize) return false; // LastNo 相同,沒有更新
 
$fp = fopen($this->FEED_STATUSFILE, 'w');
stream_set_write_buffer($fp, 0); // 立刻寫入不用緩衝
flock($fp, LOCK_EX); // 鎖定
fwrite($fp, $tmp_fsize); // 更新
flock($fp, LOCK_UN); // 解鎖
fclose($fp);
@chmod($this->FEED_STATUSFILE, 0666); // 可讀可寫
return true; // 有更新過
}
 
/* 生成 / 更新靜態快取Feed檔案 */
function GenerateCache(){
global $PIO, $FileIO;
 
$lastpost = $PIO->fetchPosts($PIO->getLastPostNo('afterCommit'));
$feedupdated = date("c", substr($lastpost[0]['tim'], 0, -3));
switch($this->FEED_DISPLAYTYPE){
case 'T':
$plist = $PIO->fetchThreadList(0, $this->FEED_COUNT); // 取出前n筆討論串首篇編號
$plist_count = count($plist);
// 為何這樣取?避免 SQL-like 自動排序喪失時間順序
$post = array();
for($p = 0; $p < $plist_count; $p++) $post[] = current($PIO->fetchPosts($plist[$p])); // 取出編號文章資料
break;
case 'P':
$plist = $PIO->fetchPostList(0, 0, $this->FEED_COUNT); // 取出前n筆文章編號
$post = $PIO->fetchPosts($plist);
break;
}
$post_count = count($post);
// Atom Feed內容
$tmp_c = '<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-TW">
<title>'.TITLE.'</title>
<id>'.$this->BASEDIR.'</id>
<generator>'.$this->getModuleName().' '.$this->getModuleVersionInfo().'</generator>
<updated>'.$feedupdated.'</updated>
<link href="'.$this->SELF.'" rel="self" type="application/atom+xml" />
';
for($i = 0; $i < $post_count; $i++){
$imglink = ''; // 圖檔
$resto = 0; // 回應
list($no, $resto, $time, $tw, $th, $tim, $ext, $name, $sub, $com) = array(
$post[$i]['no'],
$post[$i]['resto'],
substr($post[$i]['tim'], 0, -3),
$post[$i]['tw'],
$post[$i]['th'],
$post[$i]['tim'],
$post[$i]['ext'],
$post[$i]['name'],
$post[$i]['sub'],
$post[$i]['com']);
 
// 處理資料
if($ext && $FileIO->imageExists($tim.'s.jpg'))
$imglink = '<img src="'.$FileIO->getImageURL($tim.'s.jpg').'" alt="'.$tim.$ext.'" width="'.$tw.'" height="'.$th.'" /><br />';
$time = date("c", $time); // 本地時間ISO8601標準格式
$reslink = $this->BASEDIR.PHP_SELF.'?res='.($resto ? $resto : $no); // 回應連結
switch($this->FEED_DISPLAYTYPE){
case 'T':
$titleBar = $sub.' No.'.$no.' (Res: '.($PIO->postCount($no) - 1).')'; // 標題 No.編號 (Res:回應數)
$threadlastpost = $PIO->fetchPosts(array_pop($PIO->fetchPostList($no)));
$updateTime = date("c", substr($threadlastpost[0]['tim'], 0, -3));
break;
case 'P':
$titleBar = $sub.' ('.$no.')'; // 標題 (編號)
$updateTime = $time;
break;
}
 
$tmp_c .= '<entry>
<title>'.$titleBar.'</title>
<link href="'.$reslink.'" />
<author><name>'.$name.'</name></author>
<content type="html">
<![CDATA[
'.$imglink.$com.'
]]>
</content>
<id>'.$reslink.'#r'.$no.'</id>
<published>'.$time.'</published>
<updated>'.$updateTime.'</updated>
</entry>
';
}
$tmp_c .= '</feed>';
$fp = fopen($this->FEED_CACHEFILE, 'w');
flock($fp, LOCK_EX); // 鎖定
fwrite($fp, $tmp_c); // 更新
flock($fp, LOCK_UN); // 解鎖
fclose($fp);
@chmod($this->FEED_CACHEFILE, 0666); // 可讀可寫
}
 
/* 重導向到靜態快取 */
function RedirectToCache(){
header('HTTP/1.1 302 Moved Temporarily'); // 暫時性導向
header('Location: '.$this->BASEDIR.$this->FEED_CACHEFILE);
}
}
?>
New file

Property changes:

Name: svn:keywords
+ Id Date Author

/release/Modules-PIO-v6/mod_code_prettify/mod_code_prettify.php
@@ -0,0 +1,66 @@
<?php
class mod_code_prettify{
// 是否硬轉換 (直接儲存轉換後的結果,減少系統日後輸出時的多次軟轉換負擔)
// 優點是只需轉換一次,以後不再需要轉換
var $HARD_TRANSLATE = false;
// 硬轉換後是否相容舊 mod_code 繼續軟轉換板上已有之 [code] (因硬轉換啟動後預設不再軟轉換處理)
// 簡單說就是硬/軟轉換並行,這樣硬轉換的好處沒有辦法完全表現出來
var $MOD_CODE_COMPATIBLE = true;
 
function mod_code_prettify() {
global $PMS;
if(method_exists($PMS,'addCHP')) {
$PMS->addCHP('mod_bbbutton_addButtons',array($this,'_addButtons'));
}
}
 
function _addButtons($txt) {
$txt .= 'bbbuttons.tags = $.extend({
code:{desc:"Insert Code block"},
},bbbuttons.tags);';
}
 
function getModuleName(){
return 'mod_code_prettify : google-code-prettify Syntax Highlighting';
}
 
function getModuleVersionInfo(){
return '5th.Release (v100727)';
}
 
function autoHookHead(&$dat){
$dat .= '<link rel="stylesheet" type="text/css" href="module/prettify/prettify.css" />'."\n";
}
 
function autoHookPostInfo(&$postinfo){
$postinfo .= '<li>程式碼可使用 [code][/code] 以 google-code-prettify 標亮 (程式自動判斷語言類別)</li>'."\n";
}
 
// 發文儲存前即進行轉換 (硬轉換)
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status){
if(!$this->HARD_TRANSLATE) return; // 選擇不作硬轉換
if(strpos($com, '[/code]') !== false){
$com = preg_replace('/\[code(?:=(\S*?))?](?:<br \/>)?(.*?)(?:<br \/>)?\[\/code\]/us',
'<pre class="prettyprint linenums">$2</pre>', $com);
}
}
 
// 輸出時才即時轉換 (軟轉換)
function autoHookThreadPost(&$arrLabels, $post, $isReply){
if($this->HARD_TRANSLATE && !$this->MOD_CODE_COMPATIBLE) return; // 不需再做軟轉換 (除非啟動相容模式)
if(strpos($arrLabels['{$COM}'], '[/code]')===false) return;
 
$arrLabels['{$COM}'] = preg_replace('/\[code(?:=(\S*?))?](?:<br \/>)?(.*?)(?:<br \/>)?\[\/code\]/us',
'<pre class="prettyprint linenums">$2</pre>', $arrLabels['{$COM}']);
}
 
function autoHookThreadReply(&$arrLabels, $post, $isReply){
$this->autoHookThreadPost($arrLabels, $post, $isReply);
}
 
function autoHookFoot(&$dat){
$dat .= '<script type="text/javascript" src="module/prettify/prettify.js"></script>
<script type="text/javascript">prettyPrint();</script>'."\n";
}
}
?>
New file
/release/Modules-PIO-v6/mod_code_prettify/howto.txt
@@ -0,0 +1,20 @@
License:
 
google-code-prettify is licensed under Apache License 2.0. http://code.google.com/p/google-code-prettify/
mod_code_prettify is not a part of Pixmicat! package. So it's not licensed under the Clarified Artistic License. It's in the public domain.
 
中文安裝指引:
 
1. 下載 google-code-prettify (http://code.google.com/p/google-code-prettify/) 儲存
2. 將 mod_code_prettify.php, 1. 解壓後的 prettify 目錄放到 module/ 目錄裡
3. 修改 config.php,在模組載入區塊下加一行 $ModuleList[] = 'mod_code_prettify';
4. 如果遇到 XHTML 解析錯誤問題,可將 config.php USE_XHTML 設為 0 取消
5. 若要修改顯示樣式 (顯示行號、改變背景顏色等),可修改 prettify 目錄下的 prettify.css 樣式表
 
English Instruction:
 
1. Download google-code-prettify from the project page (http://code.google.com/p/google-code-prettify/).
2. Put the following files into the module/ directory: "mod_code_prettify.php" and "prettify" folders.
3. Use your favorite editor to open the "config.php" and add one line ($ModuleList[] = 'mod_code_prettify';) into the "Modules to be loaded" block.
4. You can edit config.php and change the value of USE_XHTML to 0 to avoid display problem in XHTML parsing mode.
5. You can edit prettify/prettify.css to meet your need such as showing line number or changing background color.
New file
/release/Modules-PIO-v6/mod_threadlist/mod_threadlist.php
@@ -0,0 +1,197 @@
<?php
/*
mod_threadlist : 討論串列表
By: scribe
*/
 
class mod_threadlist{
var $THREADLIST_NUMBER,$THREADLIST_NUMBER_IN_MAIN,$SHOW_IN_MAIN,$FORCE_SUBJECT,$SHOW_FORM,$HIGHLIGHT_COUNT;
 
function mod_threadlist(){
global $PMS;
$PMS->hookModuleMethod('ModulePage', __CLASS__); // 向系統登記模組專屬獨立頁面
 
$this->THREADLIST_NUMBER = 50; // 一頁顯示列表個數
$this->THREADLIST_NUMBER_IN_MAIN = 20; // 在主頁面顯示列表個數
$this->SHOW_IN_MAIN = true; // 在主頁面顯示
$this->FORCE_SUBJECT = false; // 是否強制開新串要有標題
$this->SHOW_FORM = true; // 是否顯示刪除表單
$this->HIGHLIGHT_COUNT = 30; // 熱門回應數,超過這個值回應數會變紅色 (0 為不使用)
}
 
/* Get the name of module */
function getModuleName(){
return __CLASS__.' : 討論串列表';
}
 
/* Get the module version infomation */
function getModuleVersionInfo(){
return '5th.Release.2 (v110125)';
}
 
function autoHookRegistBeforeCommit(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $isReply, $imgWH, &$status){
if($this->FORCE_SUBJECT && !$isReply && $sub==DEFAULT_NOTITLE) error('發文不可以沒有標題喔', $dest);
}
 
/* 自動掛載:頂部連結列 */
function autoHookToplink(&$linkbar, $isReply){
global $PMS;
$linkbar .= '[<a href="'.$PMS->getModulePageURL('mod_threadlist').'">主題列表</a>]'."\n";
}
 
function autoHookThreadFront(&$txt,$isReply){
global $PMS, $PIO, $FileIO;
if($this->SHOW_IN_MAIN && !$isReply) {
$dat = ''; // HTML Buffer
$plist = $PIO->fetchThreadList(0, $this->THREADLIST_NUMBER_IN_MAIN, true); // 編號由大到小排序
$PMS->useModuleMethods('ThreadOrder', array($isReply,0,0,&$plist)); // "ThreadOrder" Hook Point
$post = $PIO->fetchPosts($plist); // 取出資料
$post_count = ceil(count($post) / 2);
$dat .= '<div id="topiclist" style="text-align: center; clear: both;">
<table cellpadding="1" cellspacing="1" border="0" width="100%" style="margin: 0px auto; text-align: left; margin-bottom: 1em; font-size: 1em;">
<tr><th class="reply_hl" colspan="2" style="text-align: center;">題名一覽</th></tr>
';
for($i = 0; $i < $post_count; $i++){
$leftStr = $post[$i]['no'].': <a href="'.PHP_SELF.'?res='.$post[$i]['no'].'">'.$post[$i]['sub'].' ('.($PIO->postCount($post[$i]['no']) - 1).')</a>';
$rightStr = isset($post[$i + $post_count]) ? $post[$i + $post_count]['no'].': <a href="'.PHP_SELF.'?res='.$post[$i + $post_count]['no'].'">'.$post[$i + $post_count]['sub'].' ('.($PIO->postCount($post[$i + $post_count]['no']) - 1).')</a>' : '';
$dat .= '<tr class="ListRow'.($i % 2 + 1).'_bg"><td style="width: 50%">'.$leftStr.'</td><td>'.$rightStr.'</td></tr>'."\n";
}
$dat .= '</table>
</div>
 
';
$txt .= $dat;
}
}
 
function _getPostCounts($posts) {
global $PIO;
 
$pc = array();
foreach($posts as $post)
$pc[$post] = $PIO->postCount($post);
 
return $pc;
}
 
function _kasort(&$a,$revkey=false,$revval=false) {
$t=$u=array();
foreach($a as $k=>&$v) { // flip array
if(!isset($t[$v])) $t[$v] = array($k);
else $t[$v][] = $k;
}
 
if($revkey) krsort($t);
else ksort($t);
foreach($t as $k=>&$vv) {
if($revval) rsort($vv);
else sort($vv);
}
foreach($t as $k=>&$vv) { // reconstruct array
foreach($vv as &$v)
$u[$v] = $k;
}
$a=$u;
}
 
/* 模組獨立頁面 */
function ModulePage(){
global $PMS, $PIO, $FileIO, $PTE;
 
$thisPage = $PMS->getModulePageURL('mod_threadlist'); // 基底位置
$dat = ''; // HTML Buffer
$listMax = $PIO->threadCount(); // 討論串總筆數
$pageMax = ceil($listMax / $this->THREADLIST_NUMBER) - 1; // 分頁最大編號
$page = isset($_GET['page']) ? intval($_GET['page']) : 0; // 目前所在分頁頁數
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'no';
if($page < 0 || $page > $pageMax) exit('Page out of range.'); // $page 超過範圍
if(strpos($sort, 'post') !== false) {
$plist = $PIO->fetchThreadList();
$pc = $this->_getPostCounts($plist);
$this->_kasort($pc,$sort == 'postdesc',true);
 
$plist = array_keys($pc);
 
$plist = array_slice($plist, $this->THREADLIST_NUMBER * $page, $this->THREADLIST_NUMBER); //切出需要的大小
} else {
$plist = $PIO->fetchThreadList($this->THREADLIST_NUMBER * $page, $this->THREADLIST_NUMBER, $sort == 'date' ? false : true); // 編號由大到小排序
$PMS->useModuleMethods('ThreadOrder', array(0,$page,0,&$plist)); // "ThreadOrder" Hook Point
$pc = $this->_getPostCounts($plist);
}
$post = $PIO->fetchPosts($plist); // 取出資料
$post_count = count($post);
 
if(strpos($sort, 'post') !== false) { // 要重排次序
$mypost = array();
foreach($plist as $p) {
while (list($k, $v) = each($post)) {
if($v['no'] == $p) {
$mypost[] = $v;
unset($post[$k]);
break;
}
}
reset($post);
}
$post = $mypost;
}
 
head($dat);
$dat .= '<div id="contents">
[<a href="'.PHP_SELF2.'?'.time().'">回到版面</a>]
<div class="bar_reply">列表模式</div>'.($this->SHOW_FORM ? '<form action="'.PHP_SELF.'" method="post">' : '').'<table align="center" width="98%"><tr>
'.($this->SHOW_FORM ? '<th></th>' : '').'
<th><a href="'.$thisPage.'&amp;sort=no">No.'.($sort == 'no' ? ' ▼' : '').'</a></th>
<th width="48%">標題</th>
<th>發文者</th>
<th><a href="'.$thisPage.'&amp;sort='.($sort == 'postdesc' ? 'postasc' : 'postdesc').'">回應'.($sort == 'postdesc' ? ' ▼' : ($sort == 'postasc' ? ' ▲' : '')).'</a></th>
<th><a href="'.$thisPage.'&amp;sort=date">日期'.($sort == 'date' ? ' ▼' : '').'</a></th></tr>
';
// 逐步取資料
for($i = 0; $i < $post_count; $i++){
list($no, $sub, $name, $now) = array($post[$i]['no'], $post[$i]['sub'],$post[$i]['name'], $post[$i]['now']);
 
$rescount = $pc[$no] - 1;
if($this->HIGHLIGHT_COUNT > 0 && $rescount > $this->HIGHLIGHT_COUNT){
$rescount = '<span style="color:red">'.$rescount.'</span>';
}
$dat .= '<tr class="ListRow'.($i % 2 + 1).'_bg">'.($this->SHOW_FORM ? '<td><input type="checkbox" name="'.$no.'" value="delete" /></td>' : '').'<td>'.$no.'</td><td><a href="'.PHP_SELF.'?res='.$no.'">'.$sub.'</a></td><td>'.$name.'</td><td>'.$rescount.'</td><td>'.$now.'</td></tr>'."\n";
}
 
$dat .= '</table>
<hr />
 
<div id="page_switch">
<table border="1" style="float: left;"><tr>
';
if($page) $dat .= '<td><a href="'.$thisPage.'&amp;page='.($page - 1).'&amp;sort='.$sort.'">上一頁</a></td>';
else $dat .= '<td style="white-space: nowrap;">第一頁</td>';
$dat .= '<td>';
for($i = 0; $i <= $pageMax; $i++){
if($i==$page) $dat .= '[<b>'.$i.'</b>] ';
else $dat .= '[<a href="'.$thisPage.'&amp;page='.$i.'&amp;sort='.$sort.'">'.$i.'</a>] ';
}
$dat .= '</td>';
if($page < $pageMax) $dat .= '<td><a href="'.$thisPage.'&amp;page='.($page + 1).'&amp;sort='.$sort.'">下一頁</a></td>';
else $dat .= '<td style="white-space: nowrap;">最後一頁</td>';
$dat .= '
</tr></table>
</div>';
if($this->SHOW_FORM) {
$pte_vals = array('{$DEL_HEAD_TEXT}' => '<input type="hidden" name="mode" value="usrdel" />'._T('del_head'),
'{$DEL_IMG_ONLY_FIELD}' => '<input type="checkbox" name="onlyimgdel" id="onlyimgdel" value="on" />',
'{$DEL_IMG_ONLY_TEXT}' => _T('del_img_only'),
'{$DEL_PASS_TEXT}' => _T('del_pass'),
'{$DEL_PASS_FIELD}' => '<input type="password" name="pwd" size="8" value="" />',
'{$DEL_SUBMIT_BTN}' => '<input type="submit" value="'._T('del_btn').'" />');
$dat .= $PTE->ParseBlock('DELFORM', $pte_vals).'</form>';
}
 
$dat .= '</div>';
foot($dat);
echo $dat;
}
}
?>
New file
/release/Modules-PIO-v6/mod_threadorder/mod_threadorder.php
@@ -0,0 +1,203 @@
<?php
class mod_threadorder{
var $TOPMOST_LOG,$BOTTOMMOST_LOG;
function mod_threadorder(){
global $PMS;
$this->TOPMOST_LOG = './topmost.log'; // 置頂紀錄檔位置
$this->BOTTOMMOST_LOG = './buttommost.log'; // 置底紀錄檔位置
$PMS->hookModuleMethod('ModulePage', 'mod_threadorder'); // 向系統登記模組專屬獨立頁面
$this->mypage = $PMS->getModulePageURL('mod_threadorder');
}
 
function getModuleName(){
return 'mod_threadorder : 討論串置頂置底';
}
 
function getModuleVersionInfo(){
return 'v100619';
}
 
function autoHookAdminList(&$modFunc, $post, $isres){
if(!$isres) $modFunc .= '[<a href="'.$this->mypage.'&amp;no='.$post['no'].'&amp;action=top" title="Top most">TM</a>][<a href="'.$this->mypage.'&amp;no='.$post['no'].'&amp;action=bottom" title="Bottom most">BM</a>]';
}
 
function autoHookLinksAboveBar(&$link, $pageId, $addinfo=false) {
if($pageId == 'admin') $link.=' [<a href="'.$this->mypage.'">置頂/置底管理</a>]';
}
 
function _write($file,$data) {
$rp = fopen($file, "w");
flock($rp, LOCK_EX); // 鎖定檔案
@fputs($rp,$data);
flock($rp, LOCK_UN); // 解鎖
fclose($rp);
chmod($file,0666);
}
 
function autoHookThreadOrder($resno,$page_num,$single_page,&$threads){
if($logs=@file($this->TOPMOST_LOG)) { // order asc
// $logs = array_reverse($logs);
foreach($logs as $tm) {
$temp = array_search( $tm=trim($tm), $threads );
if($temp !== NULL && $temp !== FALSE) {
array_splice($threads, $temp, 1);
array_unshift($threads, $tm);
}
}
}
if($logs=@file($this->BOTTOMMOST_LOG)) { // order asc
foreach($logs as $bm) {
$temp = array_search( $bm=trim($bm), $threads );
if($temp !== NULL && $temp !== FALSE) {
array_splice($threads, $temp, 1);
array_push($threads, $bm);
}
}
}
}
function ModulePage(){
global $PIO;
if(!adminAuthenticate('check')) die('403 Access denied');
 
$act=isset($_REQUEST['action'])?$_REQUEST['action']:'';
if($_SERVER['REQUEST_METHOD']=='POST') {
 
if($act=='reorder'){ // 排序
$newTop = explode('|',$_POST['newTopmost']);
$newTop = array_reverse($newTop);
$newTop = trim(implode("\n",$newTop));
$this->_write($this->TOPMOST_LOG,$newTop);
$newBottom = trim(implode("\n",explode('|',$_POST['newBottommost'])));
$this->_write($this->BOTTOMMOST_LOG,$newBottom);
die('Done. Please go back.');
}
}
switch($act) {
case 'top'; // 置頂
if($PIO->isThread($_GET['no'])) {
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
$this->_write($this->TOPMOST_LOG,$_GET['no']."\n".@file_get_contents($this->TOPMOST_LOG));
die('Done. Please go back.');
} else die('[Error] Thread does not exist.');
break;
case 'bottom'; // 置底
if($PIO->isThread($_GET['no'])) {
$post = $PIO->fetchPosts($_GET['no']);
if(!count($post)) die('[Error] Post does not exist.');
$this->_write($this->BOTTOMMOST_LOG,@file_get_contents($this->BOTTOMMOST_LOG).$_GET['no']."\n");
die('Done. Please go back.');
} else die('[Error] Thread does not exist.');
break;
default:
$dat=''; head($dat); echo $dat; $dat='';
echo '<script type="text/javascript">
function move(target,index,to) {
var list = document.getElementById(target);
var total = list.options.length-1;
if (index == -1) return false;
if (to == +1 && index == total) return false;
if (to == -1 && index == 0) return false;
var items = new Array;
var values = new Array;
for (i = total; i >= 0; i--) {
items[i] = list.options[i].text;
values[i] = list.options[i].value;
}
for (i = total; i >= 0; i--) {
if (index == i) {
list.options[i + to] = new Option(items[i],values[i], 0, 1);
list.options[i] = new Option(items[i + to], values[i +to]);
i--;
} else {
list.options[i] = new Option(items[i], values[i]);
}
}
list.focus();
return true;
}
function add(target,name,value){
target.options[target.length] = new Option(name, value);
}
function remove(target){
var list = document.getElementById(target);
var selIndex = list.selectedIndex;
if (selIndex != -1) {
for(i=list.length-1; i>=0; i--)
{
if(list.options[i].selected)
{
list.options[i] = null;
}
}
if (list.length > 0) {
list.selectedIndex = selIndex == 0 ? 0 : selIndex - 1;
}
}
}
function place(){
placeInHidden("|", "topmost", "ntop");
placeInHidden("|", "buttommost", "nbottom");
 
}
function placeInHidden(delim, selStr, hidStr){
var selObj = document.getElementById(selStr);
var hideObj = document.getElementById(hidStr);
hideObj.value = "";
for (i = 0; i <= selObj.options.length-1; i++) {
hideObj.value += selObj.options[i].value + delim;
}
 
}
</script>
<form action='.$this->mypage.' method="post" onsubmit="place()">
<input type="hidden" name="action" value="reorder" />
<table>
<tr>
<td>置頂:</td><td></td><td>置底:</td><td></td>
</tr>
<tr>
<td align="middle">';
echo ' <select id="topmost" size="30">';
$logs=@file($this->TOPMOST_LOG); // order asc
$logs=array_reverse($logs);
foreach($logs as $tm) {
echo ' <option value="'.$tm.'" >'.$tm.'</option>';
}
echo ' </select>
</td>
<td>
<input type="button" value="↑"
onClick="move(\'topmost\',document.getElementById(\'topmost\').selectedIndex,-1)"><br/><br/>
<input type="button" value="↓"
onClick="move(\'topmost\',document.getElementById(\'topmost\').selectedIndex,+1)"><br/><br/>
<input type="button" value="解"
onClick="remove(\'topmost\')">
</td>
<td align="middle">';
echo ' <select id="buttommost" size="30">';
$logs=@file($this->BOTTOMMOST_LOG); // order asc
foreach($logs as $bm) {
echo ' <option value="'.$bm.'" >'.$bm.'</option>';
}
echo ' </select>
</td>
<td>
<input type="button" value="↑"
onClick="move(\'buttommost\',document.getElementById(\'buttommost\').selectedIndex,-1)"><br/><br/>
<input type="button" value="↓"
onClick="move(\'buttommost\',document.getElementById(\'buttommost\').selectedIndex,+1)"><br/><br/>
<input type="button" value="解"
onClick="remove(\'buttommost\')">
</td>
</tr>
<tr><td colspan="4"><input type="hidden" name="newTopmost" id="ntop" value="" /><input type="hidden" name="newBottommost" id="nbottom" value="" />
<input type="hidden" name="action" value="reorder">
<input type="submit">
</td>
</tr>
</table></form>';
$dat=''; foot($dat); echo $dat;
}
}
}