├── README.md ├── LICENSE └── passkit.php /README.md: -------------------------------------------------------------------------------- 1 | # php-passkit 2 | A php library to create AppleWallet Pass. 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 时光 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /passkit.php: -------------------------------------------------------------------------------- 1 | passDir = realpath($dir) . "/"; 17 | $passfile = file_get_contents($this->passDir . "pass.json"); 18 | $this->passkit = json_decode($passfile,true); 19 | $this->extendFiles = []; 20 | }catch(Exception $e){ 21 | return $e->getMessage(); 22 | } 23 | } 24 | 25 | public function setCert($path){ // 设置签名证书路径 26 | $this->certPath = $path; 27 | return true; 28 | } 29 | 30 | public function setWWDR($path){ // 设置WWDR证书路径 31 | $this->wwdrPath = $path; 32 | return true; 33 | } 34 | 35 | public function setPassword($password){ // 设置证书密码 36 | $this->certPassword = $password; 37 | return true; 38 | } 39 | 40 | /* 41 | * 向用户生成好的pkpass文件 42 | */ 43 | public function outputPass(){ 44 | if(is_array($this->passkit)) 45 | $this->exportPass(); 46 | header('Content-Type: application/vnd.apple.pkpass'); 47 | header('Content-Disposition: attachment; filename="pass.pkpass"'); 48 | header('Content-Transfer-Encoding: binary'); 49 | header('Connection: Keep-Alive'); 50 | header('Expires: 0'); 51 | echo $this->passkit; 52 | } 53 | 54 | /* 55 | * 返回生成的pkpass文件 56 | */ 57 | public function exportPass(){ 58 | $mainfest = []; 59 | $this->setTempDir(); 60 | $zip = new \ZipArchive; 61 | $zip->open($this->tempPath."pass.pkpass", \ZipArchive::CREATE | \ZipArchive::OVERWRITE); 62 | $this->passkit = json_encode($this->passkit,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); 63 | foreach(scandir($this->passDir) as $file) 64 | if(is_file($this->passDir.$file) && $file != "pass.json") 65 | $mainfest[$file] = sha1_file($this->passDir.$file); 66 | if(count($this->extendFiles))// 如果有更改额外文件,则依次添加 67 | foreach($this->extendFiles as $name => $data){ 68 | $zip->addFromString($name,$data); 69 | $mainfest[$name] = sha1($data); 70 | } 71 | $mainfest["pass.json"] = sha1($this->passkit); 72 | $this->signPass($mainfest); 73 | foreach(scandir($this->passDir) as $file) 74 | if(is_file($this->passDir.$file) && $file != "pass.json") 75 | $zip->addFile($this->passDir.$file,$file); 76 | $zip->addFile($this->tempPath."manifest.json","manifest.json"); 77 | $zip->addFile($this->tempPath."signature","signature"); 78 | $zip->addFromString("pass.json",$this->passkit); 79 | $zip->close(); 80 | $this->passkit = file_get_contents($this->tempPath."pass.pkpass"); 81 | return $this->passkit; 82 | } 83 | 84 | /* 85 | * 对mainfest进行签名 86 | */ 87 | private function signPass(Array $mainfest){ 88 | $certs = []; 89 | file_put_contents($this->tempPath."manifest.json",json_encode($mainfest,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)); 90 | try{ 91 | openssl_pkcs12_read(file_get_contents($this->certPath), $certs, $this->certPassword); 92 | $openssl_args = [ 93 | $this->tempPath."manifest.json", 94 | $this->tempPath."signature", 95 | openssl_x509_read($certs['cert']), 96 | openssl_pkey_get_private($certs['pkey'], $this->certPassword), 97 | [], 98 | PKCS7_BINARY | PKCS7_DETACHED, 99 | $this->wwdrPath 100 | ]; 101 | call_user_func_array('openssl_pkcs7_sign', $openssl_args); 102 | }catch(Exception $e){ 103 | return $e->getMessage(); 104 | } 105 | if(!is_file($this->tempPath."signature")) 106 | return false; 107 | $signature = file_get_contents($this->tempPath."signature"); 108 | $begin = 'filename="smime.p7s"'; 109 | $end = '------'; 110 | $signature = substr($signature, strpos($signature, $begin) + strlen($begin)); 111 | $signature = substr($signature, 0, strpos($signature, $end)); 112 | $signature = trim($signature); 113 | $signature = base64_decode($signature); 114 | file_put_contents($this->tempPath."signature", $signature); 115 | return true; 116 | } 117 | 118 | /* 119 | * 提供一个可用的临时目录 120 | */ 121 | private function setTempDir(){ 122 | $dir = sys_get_temp_dir() . '/passkit-'.time() . '/'; 123 | if(!is_dir($dir)) 124 | mkdir($dir,0777); 125 | $this->tempPath = $dir; 126 | return true; 127 | } 128 | } 129 | --------------------------------------------------------------------------------