[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/enrol/authorize/ -> authorizenetlib.php (source)

   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  ?>


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7