Pay for the development of Alipay

Pay for the development of Alipay

Alipay is the best developed among all payment methods because the documentation is clearer and the development is relatively simple. Therefore, Alipay has relatively few pits.

APP payment

APP payment steps are:

  1. Get Alipay configuration information.

  2. Generate merchant order information.

  3. Generate the data to be verified according to the order information .

  4. Generate the encrypted string of the request to Alipay .

  5. Concatenate the data to be verified and the encrypted string and return it to the APP.

  6. The APP requests the Alipay client to make payment with the data obtained.

Since APP payment is called by the APP to make Alipay payment, all the server needs to do is to encapsulate the request parameters and return to the APP.

  1. Get Alipay configuration information.
    The configuration information required for payment is:

    • key: Transaction security check code.

    • app_id: The application ID assigned by Alipay to the developer.

  2. Generate merchant order information.
    This step is generated by the merchant. The only order information that Alipay needs to know is:

    • subject: required. Product title/transaction title/order title/order keywords, etc.

    • total_amount: required. Order price.

    • out_trade_no: required. The unique order number on the merchant website.

    • body: Optional. The specific description of the transaction.

  3. Generate the data to be verified according to the order information .
    Detailed request parameters for APP payment: click to view

  4. Generate the encrypted string of the request to Alipay .

    $sign = $alipaySubmit->buildRequestParaForApp($para_token); 

    Among them, buildRequestParaForAppthe realization is:

    1. Sort the array of signature parameters

    /**
     *  
     * @param $para  
     * return  
     */
    function argSort($para) {
        ksort($para);
        reset($para);
        return $para;
    } 
    1. Generate signature results (Ali recommends the RSA2 signature method, and RSA is used in this project)

    /**
     * RSA 
     * @param $data  
     * @param $private_key_path  
     * return  
     */
    function rsaSign($data, $private_key_path) {
        $priKey = file_get_contents($private_key_path);
        $res = openssl_get_privatekey($priKey);
        openssl_sign($data, $sign, $res);
        openssl_free_key($res);
        //base64 
        $sign = base64_encode($sign);
        return $sign;
    } 
  5. Concatenate the data to be verified and the encrypted string and return it to the APP.

    $url = "";
    foreach ($para_token as $key => $value) {
        $url .= $key."=".urlencode($value)."&";
    }
    return $url."sign=".urlencode($sign); 
  6. The APP requests the Alipay client to make payment with the data obtained.
    The APP takes the spliced string to request the Alipay client to call Alipay for payment. The spliced string is roughly as shown in the figure below:

Web version payment

The web version payment steps are:

  1. Set the configuration information of Alipay.

  2. Apply for a new order to Alipay and get a payment token.

  3. Carry token for order payment.

The web version of Alipay payment is more complicated than the APP to transfer Alipay, because when paying on the web, you need to request the Alipay server multiple times to obtain the necessary parameters for the payment.

  1. Set Alipay configuration information.

    /** alipay.wap.trade.create.direct token**/
            
        //
        private  $format = "";
        //
        
        //
        private $v = "";
        //
        
        //
        private $req_id = "";
        //
        
        //**req_data **
        
        //
        private $notify_url = "";
        //http://?id=123 
        
        //
        private $call_back_url = "";
        //http://?id=123 
        
        //
        private $seller_email = "";
        //
        
        //
        private $out_trade_no = "";
        //
        
        //
        private $subject = "";
        //
        
        //
        private $total_fee = "";
        //
        
        //
        private $req_data = "";
        //
        
        //
        private $alipay_config = array();
        
    /************************************************************/ 
  2. Apply for a new order to Alipay and get the token of the order.

    Service request token is: alipay.wap.trade.create.direct.

    1. Construction parameters:

      $para_token = array(
          "service" => "alipay.wap.trade.create.direct",
          //  (partner ID)
          "partner" => trim($this->alipay_config['partner']),
          // APP RSA MD5
          "sec_id" => trim($this->alipay_config['sign_type']),
          //  
          "format"    => $this->format,
          //  
          "v" => $this->v,
          //  
          "req_id"    => $this->req_id,
          //  
          "req_data"  => $req_data,
          //  utf8 
          "_input_charset"    => trim(strtolower($this->alipay_config['input_charset']))
      ); 
    2. Process the constructed request parameters, sort the dictionary, concatenate strings, and sign:

      $para_filter = paraFilter($para_temp);
      $para_sort = argSort($para_filter);
      $mysign = $this->buildRequestMysign($para_sort);
      //
      $para_sort['sign'] = $mysign;
      return $para_sort; 

      Processing: Filter the data whose value is empty, and filter the signature type and signature.

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

      Dictionary sorting:

      /**
       *  
       * @param $para  
       * return  
       */
      function argSort($para) {
          ksort($para);
          reset($para);
          return $para;
      } 

      signature:

      /**
       *  
       * @param $para_sort  
       * return  
       */
      function buildRequestMysign($para_sort) {
          //= & 
          $prestr = createLinkstring($para_sort);
          $mysign = "";
          switch (strtoupper(trim($this->alipay_config['sign_type']))) {
              case "MD5" :
                  // MD5 MD5 
                  $mysign = md5Sign($prestr, $this->alipay_config['key']);
                  break;
              case "RSA" :
                  // RSA 
                  $mysign = rsaSign($prestr, $this->alipay_config['private_key_path']);
                  break;
              case "0001" :
                  $mysign = rsaSign($prestr, $this->alipay_config['private_key_path']);
                  break;
              default :
                  $mysign = "";
          }
          
          return $mysign;
      } 
    3. Use the constructed parameters to request Alipay backend to apply for a new order:

      Note: When requesting, you must bring your SSL certificate.

      $sResult = getHttpResponsePOST($this->alipay_gateway_new, $this->alipay_config['cacert'],$request_data,trim(strtolower($this->alipay_config['input_charset']))); 

      Implementation of the request function:

      /**
       *  POST 
       *  
       * 1. Crul php.ini php_curl.dll ";" 
       * 2. cacert.pem SSL getcwd().'\\cacert.pem'
       * @param $url  URL 
       * @param $cacert_url  
       * @param $para  
       * @param $input_charset  
       * return  
       */
      function getHttpResponsePOST($url, $cacert_url, $para, $input_charset = '') {
      
          if (trim($input_charset) != '') {
              $url = $url."_input_charset=".$input_charset;
          }
          $curl = curl_init($url);
          curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL 
          curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//
          curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//
          curl_setopt($curl, CURLOPT_HEADER, 0 ); // HTTP 
          curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 
          curl_setopt($curl,CURLOPT_POST,true); //post 
          curl_setopt($curl,CURLOPT_POSTFIELDS,$para);//post 
          $responseText = curl_exec($curl);
          //var_dump( curl_error($curl) );//curl 
          curl_close($curl);
          
          return $responseText;
      } 

      Process the data returned by Alipay and obtain the token.

      //URLDECODE 
      $html_text = urldecode($html_text);
      //
      $para_html_text = parseResponse($html_text);
      //request_token
      $request_token = $para_html_text['request_token']; 

      Implementation of the parseResponse function:

      /**
       *  
       * @param $str_text  
       * @return  
       */
      function parseResponse($str_text) {
          //& 
          $para_split = explode('&',$str_text);
          //
          foreach ($para_split as $item) {
              //= 
              $nPos = strpos($item,'=');
              //
              $nLen = strlen($item);
              //
              $key = substr($item,0,$nPos);
              //
              $value = substr($item,$nPos+1,$nLen-$nPos-1);
              //
              $para_text[$key] = $value;
          }
          
          if( ! empty ($para_text['res_data'])) {
              //
              if($this->alipay_config['sign_type'] == '0001') {
                  $para_text['res_data'] = rsaDecrypt($para_text['res_data'], $this->alipay_config['private_key_path']);
              }
              
              //token res_data res_data token 
              $doc = new DOMDocument();
              $doc->loadXML($para_text['res_data']);
              $para_text['request_token'] = $doc->getElementsByTagName( "request_token" )->item(0)->nodeValue;
          }
          
          return $para_text;
      } 
  3. Carry token for order payment.

    After successfully requesting the token back, you can send a payment request to Alipay.

    Also construct the request data:

    //2 token 
    $req_data = '<auth_and_execute_req><request_token>' . $request_token . '</request_token></auth_and_execute_req>';
    //
    
    //
    $parameter = array(
        "service" => "alipay.wap.auth.authAndExecute",
        //  (partner ID)
        "partner" => trim($this->alipay_config['partner']),
        //  
        "sec_id" => trim($this->alipay_config['sign_type']),
        //  2 
        "format"    => $this->format,
        "v" => $this->v,
        "req_id"    => $this->req_id,
        //  
        "req_data"  => $req_data,
        //  utf8.
        "_input_charset"    => trim(strtolower($this->alipay_config['input_charset']))
    ); 

    Send these parameters to Alipay on the page to initiate a payment request.

    The implementation in PHP is to render these parameters into HTML, and then submit the form in HTML.

    At this point, the web version of Alipay payment has completed the entire process.

Asynchronous notification of payment results

In the above, we see that there are two parameters passed to Alipay:

  • call_back_url: After the transaction is successful, the "return to merchant page" address on the Alipay page (synchronous callback)

  • notify_url: After the transaction status changes, Alipay will notify the callback address of the website (asynchronous notification)

For transactions generated by mobile website payment, Alipay will notify the merchant system of the payment result as a parameter in the form of a POST request according to the asynchronous notification address notify_url passed in the original payment API.

For transactions generated by App payment, Alipay will notify the merchant system of the payment result as a parameter in the form of a POST request according to the asynchronous notification address notify_url passed in the original payment API.

The official Alipay asynchronous notification document is relatively clear, when to start the notification, what parameters are returned, and there are precautions. Developers can view the specific information according to their own circumstances.

The verification step can be moved here

Here is a simple example of the items on hand to illustrate how the back-end will verify the signature and process the order after Alipay informs it.

public function app_notifyOp(){
    $payment_api = $this->_get_payment_api();
    $payment_config = $this->_get_payment_config();
    // POST 
    $callback_info = $payment_api->getNotifyInfoApp($_POST);
    if($callback_info) {
        //
        if ($callback_info['order_state']) {
            // 
            $result = $this->_update_order($callback_info['out_trade_no'], $callback_info['trade_no']);
        }else{
            // 
            $result = $this->_app_refund($callback_info['out_trade_no'], $callback_info['trade_no'], $callback_info['refund_fee']);
        }
        if($result['state']) {
            echo 'success';die;
        }
    }
    //
    echo "fail";die;
} 
  1. Get Alipay notification data
    Alipay asynchronous notification is a POST request, and the returned data structure is as follows:

    {
        "total_amount": "31.00",
        "buyer_id": "ID",
        "trade_no": "TRADE_NO",
        "body": "pay_sn:580546601841783375",
        "notify_time": "2017-04-27 09:50:59",
        "subject": "580546601841783375",
        "sign_type": "RSA",
        "buyer_logon_id": "ID",
        "auth_app_id": "APPID",
        "charset": "utf-8",
        "notify_type": "trade_status_sync",
        "invoice_amount": "31.00",
        "out_trade_no": "580546601841783375_r",
        "trade_status": "TRADE_SUCCESS",
        "gmt_payment": "2017-04-27 09:50:58",
        "version": "1.0",
        "point_amount": "0.00",
        "sign": "SIGNATURE",
        "gmt_create": "2017-04-27 09:50:58",
        "buyer_pay_amount": "31.00",
        "receipt_amount": "31.00",
        "fund_bill_list": "[{&quot;amount&quot;:&quot;31.00&quot;,&quot;fundChannel&quot;:&quot;ALIPAYACCOUNT&quot;}]",
        "app_id": "APPID",
        "seller_id": "SELLERID",
        "notify_id": "8414394a1190f25edbbec9ba4b98642mem",
        "seller_email": "YOUR_ALIPAY_ACCOUNT"
    } 
  2. Verification data
    Verification requires Alipay's public key

    Sign and verify the signature of the process is the same, it is in addition to all the signparameters other than a dictionary sort, and to key=valuethe form of &the symbol makes up the string, and then use the key signature, the resulting signature with the signature of Alipay return Compare and complete the verification process.

    function getSignVeryfy($para_temp, $sign) {
        //
        $para = paraFilter($para_temp);
        
        //
        $para = argSort($para);
    
        //= & 
        $prestr = createLinkstring($para);
        $prestr = htmlspecialchars_decode($prestr);
        $isSgin = false;
        switch (strtoupper(trim($this->alipay_config['sign_type']))) {
            case "MD5" :
                $isSgin = md5Verify($prestr, $sign, $this->alipay_config['key']);
                break;
            case "RSA" :
                $isSgin = rsaVerify($prestr, trim($this->alipay_config['ali_public_key_path']), $sign);
                break;
            case "0001" :
                $isSgin = rsaVerify($prestr, trim($this->alipay_config['ali_public_key_path']), $sign);
                break;
            default :
                $isSgin = false;
        }
        logResult($log);
        
        return $isSgin;
    } 

    But there is a pit, is the return data fund_bill_listis the result of html escaped (as in the example of data: [{&quot;amount&quot;:&quot;31.00&quot;,&quot;fundChannel&quot;:&quot;ALIPAYACCOUNT&quot;}]), if the direct use of this parameter is signed, it will lead to the signature failure. Here you need to escape the string:, [{"amount":"31.00","fundChannel":"ALIPAYACCOUNT"}]sign with the escaped parameter value, and pass the verification.

  3. After the order status
    verification is completed, the background can change the order status according to the actual situation.

complete

I wish you programmers no more pits when developing Alipay payment, and I hope Alipay will no longer mine mines in subsequent updates.