| 1 | <?php |
|---|
| 2 | // GIJOE's Ticket Class (based on Marijuana's Oreteki XOOPS) |
|---|
| 3 | // nobunobu's suggestions are applied |
|---|
| 4 | |
|---|
| 5 | if( ! class_exists( 'XoopsGTicket' ) ) { |
|---|
| 6 | |
|---|
| 7 | class XoopsGTicket { |
|---|
| 8 | |
|---|
| 9 | var $_errors = array() ; |
|---|
| 10 | var $_latest_token = '' ; |
|---|
| 11 | var $messages = array() ; |
|---|
| 12 | |
|---|
| 13 | function XoopsGTicket() |
|---|
| 14 | { |
|---|
| 15 | global $xoopsConfig ; |
|---|
| 16 | |
|---|
| 17 | // language file |
|---|
| 18 | if( defined( 'XOOPS_ROOT_PATH' ) && ! empty( $xoopsConfig['language'] ) && ! strstr( $xoopsConfig['language'] , '/' ) ) { |
|---|
| 19 | if( file_exists( dirname( dirname( __FILE__ ) ) . '/language/' . $xoopsConfig['language'] . '/gticket_messages.phtml' ) ) { |
|---|
| 20 | include dirname( dirname( __FILE__ ) ) . '/language/' . $xoopsConfig['language'] . '/gticket_messages.phtml' ; |
|---|
| 21 | } |
|---|
| 22 | } |
|---|
| 23 | |
|---|
| 24 | // default messages |
|---|
| 25 | if( empty( $this->messages ) ) $this->messages = array( |
|---|
| 26 | 'err_general' => 'GTicket Error' , |
|---|
| 27 | 'err_nostubs' => 'No stubs found' , |
|---|
| 28 | 'err_noticket' => 'No ticket found' , |
|---|
| 29 | 'err_nopair' => 'No valid ticket-stub pair found' , |
|---|
| 30 | 'err_timeout' => 'Time out' , |
|---|
| 31 | 'err_areaorref' => 'Invalid area or referer' , |
|---|
| 32 | 'fmt_prompt4repost' => 'error(s) found:<br /><span style="background-color:red;font-weight:bold;color:white;">%s</span><br />Confirm it.<br />And do you want to post again?' , |
|---|
| 33 | 'btn_repost' => 'repost' , |
|---|
| 34 | ) ; |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | // render form as plain html |
|---|
| 38 | function getTicketHtml( $salt = '' , $timeout = 1800 , $area = '' ) |
|---|
| 39 | { |
|---|
| 40 | return '<input type="hidden" name="XOOPS_G_TICKET" value="'.$this->issue( $salt , $timeout , $area ).'" />' ; |
|---|
| 41 | } |
|---|
| 42 | |
|---|
| 43 | // returns an object of XoopsFormHidden including theh ticket |
|---|
| 44 | function getTicketXoopsForm( $salt = '' , $timeout = 1800 , $area = '' ) |
|---|
| 45 | { |
|---|
| 46 | return new XoopsFormHidden( 'XOOPS_G_TICKET' , $this->issue( $salt , $timeout , $area ) ) ; |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | // add a ticket as Hidden Element into XoopsForm |
|---|
| 50 | function addTicketXoopsFormElement( &$form , $salt = '' , $timeout = 1800 , $area = '' ) |
|---|
| 51 | { |
|---|
| 52 | $form->addElement( new XoopsFormHidden( 'XOOPS_G_TICKET' , $this->issue( $salt , $timeout , $area ) ) ) ; |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | // returns an array for xoops_confirm() ; |
|---|
| 56 | function getTicketArray( $salt = '' , $timeout = 1800 , $area = '' ) |
|---|
| 57 | { |
|---|
| 58 | return array( 'XOOPS_G_TICKET' => $this->issue( $salt , $timeout , $area ) ) ; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | // return GET parameter string. |
|---|
| 62 | function getTicketParamString( $salt = '' , $noamp = false , $timeout=1800 , $area = '' ) |
|---|
| 63 | { |
|---|
| 64 | return ( $noamp ? '' : '&' ) . 'XOOPS_G_TICKET=' . $this->issue( $salt, $timeout , $area ) ; |
|---|
| 65 | } |
|---|
| 66 | |
|---|
| 67 | // issue a ticket |
|---|
| 68 | function issue( $salt = '' , $timeout = 1800 , $area = '' ) |
|---|
| 69 | { |
|---|
| 70 | global $xoopsModule ; |
|---|
| 71 | |
|---|
| 72 | // create a token |
|---|
| 73 | list( $usec , $sec ) = explode( " " , microtime() ) ; |
|---|
| 74 | $appendix_salt = empty( $_SERVER['PATH'] ) ? XOOPS_DB_NAME : $_SERVER['PATH'] ; |
|---|
| 75 | $token = crypt( $salt . $usec . $appendix_salt . $sec ) ; |
|---|
| 76 | $this->_latest_token = $token ; |
|---|
| 77 | |
|---|
| 78 | if( empty( $_SESSION['XOOPS_G_STUBS'] ) ) $_SESSION['XOOPS_G_STUBS'] = array() ; |
|---|
| 79 | |
|---|
| 80 | // limit max stubs 10 |
|---|
| 81 | if( sizeof( $_SESSION['XOOPS_G_STUBS'] ) > 10 ) { |
|---|
| 82 | $_SESSION['XOOPS_G_STUBS'] = array_slice( $_SESSION['XOOPS_G_STUBS'] , -10 ) ; |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | // record referer if browser send it |
|---|
| 86 | $referer = empty( $_SERVER['HTTP_REFERER'] ) ? '' : $_SERVER['REQUEST_URI'] ; |
|---|
| 87 | |
|---|
| 88 | // area as module's dirname |
|---|
| 89 | if( ! $area && is_object( @$xoopsModule ) ) { |
|---|
| 90 | $area = $xoopsModule->getVar('dirname') ; |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | // store stub |
|---|
| 94 | $_SESSION['XOOPS_G_STUBS'][] = array( |
|---|
| 95 | 'expire' => time() + $timeout , |
|---|
| 96 | 'referer' => $referer , |
|---|
| 97 | 'area' => $area , |
|---|
| 98 | 'token' => $token |
|---|
| 99 | ) ; |
|---|
| 100 | |
|---|
| 101 | // paid md5ed token as a ticket |
|---|
| 102 | return md5( $token . XOOPS_DB_PREFIX ) ; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | // check a ticket |
|---|
| 106 | function check( $post = true , $area = '' , $allow_repost = true ) |
|---|
| 107 | { |
|---|
| 108 | global $xoopsModule ; |
|---|
| 109 | |
|---|
| 110 | $this->_errors = array() ; |
|---|
| 111 | |
|---|
| 112 | // CHECK: stubs are not stored in session |
|---|
| 113 | if( ! is_array(@$_SESSION['XOOPS_G_STUBS'])) { |
|---|
| 114 | $this->_errors[] = $this->messages['err_nostubs'] ; |
|---|
| 115 | $_SESSION['XOOPS_G_STUBS'] = array() ; |
|---|
| 116 | } |
|---|
| 117 | |
|---|
| 118 | // get key&val of the ticket from a user's query |
|---|
| 119 | $ticket = $post ? @$_POST['XOOPS_G_TICKET'] : @$_GET['XOOPS_G_TICKET'] ; |
|---|
| 120 | |
|---|
| 121 | // CHECK: no tickets found |
|---|
| 122 | if( empty( $ticket ) ) { |
|---|
| 123 | $this->_errors[] = $this->messages['err_noticket'] ; |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | // gargage collection & find a right stub |
|---|
| 127 | $stubs_tmp = $_SESSION['XOOPS_G_STUBS'] ; |
|---|
| 128 | $_SESSION['XOOPS_G_STUBS'] = array() ; |
|---|
| 129 | foreach( $stubs_tmp as $stub ) { |
|---|
| 130 | // default lifetime 30min |
|---|
| 131 | if( $stub['expire'] >= time() ) { |
|---|
| 132 | if( md5( $stub['token'] . XOOPS_DB_PREFIX ) === $ticket ) { |
|---|
| 133 | $found_stub = $stub ; |
|---|
| 134 | } else { |
|---|
| 135 | // store the other valid stubs into session |
|---|
| 136 | $_SESSION['XOOPS_G_STUBS'][] = $stub ; |
|---|
| 137 | } |
|---|
| 138 | } else { |
|---|
| 139 | if( md5( $stub['token'] . XOOPS_DB_PREFIX ) === $ticket ) { |
|---|
| 140 | // not CSRF but Time-Out |
|---|
| 141 | $timeout_flag = true ; |
|---|
| 142 | } |
|---|
| 143 | } |
|---|
| 144 | } |
|---|
| 145 | |
|---|
| 146 | // CHECK: the right stub found or not |
|---|
| 147 | if( empty( $found_stub ) ) { |
|---|
| 148 | if( empty( $timeout_flag ) ) $this->_errors[] = $this->messages['err_nopair'] ; |
|---|
| 149 | else $this->_errors[] = $this->messages['err_timeout'] ; |
|---|
| 150 | } else { |
|---|
| 151 | |
|---|
| 152 | // set area if necessary |
|---|
| 153 | // area as module's dirname |
|---|
| 154 | if( ! $area && is_object( @$xoopsModule ) ) { |
|---|
| 155 | $area = $xoopsModule->getVar('dirname') ; |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | // check area or referer |
|---|
| 159 | if( @$found_stub['area'] == $area ) $area_check = true ; |
|---|
| 160 | if( ! empty( $found_stub['referer'] ) && strstr( @$_SERVER['HTTP_REFERER'] , $found_stub['referer'] ) ) $referer_check = true ; |
|---|
| 161 | |
|---|
| 162 | if( empty( $area_check ) && empty( $referer_check ) ) { // loose |
|---|
| 163 | $this->_errors[] = $this->messages['err_areaorref'] ; |
|---|
| 164 | } |
|---|
| 165 | } |
|---|
| 166 | |
|---|
| 167 | if( ! empty( $this->_errors ) ) { |
|---|
| 168 | if( $allow_repost ) { |
|---|
| 169 | // repost form |
|---|
| 170 | $this->draw_repost_form( $area ) ; |
|---|
| 171 | exit ; |
|---|
| 172 | } else { |
|---|
| 173 | // failed |
|---|
| 174 | $this->clear() ; |
|---|
| 175 | return false ; |
|---|
| 176 | } |
|---|
| 177 | } else { |
|---|
| 178 | // all green |
|---|
| 179 | return true; |
|---|
| 180 | } |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | // draw form for repost |
|---|
| 184 | function draw_repost_form( $area = '' ) |
|---|
| 185 | { |
|---|
| 186 | // Notify which file is broken |
|---|
| 187 | if( headers_sent() ) { |
|---|
| 188 | restore_error_handler() ; |
|---|
| 189 | set_error_handler( 'GTicket_ErrorHandler4FindOutput' ) ; |
|---|
| 190 | header( 'Dummy: for warning' ) ; |
|---|
| 191 | restore_error_handler() ; |
|---|
| 192 | exit ; |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | error_reporting( 0 ) ; |
|---|
| 196 | while( ob_get_level() ) ob_end_clean() ; |
|---|
| 197 | |
|---|
| 198 | $table = '<table>' ; |
|---|
| 199 | $form = '<form action="?'.htmlspecialchars(@$_SERVER['QUERY_STRING'],ENT_QUOTES).'" method="post" >' ; |
|---|
| 200 | foreach( $_POST as $key => $val ) { |
|---|
| 201 | if( $key == 'XOOPS_G_TICKET' ) continue ; |
|---|
| 202 | if( get_magic_quotes_gpc() ) { |
|---|
| 203 | $key = stripslashes( $key ) ; |
|---|
| 204 | } |
|---|
| 205 | if( is_array( $val ) ) { |
|---|
| 206 | list( $tmp_table , $tmp_form ) = $this->extract_post_recursive( htmlspecialchars($key,ENT_QUOTES) , $val ) ; |
|---|
| 207 | $table .= $tmp_table ; |
|---|
| 208 | $form .= $tmp_form ; |
|---|
| 209 | } else { |
|---|
| 210 | if( get_magic_quotes_gpc() ) { |
|---|
| 211 | $val = stripslashes( $val ) ; |
|---|
| 212 | } |
|---|
| 213 | $table .= '<tr><th>'.htmlspecialchars($key,ENT_QUOTES).'</th><td>'.htmlspecialchars($val,ENT_QUOTES).'</td></tr>'."\n" ; |
|---|
| 214 | $form .= '<input type="hidden" name="'.htmlspecialchars($key,ENT_QUOTES).'" value="'.htmlspecialchars($val,ENT_QUOTES).'" />'."\n" ; |
|---|
| 215 | } |
|---|
| 216 | } |
|---|
| 217 | $table .= '</table>' ; |
|---|
| 218 | $form .= $this->getTicketHtml(__LINE__,300,$area).'<input type="submit" value="'.$this->messages['btn_repost'].'" /></form>' ; |
|---|
| 219 | |
|---|
| 220 | echo '<html><head><title>'.$this->messages['err_general'].'</title><style>table,td,th {border:solid black 1px; border-collapse:collapse;}</style></head><body>' . sprintf( $this->messages['fmt_prompt4repost'] , $this->getErrors() ) . $table . $form . '</body></html>' ; |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | function extract_post_recursive( $key_name , $tmp_array ) { |
|---|
| 224 | $table = '' ; |
|---|
| 225 | $form = '' ; |
|---|
| 226 | foreach( $tmp_array as $key => $val ) { |
|---|
| 227 | if( get_magic_quotes_gpc() ) { |
|---|
| 228 | $key = stripslashes( $key ) ; |
|---|
| 229 | } |
|---|
| 230 | if( is_array( $val ) ) { |
|---|
| 231 | list( $tmp_table , $tmp_form ) = $this->extract_post_recursive( $key_name.'['.htmlspecialchars($key,ENT_QUOTES).']' , $val ) ; |
|---|
| 232 | $table .= $tmp_table ; |
|---|
| 233 | $form .= $tmp_form ; |
|---|
| 234 | } else { |
|---|
| 235 | if( get_magic_quotes_gpc() ) { |
|---|
| 236 | $val = stripslashes( $val ) ; |
|---|
| 237 | } |
|---|
| 238 | $table .= '<tr><th>'.$key_name.'['.htmlspecialchars($key,ENT_QUOTES).']</th><td>'.htmlspecialchars($val,ENT_QUOTES).'</td></tr>'."\n" ; |
|---|
| 239 | $form .= '<input type="hidden" name="'.$key_name.'['.htmlspecialchars($key,ENT_QUOTES).']" value="'.htmlspecialchars($val,ENT_QUOTES).'" />'."\n" ; |
|---|
| 240 | } |
|---|
| 241 | } |
|---|
| 242 | return array( $table , $form ) ; |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | |
|---|
| 246 | // clear all stubs |
|---|
| 247 | function clear() |
|---|
| 248 | { |
|---|
| 249 | $_SESSION['XOOPS_G_STUBS'] = array() ; |
|---|
| 250 | } |
|---|
| 251 | |
|---|
| 252 | |
|---|
| 253 | // Ticket Using |
|---|
| 254 | function using() |
|---|
| 255 | { |
|---|
| 256 | if( ! empty( $_SESSION['XOOPS_G_STUBS'] ) ) { |
|---|
| 257 | return true; |
|---|
| 258 | } else { |
|---|
| 259 | return false; |
|---|
| 260 | } |
|---|
| 261 | } |
|---|
| 262 | |
|---|
| 263 | |
|---|
| 264 | // return errors |
|---|
| 265 | function getErrors( $ashtml = true ) |
|---|
| 266 | { |
|---|
| 267 | if( $ashtml ) { |
|---|
| 268 | $ret = '' ; |
|---|
| 269 | foreach( $this->_errors as $msg ) { |
|---|
| 270 | $ret .= "$msg<br />\n" ; |
|---|
| 271 | } |
|---|
| 272 | } else { |
|---|
| 273 | $ret = $this->_errors ; |
|---|
| 274 | } |
|---|
| 275 | return $ret ; |
|---|
| 276 | } |
|---|
| 277 | |
|---|
| 278 | // end of class |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | function GTicket_ErrorHandler4FindOutput($errNo, $errStr, $errFile, $errLine) |
|---|
| 282 | { |
|---|
| 283 | if( preg_match( '?'.preg_quote(XOOPS_ROOT_PATH).'([^:]+)\:(\d+)?' , $errStr , $regs ) ) { |
|---|
| 284 | echo "Irregular output! check the file ".htmlspecialchars($regs[1])." line ".htmlspecialchars($regs[2]) ; |
|---|
| 285 | } else { |
|---|
| 286 | echo "Irregular output! check language files etc." ; |
|---|
| 287 | } |
|---|
| 288 | return ; |
|---|
| 289 | } |
|---|
| 290 | |
|---|
| 291 | // create a instance in global scope |
|---|
| 292 | $GLOBALS['xoopsGTicket'] = new XoopsGTicket() ; |
|---|
| 293 | |
|---|
| 294 | } |
|---|
| 295 | |
|---|
| 296 | if( ! function_exists( 'admin_refcheck' ) ) { |
|---|
| 297 | |
|---|
| 298 | //Admin Referer Check By Marijuana(Rev.011) |
|---|
| 299 | function admin_refcheck($chkref = "") { |
|---|
| 300 | if( empty( $_SERVER['HTTP_REFERER'] ) ) { |
|---|
| 301 | return true ; |
|---|
| 302 | } else { |
|---|
| 303 | $ref = $_SERVER['HTTP_REFERER']; |
|---|
| 304 | } |
|---|
| 305 | $cr = XOOPS_URL; |
|---|
| 306 | if ( $chkref != "" ) { $cr .= $chkref; } |
|---|
| 307 | if ( strpos($ref, $cr) !== 0 ) { return false; } |
|---|
| 308 | return true; |
|---|
| 309 | } |
|---|
| 310 | |
|---|
| 311 | } |
|---|
| 312 | |
|---|
| 313 | |
|---|
| 314 | ?> |
|---|