<?php
/*
  $Id: alipay.php $
  TomatoCart Open Source Shopping Cart Solutions
  http://www.tomatocart.com

  Copyright (c) 2009 Wuxi Elootec Technology Co., Ltd;  Copyright (c) 2006 osCommerce

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License v2 (1991)
  as published by the Free Software Foundation.
*/

class osC_Payment_alipay extends osC_Payment {
  var $_method_title,
  $_code = 'alipay',
  $_status = false,
  $_sort_order,
  $_order_id,
  $sign_type = 'MD5',
  $_input_charset = 'utf-8',
  $mysign,
  $gateway = 'https://www.alipay.com/cooperate/gateway.do?';

  function osC_Payment_alipay() {
    global $osC_Database, $osC_Language, $osC_ShoppingCart;

    $this->_method_title = $osC_Language->get('payment_alipay_method_title');
    $this->_status = (MODULE_PAYMENT_ALIPAY_STATUS == '1') ? true : false;
    $this->_sort_order = MODULE_PAYMENT_ALIPAY_SORT_ORDER;

    $this->form_action_url = $this->gateway . '_input_charset=' . $this->_input_charset;

    if ($this->_status === true) {
      if ((int)MODULE_PAYMENT_ALIPAY_ORDER_STATUS_ID > 0) {
        $this->order_status = MODULE_PAYMENT_ALIPAY_ORDER_STATUS_ID;
      }

      if ((int)MODULE_PAYMENT_ALIPAY_ZONE > 0) {
        $check_flag = false;

        $Qcheck = $osC_Database->query('select zone_id from :table_zones_to_geo_zones where geo_zone_id = :geo_zone_id and zone_country_id = :zone_country_id order by zone_id');
        $Qcheck->bindTable(':table_zones_to_geo_zones', TABLE_ZONES_TO_GEO_ZONES);
        $Qcheck->bindInt(':geo_zone_id', MODULE_PAYMENT_ALIPAY_ZONE);
        $Qcheck->bindInt(':zone_country_id', $osC_ShoppingCart->getBillingAddress('country_id'));
        $Qcheck->execute();

        while ($Qcheck->next()) {
          if ($Qcheck->valueInt('zone_id') < 1) {
            $check_flag = true;
            break;
          } elseif ($Qcheck->valueInt('zone_id') == $osC_ShoppingCart->getBillingAddress('zone_id')) {
            $check_flag = true;
            break;
          }
        }

        if ($check_flag == false) {
          $this->_status = false;
        }
      }
    }
  }

  function selection() {
    return array('id' => $this->_code,
                   'module' => $this->_method_title);
  }

  function confirmation() {
    $this->_order_id = osC_Order::insert(ORDERS_STATUS_PREPARING);
  }

  function process_button() {
    global $osC_Language, $osC_Customer, $osC_ShoppingCart, $osC_Currencies;
    $currency = 'CNY';
    $this->_order_id = osC_Order::insert();
    $body = STORE_NAME . ';' . $osC_Language->get('payment_alipay_body_user_id') . $osC_Customer->getID() . ';' . $osC_Language->get('payment_alipay_body_order_id') . $this->_order_id;//$_SESSION['prepOrderID'];
    $params = array('service' => 'create_partner_trade_by_buyer',
            'payment_type' => '1',
            'partner' => MODULE_PAYMENT_ALIPAY_API_PARTNER,
            'seller_email' => MODULE_PAYMENT_ALIPAY_EMAIL,
            'notify_url' => str_replace('&amp;', '&', osc_href_link(FILENAME_CHECKOUT, 'callback&module=' . $this->_code, 'SSL', null, null, true)),
            'return_url' => osc_href_link(FILENAME_CHECKOUT, 'process', 'SSL', null, null, true),
            '_input_charset' => $this->_input_charset,
            'show_url' => osc_href_link(FILENAME_CHECKOUT, '', 'SSL', null, null, true),
            'out_trade_no' => $this->_order_id,
            'subject' => MODULE_PAYMENT_ALIPAY_MAIN_NAME,
            'body' => $body
    );
    
    if (MODULE_PAYMENT_ALIPAY_TYPE === '0' || MODULE_PAYMENT_ALIPAY_TYPE === '2') { // 纯担保交易， 标准双接口
      $receive_name = $osC_ShoppingCart->getShippingAddress('firstname') . $osC_ShoppingCart->getShippingAddress('lastname');
      $receive_address = $osC_ShoppingCart->getShippingAddress('state') . $osC_ShoppingCart->getShippingAddress('city') . $osC_ShoppingCart->getShippingAddress('suburb') . $osC_ShoppingCart->getShippingAddress('street_address');
      $receive_zip = $osC_ShoppingCart->getShippingAddress('postcode');
      $receive_phone = $osC_ShoppingCart->getShippingAddress('telephone_number');

      if (MODULE_PAYMENT_ALIPAY_TYPE === '2') {
        $params['service']  = 'trade_create_by_buyer';
      }
      
//      $params['price']      = $osC_Currencies->formatRaw($osC_ShoppingCart->getTotal() - $osC_ShoppingCart->getShippingMethod('cost'), $currency);
      $params['price'] = 0.1;
      $params['quantity']     = '1';
//      $params['logistics_fee']  = $osC_Currencies->formatRaw($osC_ShoppingCart->getShippingMethod('cost'), $currency);
      $params['logistics_fee']  = 0;
      $params['logistics_type'] = 'EXPRESS';
      $params['logistics_payment']= 'BUYER_PAY';
      $params['receive_name']   = $receive_name;
      if (!empty($receive_zip)) {
        $params['receive_zip']    = $receive_zip;
      }
      $params['receive_phone']  = $receive_phone;
      $params['receive_mobile'] = $receive_phone;
    } else if (MODULE_PAYMENT_ALIPAY_TYPE === '1') {  // 通用即时到账
      $params['service']    = 'create_direct_pay_by_user';
      $params['total_fee']  = $osC_Currencies->formatRaw($osC_ShoppingCart->getTotal(), $currency);
      $params['paymethod']  = 'bankPay';
      $params['defaultbank']  = 'CMB';
    }
    

    
    $sorted_params = $this->arg_sort($params);
    $this->mysign = $this->build_mysign($sorted_params, MODULE_PAYMENT_ALIPAY_API_SECURITY_CODE, $this->sign_type);
    
    $process_button_string = '';
    foreach ($params as $key => $value) {
      $process_button_string .= osc_draw_hidden_field($key, $value);
    }
    $process_button_string .= osc_draw_hidden_field('sign', $this->mysign);
    $process_button_string .= osc_draw_hidden_field('sign_type', $this->sign_type);

    return $process_button_string;
  }

  function callback() {
    global $osC_Database;

    if($this->notify_verify()) {

      $order_id = $_POST['out_trade_no'];

      if($_POST['trade_status'] == 'WAIT_BUYER_PAY') {
        echo "success";
      } else if ($_POST['trade_status'] == 'WAIT_SELLER_SEND_GOODS') {
        
        $comments = 'Alipay Verified.';
        osC_Order::process($order_id, $this->order_status, $comments);

        echo "success";
      } else if ($_POST['trade_status'] == 'WAIT_BUYER_CONFIRM_GOODS') {
        echo "success";
      } else if ($_POST['trade_status'] == 'TRADE_FINISHED'){
        echo "success";
      } else {
        echo "success";   
      }

      $post_array = array('root' => $_POST);
      $post_array['root']['transaction_response'] = $_POST['trade_status'];
      $osC_XML = new osC_XML($post_array);

      $Qtransaction = $osC_Database->query('insert into :table_orders_transactions_history (orders_id, transaction_code, transaction_return_value, transaction_return_status, date_added) values (:orders_id, :transaction_code, :transaction_return_value, :transaction_return_status, now())');
      $Qtransaction->bindTable(':table_orders_transactions_history', TABLE_ORDERS_TRANSACTIONS_HISTORY);
      $Qtransaction->bindInt(':orders_id', $order_id);
      $Qtransaction->bindInt(':transaction_code', 1);
      $Qtransaction->bindValue(':transaction_return_value', $osC_XML->toXML());
      $Qtransaction->bindInt(':transaction_return_status', 1);
      $Qtransaction->execute();
    } else {
      echo "fail";
    }
  }

  function build_mysign($sort_array,$security_code,$sign_type = "MD5") {
    $prestr = $this->create_linkstring($sort_array);
    $prestr = $prestr . $security_code;
    $mysgin = $this->sign($prestr,$sign_type);
    return $mysgin;
  }

  function create_linkstring($array) {
    $arg  = "";
    while (list ($key, $val) = each ($array)) {
      $arg.=$key."=".$val."&";
    }
    $arg = substr($arg,0,count($arg)-2);        
    return $arg;
  }

  function create_linkstring_urlencode($array) {
    $arg  = "";
    while (list ($key, $val) = each ($array)) {
      if ($key != "service" && $key != "_input_charset")
      $arg.=$key."=".urlencode($val)."&";
      else $arg.=$key."=".$val."&";
    }
    $arg = substr($arg,0,count($arg)-2);         
    return $arg;
  }

  function para_filter($parameter) {
    $para = array();
    while (list ($key, $val) = each ($parameter)) {
      if($key == "sign" 
      || $key == "sign_type" 
      || $key == "callback" 
      || $key == "module" 
      || $key=="sid" 
      || $val == "") continue;
      else  $para[$key] = $parameter[$key];
    }
    return $para;
  }

  function arg_sort($array) {
    ksort($array);
    reset($array);
    return $array;
  }

  function sign($prestr,$sign_type) {
    $sign='';
    if($sign_type == 'MD5') {
      $sign = md5($prestr);
    }
    elseif($sign_type =='DSA') {
      //DSA 签名方法待后续开发
      die("DSA 签名方法待后续开发，请先使用MD5签名方式");
    }else {
      die("支付宝暂不支持".$sign_type."类型的签名方式");
    }
    return $sign;
  }


  function  log_result($word) {
    $fp = fopen("log.txt","a");
    flock($fp, LOCK_EX) ;
    fwrite($fp,"执行日期：".strftime("%Y%m%d%H%M%S",time())."\n".$word."\n");
    flock($fp, LOCK_UN);
    fclose($fp);
  }

  function query_timestamp($partner) {
    $URL = $this->gateway . "service=query_timestamp&partner=".$partner;
    $encrypt_key = "";
   
    $doc = new DOMDocument();
    $doc->load($URL);
    $itemEncrypt_key = $doc->getElementsByTagName( "encrypt_key" );
    $encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
    return $encrypt_key;
  }

  function notify_verify() {
    global $request_type;
    
    if(($request_type == 'SSL') && (ENABLE_SSL === true)) {
      $veryfy_url = $this->gateway . "service=notify_verify" ."&partner=" . MODULE_PAYMENT_ALIPAY_API_PARTNER . "&notify_id=" . $_POST["notify_id"];
    } else {
      $veryfy_url = "http://notify.alipay.com/trade/notify_query.do?partner=" . MODULE_PAYMENT_ALIPAY_API_PARTNER . "&notify_id=" . $_POST["notify_id"];
    }
    $veryfy_result = $this->get_verify($veryfy_url);

    
    if(empty($_POST)) {             
      return false;
    } else {
      $post          = $this->para_filter($_POST);      
      
      $sort_post     = $this->arg_sort($post);      
      $this->mysign  = $this->build_mysign($sort_post, MODULE_PAYMENT_ALIPAY_API_SECURITY_CODE);   
  
      if (preg_match("/true$/i",$veryfy_result) && $this->mysign == $_POST["sign"]) {
        return true;
      } else {
        return false;
      }
    }
  }

  function return_verify($transport) {
    global $request_type;

    if(($request_type == 'SSL') && (ENABLE_SSL === true)) {
      $veryfy_url = $this->gateway . "service=notify_verify" ."&partner=" .MODULE_PAYMENT_ALIPAY_API_PARTNER. "&notify_id=".$_GET["notify_id"];
    } else {
      $veryfy_url = "http://notify.alipay.com/trade/notify_query.do?partner=".MODULE_PAYMENT_ALIPAY_API_PARTNER."&notify_id=".$_GET["notify_id"];
    }
    $veryfy_result = $this->get_verify($veryfy_url);

    
    if(empty($_GET)) {              
      return false;
    } else {
      $get          = $this->para_filter($_GET);      
      $sort_get     = $this->arg_sort($get);        
      $this->mysign = $this->build_mysign($sort_get,MODULE_PAYMENT_ALIPAY_API_SECURITY_CODE,$this->sign_type);    

      if (preg_match("/true$/i",$veryfy_result) && $this->mysign == $_GET["sign"]) {
        return true;
      }else {
        return false;
      }
    }
  }

  function get_verify($url,$time_out = "60") {
    $urlarr     = parse_url($url);
    $errno      = "";
    $errstr     = "";
    $transports = "";
    if($urlarr["scheme"] == "https") {
      $transports = "ssl://";
      $urlarr["port"] = "443";
    } else {
      $transports = "tcp://";
      $urlarr["port"] = "80";
    }
    $fp=@fsockopen($transports . $urlarr['host'],$urlarr['port'],$errno,$errstr,$time_out);
    if(!$fp) {
      die("ERROR: $errno - $errstr<br />\n");
    } else {
      fputs($fp, "POST ".$urlarr["path"]." HTTP/1.1\r\n");
      fputs($fp, "Host: ".$urlarr["host"]."\r\n");
      fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
      fputs($fp, "Content-length: ".strlen($urlarr["query"])."\r\n");
      fputs($fp, "Connection: close\r\n\r\n");
      fputs($fp, $urlarr["query"] . "\r\n\r\n");
      while(!feof($fp)) {
        $info[]=@fgets($fp, 1024);
      }
      fclose($fp);
      $info = implode(",",$info);
      return $info;
    }
  }
}
?>
