| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php // $Id: authorizenetlib.php,v 1.32.2.2 2008/09/27 00:40:00 ethem Exp $ 2 3 if (!defined('MOODLE_INTERNAL')) { 4 die('Direct access to this script is forbidden.'); 5 } 6 7 define('AN_DELIM', '|'); 8 define('AN_ENCAP', '"'); 9 10 define('AN_REASON_NOCCTYPE', 17); 11 define('AN_REASON_NOCCTYPE2', 28); 12 define('AN_REASON_NOACH', 18); 13 define('AN_REASON_ACHONLY', 56); 14 define('AN_REASON_NOACHTYPE', 245); 15 define('AN_REASON_NOACHTYPE2', 246); 16 17 require_once($CFG->dirroot.'/enrol/authorize/const.php'); 18 require_once($CFG->dirroot.'/enrol/authorize/localfuncs.php'); 19 20 /** 21 * Gets settlement date and time 22 * 23 * @param int $time Time processed, usually now. 24 * @return int Settlement date and time 25 */ 26 function authorize_getsettletime($time) 27 { 28 global $CFG; 29 30 $cutoff = intval($CFG->an_cutoff); 31 $mins = $cutoff % 60; 32 $hrs = ($cutoff - $mins) / 60; 33 $cutofftime = strtotime("$hrs:$mins", $time); 34 if ($cutofftime < $time) { 35 $cutofftime = strtotime("$hrs:$mins", $time + (24 * 3600)); 36 } 37 return $cutofftime; 38 } 39 40 /** 41 * Is order settled? Status must be auth_captured or credited. 42 * 43 * @param object $order Order details 44 * @return bool true, if settled, false otherwise. 45 */ 46 function authorize_settled($order) 47 { 48 return (($order->status == AN_STATUS_AUTHCAPTURE || $order->status == AN_STATUS_CREDIT) && 49 ($order->settletime > 0) && ($order->settletime < time())); 50 } 51 52 /** 53 * Is order expired? 'Authorized/Pending Capture' transactions are expired after 30 days. 54 * 55 * @param object &$order Order details. 56 * @return bool true, transaction is expired, false otherwise. 57 */ 58 function authorize_expired(&$order) 59 { 60 static $timediff30; 61 62 if ($order->status == AN_STATUS_EXPIRE) { 63 return true; 64 } 65 elseif ($order->status != AN_STATUS_AUTH) { 66 return false; 67 } 68 69 if (empty($timediff30)) { 70 $timediff30 = authorize_getsettletime(time()) - (30 * 24 * 3600); 71 } 72 73 $isexpired = (authorize_getsettletime($order->timecreated) < $timediff30); 74 if ($isexpired) { 75 $order->status = AN_STATUS_EXPIRE; 76 update_record('enrol_authorize', $order); 77 } 78 return $isexpired; 79 } 80 81 /** 82 * Performs an action on authorize.net and updates/inserts records. If record update fails, 83 * sends email to admin. 84 * 85 * @param object &$order Which transaction data will be sent. See enrol_authorize table. 86 * @param string &$message Information about error message. 87 * @param object &$extra Extra data that used for refunding and credit card information. 88 * @param int $action Which action will be performed. See AN_ACTION_* 89 * @param string $cctype Used internally to configure credit types automatically. 90 * @return int AN_APPROVED Transaction was successful, AN_RETURNZERO otherwise. Use $message for reason. 91 * @author Ethem Evlice <ethem a.t evlice d.o.t com> 92 * @uses $CFG 93 */ 94 function authorize_action(&$order, &$message, &$extra, $action=AN_ACTION_NONE, $cctype=NULL) 95 { 96 global $CFG; 97 static $conststring; 98 99 if (!isset($conststring)) { 100 $mconfig = get_config('enrol/authorize'); 101 $constdata = array( 102 'x_version' => '3.1', 103 'x_delim_data' => 'True', 104 'x_delim_char' => AN_DELIM, 105 'x_encap_char' => AN_ENCAP, 106 'x_relay_response' => 'FALSE', 107 'x_login' => rc4decrypt($mconfig->an_login) 108 ); 109 $str = ''; 110 foreach($constdata as $ky => $vl) { 111 $str .= $ky . '=' . urlencode($vl) . '&'; 112 } 113 $str .= (!empty($mconfig->an_tran_key)) ? 114 'x_tran_key=' . urlencode(rc4decrypt($mconfig->an_tran_key)): 115 'x_password=' . urlencode(rc4decrypt($mconfig->an_password)); 116 117 $conststring = $str; 118 $str = ''; 119 } 120 121 if (empty($order) or empty($order->id)) { 122 $message = "Check order->id!"; 123 return AN_RETURNZERO; 124 } 125 126 $method = $order->paymentmethod; 127 if (empty($method)) { 128 $method = AN_METHOD_CC; 129 } 130 elseif ($method != AN_METHOD_CC && $method != AN_METHOD_ECHECK) { 131 $message = "Invalid method: $method"; 132 return AN_RETURNZERO; 133 } 134 135 $action = intval($action); 136 if ($method == AN_METHOD_ECHECK) { 137 if ($action != AN_ACTION_AUTH_CAPTURE && $action != AN_ACTION_CREDIT) { 138 $message = "Please perform AUTH_CAPTURE or CREDIT for echecks"; 139 return AN_RETURNZERO; 140 } 141 } 142 143 $poststring = $conststring; 144 $poststring .= '&x_method=' . $method; 145 146 $test = !empty($CFG->an_test); 147 $poststring .= '&x_test_request=' . ($test ? 'TRUE' : 'FALSE'); 148 149 switch ($action) { 150 case AN_ACTION_AUTH_ONLY: 151 case AN_ACTION_CAPTURE_ONLY: 152 case AN_ACTION_AUTH_CAPTURE: 153 { 154 if ($order->status != AN_STATUS_NONE) { 155 $message = "Order status must be AN_STATUS_NONE(0)!"; 156 return AN_RETURNZERO; 157 } 158 elseif (empty($extra)) { 159 $message = "Need extra fields!"; 160 return AN_RETURNZERO; 161 } 162 elseif (($action == AN_ACTION_CAPTURE_ONLY) and empty($extra->x_auth_code)) { 163 $message = "x_auth_code is required for capture only transactions!"; 164 return AN_RETURNZERO; 165 } 166 167 $ext = (array)$extra; 168 $poststring .= '&x_type=' . (($action==AN_ACTION_AUTH_ONLY) 169 ? 'AUTH_ONLY' :( ($action==AN_ACTION_CAPTURE_ONLY) 170 ? 'CAPTURE_ONLY' : 'AUTH_CAPTURE')); 171 foreach($ext as $k => $v) { 172 $poststring .= '&' . $k . '=' . urlencode($v); 173 } 174 break; 175 } 176 177 case AN_ACTION_PRIOR_AUTH_CAPTURE: 178 { 179 if ($order->status != AN_STATUS_AUTH) { 180 $message = "Order status must be authorized!"; 181 return AN_RETURNZERO; 182 } 183 if (authorize_expired($order)) { 184 $message = "Transaction must be captured within 30 days. EXPIRED!"; 185 return AN_RETURNZERO; 186 } 187 $poststring .= '&x_type=PRIOR_AUTH_CAPTURE&x_trans_id=' . urlencode($order->transid); 188 break; 189 } 190 191 case AN_ACTION_CREDIT: 192 { 193 if ($order->status != AN_STATUS_AUTHCAPTURE) { 194 $message = "Order status must be authorized/captured!"; 195 return AN_RETURNZERO; 196 } 197 if (!authorize_settled($order)) { 198 $message = "Order must be settled. Try VOID, check Cut-Off time if it fails!"; 199 return AN_RETURNZERO; 200 } 201 if (empty($extra->amount)) { 202 $message = "No valid amount!"; 203 return AN_RETURNZERO; 204 } 205 $timenowsettle = authorize_getsettletime(time()); 206 $timediff = $timenowsettle - (120 * 3600 * 24); 207 if ($order->settletime < $timediff) { 208 $message = "Order must be credited within 120 days!"; 209 return AN_RETURNZERO; 210 } 211 212 $poststring .= '&x_type=CREDIT&x_trans_id=' . urlencode($order->transid); 213 $poststring .= '&x_currency_code=' . urlencode($order->currency); 214 $poststring .= '&x_invoice_num=' . urlencode($extra->orderid); 215 $poststring .= '&x_amount=' . urlencode($extra->amount); 216 if ($method == AN_METHOD_CC) { 217 $poststring .= '&x_card_num=' . sprintf("%04d", intval($order->refundinfo)); 218 } 219 elseif ($method == AN_METHOD_ECHECK && empty($order->refundinfo)) { 220 $message = "Business checkings can be refunded only."; 221 return AN_RETURNZERO; 222 } 223 break; 224 } 225 226 case AN_ACTION_VOID: 227 { 228 if (authorize_expired($order) || authorize_settled($order)) { 229 $message = "The transaction cannot be voided due to the fact that it is expired or settled."; 230 return AN_RETURNZERO; 231 } 232 $poststring .= '&x_type=VOID&x_trans_id=' . urlencode($order->transid); 233 break; 234 } 235 236 default: { 237 $message = "Invalid action: $action"; 238 return AN_RETURNZERO; 239 } 240 } 241 242 $referer = ''; 243 if (! (empty($CFG->an_referer) || $CFG->an_referer == "http://")) { 244 $referer = "Referer: $CFG->an_referer\r\n"; 245 } 246 247 $errno = 0; $errstr = ''; 248 $host = $test ? 'certification.authorize.net' : 'secure.authorize.net'; 249 $fp = fsockopen("ssl://$host", 443, $errno, $errstr, 60); 250 if (!$fp) { 251 $message = "no connection: $errstr ($errno)"; 252 return AN_RETURNZERO; 253 } 254 255 // critical section 256 @ignore_user_abort(true); 257 if (intval(ini_get('max_execution_time')) > 0) { 258 @set_time_limit(300); 259 } 260 261 fwrite($fp, "POST /gateway/transact.dll HTTP/1.0\r\n" . 262 "Host: $host\r\n" . $referer . 263 "Content-type: application/x-www-form-urlencoded\r\n" . 264 "Connection: close\r\n" . 265 "Content-length: " . strlen($poststring) . "\r\n\r\n" . 266 $poststring . "\r\n" 267 ); 268 269 $tmpstr = ''; 270 while(!feof($fp) && !stristr($tmpstr, 'content-length')) { 271 $tmpstr = fgets($fp, 4096); 272 } 273 if (!stristr($tmpstr, 'content-length')) { 274 $message = "content-length error"; 275 @fclose($fp); 276 return AN_RETURNZERO; 277 } 278 $length = trim(substr($tmpstr, strpos($tmpstr,'content-length')+15)); 279 fgets($fp, 4096); 280 $data = fgets($fp, $length); 281 @fclose($fp); 282 $response = explode(AN_ENCAP.AN_DELIM.AN_ENCAP, $data); 283 if ($response === false) { 284 $message = "response error"; 285 return AN_RETURNZERO; 286 } 287 $rcount = count($response) - 1; 288 if ($response[0]{0} == AN_ENCAP) { 289 $response[0] = substr($response[0], 1); 290 } 291 if (substr($response[$rcount], -1) == AN_ENCAP) { 292 $response[$rcount] = substr($response[$rcount], 0, -1); 293 } 294 295 $responsecode = intval($response[0]); 296 if ($responsecode == AN_APPROVED || $responsecode == AN_REVIEW) 297 { 298 $transid = floatval($response[6]); 299 if ($test || $transid == 0) { 300 return $responsecode; // don't update original transaction in test mode. 301 } 302 switch ($action) { 303 case AN_ACTION_AUTH_ONLY: 304 case AN_ACTION_CAPTURE_ONLY: 305 case AN_ACTION_AUTH_CAPTURE: 306 case AN_ACTION_PRIOR_AUTH_CAPTURE: 307 { 308 $order->transid = $transid; 309 310 if ($method == AN_METHOD_CC) { 311 if ($action == AN_ACTION_AUTH_ONLY || $responsecode == AN_REVIEW) { 312 $order->status = AN_STATUS_AUTH; 313 } else { 314 $order->status = AN_STATUS_AUTHCAPTURE; 315 $order->settletime = authorize_getsettletime(time()); 316 } 317 } 318 elseif ($method == AN_METHOD_ECHECK) { 319 $order->status = AN_STATUS_UNDERREVIEW; 320 } 321 322 if (! update_record('enrol_authorize', $order)) { 323 email_to_admin("Error while trying to update data " . 324 "in table enrol_authorize. Please edit manually this record: ID=$order->id.", $order); 325 } 326 break; 327 } 328 case AN_ACTION_CREDIT: 329 { 330 // Credit generates new transaction id. 331 // So, $extra must be updated, not $order. 332 $extra->status = AN_STATUS_CREDIT; 333 $extra->transid = $transid; 334 $extra->settletime = authorize_getsettletime(time()); 335 if (! $extra->id = insert_record('enrol_authorize_refunds', $extra)) { 336 unset($extra->id); 337 email_to_admin("Error while trying to insert data " . 338 "into table enrol_authorize_refunds. Please add manually this record:", $extra); 339 } 340 break; 341 } 342 case AN_ACTION_VOID: 343 { 344 $tableupdate = 'enrol_authorize'; 345 if ($order->status == AN_STATUS_CREDIT) { 346 $tableupdate = 'enrol_authorize_refunds'; 347 unset($order->paymentmethod); 348 } 349 $order->status = AN_STATUS_VOID; 350 if (! update_record($tableupdate, $order)) { 351 email_to_admin("Error while trying to update data " . 352 "in table $tableupdate. Please edit manually this record: ID=$order->id.", $order); 353 } 354 break; 355 } 356 } 357 } 358 else 359 { 360 $reasonno = $response[2]; 361 $reasonstr = "reason" . $reasonno; 362 $message = get_string($reasonstr, "enrol_authorize"); 363 if ($message == '[[' . $reasonstr . ']]') { 364 $message = isset($response[3]) ? $response[3] : 'unknown error'; 365 } 366 if ($method == AN_METHOD_CC && !empty($CFG->an_avs) && $response[5] != "P") { 367 $avs = "avs" . strtolower($response[5]); 368 $stravs = get_string($avs, "enrol_authorize"); 369 $message .= "<br />" . get_string("avsresult", "enrol_authorize", $stravs); 370 } 371 if (!$test) { // Autoconfigure :) 372 switch($reasonno) { 373 // Credit card type isn't accepted 374 case AN_REASON_NOCCTYPE: 375 case AN_REASON_NOCCTYPE2: 376 { 377 if (!empty($cctype)) { 378 $ccaccepts = get_list_of_creditcards(); 379 unset($ccaccepts[$cctype]); 380 set_config('an_acceptccs', implode(',', array_keys($ccaccepts))); 381 email_to_admin("$message ($cctype)" . 382 "This is new config(an_acceptccs):", $ccaccepts); 383 } 384 break; 385 } 386 // Echecks only 387 case AN_REASON_ACHONLY: 388 { 389 set_config('an_acceptmethods', AN_METHOD_ECHECK); 390 email_to_admin("$message " . 391 "This is new config(an_acceptmethods):", array(AN_METHOD_ECHECK)); 392 break; 393 } 394 // Echecks aren't accepted 395 case AN_REASON_NOACH: 396 { 397 set_config('an_acceptmethods', AN_METHOD_CC); 398 email_to_admin("$message " . 399 "This is new config(an_acceptmethods):", array(AN_METHOD_CC)); 400 break; 401 } 402 // This echeck type isn't accepted 403 case AN_REASON_NOACHTYPE: 404 case AN_REASON_NOACHTYPE2: 405 { 406 if (!empty($extra->x_echeck_type)) { 407 switch ($extra->x_echeck_type) { 408 // CCD=BUSINESSCHECKING 409 case 'CCD': 410 { 411 set_config('an_acceptechecktypes', 'CHECKING,SAVINGS'); 412 email_to_admin("$message " . 413 "This is new config(an_acceptechecktypes):", array('CHECKING','SAVINGS')); 414 } 415 break; 416 // WEB=CHECKING or SAVINGS 417 case 'WEB': 418 { 419 set_config('an_acceptechecktypes', 'BUSINESSCHECKING'); 420 email_to_admin("$message " . 421 "This is new config(an_acceptechecktypes):", array('BUSINESSCHECKING')); 422 } 423 break; 424 } 425 } 426 break; 427 } 428 } 429 } 430 } 431 return $responsecode; 432 } 433 434 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |