{"id":3340,"date":"2025-12-04T13:08:27","date_gmt":"2025-12-04T05:08:27","guid":{"rendered":"https:\/\/blog.quantoyo.com\/?p=3340"},"modified":"2025-12-04T13:08:27","modified_gmt":"2025-12-04T05:08:27","slug":"line-pay-php%e4%b8%b2%e6%8e%a5","status":"publish","type":"post","link":"https:\/\/blog.quantoyo.com\/?p=3340","title":{"rendered":"LINE PAY &#8211; PHP\u4e32\u63a5"},"content":{"rendered":"\n<p>\u8a18\u9304\u4e00\u4e0b\u9019\u6b21\u4e32\u63a5\u7684\u7d93\u9a57<\/p>\n\n\n\n<p>LINE Pay \u78ba\u5be6\u5f88\u597d\u4e32\u63a5\uff0c\u4e00\u5207\u90fd\u975e\u5e38\u9806\u5229<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>\u9996\u5148\uff0c\u5beb\u4e00\u500b\u53d6\u5f97LINE Pay \u4ed8\u6b3e\u7db2\u5740\u7528\u7684 class<\/p>\n\n\n\n<pre class=\"wp-block-code has-cyan-bluish-gray-background-color has-background has-small-font-size\"><code>class getLPUrl\n{\n    private $channelId = \"\";\n    private $channelSecret = \"\";\n    private $queryHost = \"\";\n    private $queryUrl = \"\";\n    private $body = array();\n    private $packageInfoList = array();\n    private $data = array();\n    public function __construct($transactionId, $price, $title, $detailName, $url,  $host, $channelId, $channelSecret)\n    {\n        $this->channelId = $channelId;\n        $this->channelSecret = $channelSecret;\n        $this->queryUrl = $url;\n        $this->queryHost = $host;\n\n        $this->body&#91;\"orderId\"] = $transactionId;\n        $this->body&#91;\"currency\"] = \"TWD\";\n        $this->body&#91;\"amount\"] = $price*1;\n        $this->body&#91;\"packages\"] = &#91;&#91;\n            \"id\" => \"package1\",\n            \"amount\" => $price*1,\n            \"name\" => $title,\n            \"products\" => &#91;&#91;\n                \"name\" => $detailName,\n                \"quantity\" => 1,\n                \"price\" => $price*1\n            ]]]];\n        $this->body&#91;\"redirectUrls\"] = &#91;\n            \"confirmUrl\" => \"\u6210\u529f\u6642\u6253\u958b\u7684\u9801\u9762\",\n            \"cancelUrl\" => \"\u5931\u6557\u6642\u6253\u958b\u7684\u9801\u9762\"\n        ];\n    }\n    public function send()\n    {\n        $bodyJson = json_encode($this->body, JSON_UNESCAPED_UNICODE);\n\n        \/\/ ==== \u5efa\u7acb nonce ====\n        $nonce = bin2hex(random_bytes(16)); \/\/ \u4e82\u6578\u5b57\u4e32\n\n        \/\/ ==== \u5efa\u7acb HMAC \u7c3d\u7ae0 ====\n        $signatureStr = $this->channelSecret . $this->queryUrl . $bodyJson . $nonce;\n        $hash = hash_hmac('sha256', $signatureStr, $this->channelSecret, true);\n        $signature = base64_encode($hash);\n\n        \/\/ ==== \u8a2d\u5b9a Header\uff08\u6ce8\u610f\u9019\u88e1\u6539\u6210 X-LINE-Authorization\uff09====\n        $headers = &#91;\n            \"Content-Type: application\/json\",\n            \"X-LINE-ChannelId: {$this->channelId}\",\n            \"X-LINE-Authorization-Nonce: {$nonce}\",\n            \"X-LINE-Authorization: {$signature}\"\n        ];\n\n        $ret = sendPostJsonLP($this->queryHost.$this->queryUrl, $bodyJson, $headers);\n        $this->data = json_decode($ret, true);\n\n        if (isset($this->data&#91;'returnCode']) &amp;&amp; $this->data&#91;'returnCode'] === '0000') {\n            return true;\n        }\n        return false;\n    }\n    public function get($key)\n    {\n        if($key == \"web\"){\n            $paymentUrl = $this->data&#91;'info']&#91;'paymentUrl']&#91;'web'];\n            return $paymentUrl;\n        }else{\n            return $this->data;\n        }\n    }\n}\n\n\npublic static function sendPostJsonLP($apiUrl, $bodyJson, $headers) {\n        \/\/ ==== \u767c\u9001 API ====\n        $ch = curl_init($apiUrl);\n        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n        curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyJson);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n        $response = curl_exec($ch);\n    \n        if (curl_errno($ch)) {\n            echo \"cURL Error: \" . curl_error($ch);\n        }\n        curl_close($ch);\n        return $response;\n    }\n<\/code><\/pre>\n\n\n\n<p>\u4f7f\u7528\u6642<\/p>\n\n\n\n<pre class=\"wp-block-code has-cyan-bluish-gray-background-color has-background has-small-font-size\"><code>$tradeNo = generateUniqueString();      \/\/\u4e82\u6578\n$price = 1234;  \/\/\u50f9\u683c\n$title = \"\u9019\u662f\u6a19\u984c\";\n$detailName = \"\u9019\u662f\u5167\u6587\";\n$LP_url = \"\/v3\/payments\/request\"; \/\/\u56fa\u5b9a\u7684\n$LP_Sandbox = \"https:\/\/sandbox-api-pay.line.me\"; \/\/\u6e2c\u8a66\u74b0\u5883\n$LP_Production = \"https:\/\/api-pay.line.me\";      \/\/\u7dda\u4e0a\u74b0\u5883\n$LP_host = $LP_Production;\n\n$LP_channelId = \"\u8ddfLine Pay \u7533\u8acb\";\n$LP_channelSecret = \"\u8ddfLine Pay \u7533\u8acb\";\n\n$tool = new getLPUrl($tradeNo, $price, $title, $detailName, $LP_url, $LP_host, $LP_channelId, $LP_channelSecret);\nif($tool->send()){\n     $payUrl = $tool->get(\"web\");\n}\n\n\u9019\u500b$payUrl \u5c31\u53ef\u4ee5\u62ff\u4f86\u7d66\u5ba2\u4eba\u6253\u958b\u4ed8\u6b3e\u4e86<\/code><\/pre>\n\n\n\n<p>\u53e6\u5916\u4ed8\u6b3e\u5f8c\u7684\u6210\u529f\u9801\u9762\u4e5f\u5f88\u91cd\u8981<\/p>\n\n\n\n<pre class=\"wp-block-code has-cyan-bluish-gray-background-color has-background has-small-font-size\"><code>\n$transactionId = $_GET&#91;'transactionId'];\n$orderId = $_GET&#91;'orderId'];\n\n\n$LP_channelId = \"\u8ddfLine Pay \u7533\u8acb\";\n$LP_channelSecret = \"\u8ddfLine Pay \u7533\u8acb\";\n\n$Sandbox = \"https:\/\/sandbox-api-pay.line.me\";\n$Production = \"https:\/\/api-pay.line.me\";\n$url = \"\/v3\/payments\/$transactionId\/confirm\";  \/\/\u9019\u908a\u8981\u4e32\u4e0a\u62ff\u5230\u7684transactionId\n$apiUrl = $Production.$url;\n\n\/\/\u5efa\u7acb\u56de\u50b3\u7269\u4ef6\uff0c\u9019\u908a\u8981\u6211\u5011\u78ba\u8a8d\u91d1\u984d\uff0c\u586b\u6211\u5011\u771f\u6b63\u60f3\u8981\u7684\u3002\n$body = &#91;\n    \"amount\" => $amount*1,\n    \"currency\" => \"TWD\"\n];\n\n$bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE);\n\n\/\/ ==== \u5efa\u7acb nonce ====\n$nonce = bin2hex(random_bytes(16)); \/\/ \u4e82\u6578\u5b57\u4e32\n\n\/\/ ==== \u5efa\u7acb HMAC \u7c3d\u7ae0 ====\n$signatureStr = $channelSecret . $url . $bodyJson . $nonce;\n$hash = hash_hmac('sha256', $signatureStr, $channelSecret, true);\n$signature = base64_encode($hash);\n\n\/\/ ==== \u8a2d\u5b9a Header\uff08\u6ce8\u610f\u9019\u88e1\u6539\u6210 X-LINE-Authorization\uff09====\n$headers = &#91;\n    \"Content-Type: application\/json\",\n    \"X-LINE-ChannelId: {$channelId}\",\n    \"X-LINE-Authorization-Nonce: {$nonce}\",\n    \"X-LINE-Authorization: {$signature}\"\n];\n\n\/\/ ==== \u767c\u9001 API ====\n$ch = curl_init($apiUrl);\ncurl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $bodyJson);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = curl_exec($ch);\ncurl_close($ch);\n\nif (!curl_errno($ch)) {\n    $data = json_decode($response, true);\n\n    $rtnCode = $data&#91;'returnCode'];\n    $rtnMsg =$data&#91;'returnMessage'];\n\n    if (isset($data&#91;'returnCode']) &amp;&amp; $data&#91;'returnCode'] === '0000') {\n        $payStatus = true; \/\/ \u9019\u908a\u7b97\u662f\u5b8c\u6210\u6536\u6b3e\u4e86\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>\u6536\u6b3e\u958b\u5fc3<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u8a18\u9304\u4e00\u4e0b\u9019\u6b21\u4e32\u63a5\u7684\u7d93\u9a57 LINE Pay \u78ba\u5be6\u5f88\u597d\u4e32\u63a5\uff0c\u4e00\u5207\u90fd\u975e\u5e38\u9806\u5229<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[639,555,76,152,638],"class_list":["post-3340","post","type-post","status-publish","format-standard","hentry","category-technology","tag-example","tag-linepay","tag-php","tag-152","tag-638"],"_links":{"self":[{"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=\/wp\/v2\/posts\/3340","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3340"}],"version-history":[{"count":1,"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=\/wp\/v2\/posts\/3340\/revisions"}],"predecessor-version":[{"id":3341,"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=\/wp\/v2\/posts\/3340\/revisions\/3341"}],"wp:attachment":[{"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3340"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3340"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.quantoyo.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3340"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}