PHP实现支持CURL字符串证书传输的方法

背景

最近在对接微信支付的时候,需要在退款处用到证书,由于我们是SAAS平台,要支持多方多渠道支付,如果把所有证书文件保存在应用服务器会受到SLB的影响,会导致某台机器文件不同步而阻碍退款流程,但把文件存在OSS的话,后端又要从OSS下载到应用服务器来保证一致性。思来想去,最终决定将证书内容保存在数据库,不同客户各对应一份证书文件,无论几台机器做集群都能保证文件的一致性,同时也避免了多余的下载步骤。

问题

但是刚做就遇到了问题,PHP的CURL证书并不支持字符串的传输,只能填写证书路径(以下是官方的说法)

Client certificates must be specified by a path expression to a certificate store.

解决过程

我第一个想到的就是创建空白文件,将证书内容写进去,等证书使用完毕后再将文件删除,但是创建实体文件再删除的操作消耗性能不说,还非常麻烦,有没有创建临时文件的方法呢?有,tmpfile()函数就可以帮我们创建临时文件并拿到文件路径,于是我写了一个获取临时文件路径的方法

<?php
 public function getTmpPathByContent($content)
 {
  $tmpFile = tmpfile();
  fwrite($tmpFile, $content);
  $tempPemPath = stream_get_meta_data($tmpFile);
  return $tempPemPath['uri']; ///tmp/phpXZCtAO
 }
?>

比较悲哀的是,通过这个方法返回的路径根本读不到内容,甚至一度以为是不是被骗了

file_get_contents(/tmp/phpyyiOZv): failed to open stream: No such file or directory

看了官方文档才找到原因,如果tmpfile()返回的句柄引用计数为0的话就会将临时文件回收,临时路径自然也就失效了,显然方法getTmpPathByContent()执行完后,局部变量$tmpFile的生命周期就结束了(官方文档如下)

The file is automatically removed when closed (for example, by calling fclose(), or when there are no remaining references to the file handle returned by tmpfile()), or when the script ends.

确认了根源,那我们现在亟需找到一个生命周期随进程结束而终止的变量类型来保存句柄,什么类型能满足条件呢?静态变量。静态变量与局部变量不同的是,在PHP生命周期开始时便会为其分配内存空间,并会把它存储在全局变量区域,而全局变量是在模块关闭阶段销毁的,这样的话,声明静态变量就可以使$tmpFile引用计数持续保持大于0的状态,那我们的代码就可以做出如下处理

<?php
 public function getTmpPathByContent($content)
 {
  static $tmpFile = null;
  $tmpFile = tmpfile();
  fwrite($tmpFile, $content);
  $tempPemPath = stream_get_meta_data($tmpFile);
  return $tempPemPath['uri'];
 }
?>

再执行一次就成功读取了临时文件的内容

-----BEGIN CERTIFICATE-----
MIIEbDCCA9WgAwIBAgIEAWJKHDANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC
Q04xEjAQBgNVBAgTCUd1YW5nZG9uZzERMA8GA1UEBxMIU2hlbnpoZW4xEDAOBgNV
BAoTB1RlbmNlbnQxDDAKBgNVBAsTA1dYRzETMBEGA1UEAxMKTW1wYXltY2hDQTEf
MB0GCSqGSIb3DQEJARYQbW1wYXltY2hAdGVuY2VudDAeFw0xNzA4MDcwOTIxNDda
Fw0yNzA4MDUwOTIxNDdaMIGbMQswCQYDVQQGEwJDTjESMBAGA1UECBMJR3Vhbmdk
b25nMREwDwYDVQQHEwhTaGVuemhlbjEQMA4GA1UEChMHVGVuY2VudDEOMAwGA1UE
CxMFTU1QYXkxMDAuBgNVBAMUJ+a3seWcs+W4guaYjua6kOi9r+S7tuiCoeS7veac
iemZkOWFrOWPuDERMA8GA1UEBBMIMTAyNTkyODEwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDg2D3++uOxY/yMGQPBnROvyYimnCsfGE0dnqdGUTCykqBh
yfv82zE1/St/4DQX2QDiIvLif+sMGcYwF4bkzdY+HgitYLI0k5o/5LCNZOMctuio
kdYC2bNdWHq2y9S5UWLQR1Zvq+6QyPBVBVY9yq9xtQhIlUTsZnICAp3iQLfQUR3l
aEdH9IERoRUIkbyb8oX5ONQz4P9jOeE9C5iwx0QrH4s01NFhkhr8JHlugRLpo9vA
xGgi/48fOlONj6wWal5Gt0OvvEbIwgQwya15KBX2YeGnZvYBQa+lQMeXEqZSFie3
G+wGvbtlONczQEtp+JDxLZLUS/FT7U0TQN/t8JDvAgMBAAGjggFGMIIBQjAJBgNV
HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh0iQ0VTLUNBIEdlbmVyYXRlIENlcnRpZmlj
YXRlIjAdBgNVHQ4EFgQUjDJ75bu3Roog7XOH6uFAdZ6kpcIwgb8GA1UdIwSBtzCB
tIAUPgUm9iJitBVbiM1kfrDUYqflhnShgZCkgY0wgYoxCzAJBgNVBAYTAkNOMRIw
EAYDVQQIEwlHdWFuZ2RvbmcxETAPBgNVBAcTCFNoZW56aGVuMRAwDgYDVQQKEwdU
ZW5jZW50MQwwCgYDVQQLEwNXWEcxEzARBgNVBAMTCk1tcGF5bWNoQ0ExHzAdBgkq
hkiG9w0BCQEWEG1tcGF5bWNoQHRlbmNlbnSCCQC7VJcrvADoVzAOBgNVHQ8BAf8E
BAMCBsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEA
ucJLJkkHxlqQCEapZOWmySutqNVZxFbqyG//UXxxpA/1yG4e+KmufKZWv+c+MtYI
8i0KDDCv/UE+kkFIrHYDDKsdLRpxrYOUHGoqq0c7yBJ6Dimgy6m8U8FsEv3HtUR2
8g5xrg2Tc5MPWEp9ncEw575hGk0CXLDGOkI1nU+pGqk=
-----END CERTIFICATE-----

下面就可以把生成的临时文件地址设置到CURLOPT_SSLCERT了

<?php
 $sslCertPath = getTmpPathByContent($content);
 curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath);
 //......
?>

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • PHP使用OB缓存实现静态化功能示例

    本文实例讲述了PHP使用OB缓存实现静态化功能.分享给大家供大家参考,具体如下: 实现步骤 1.创建测试数据表并且写入数据 2.实现后台的更新操作.使用OB缓存针对每一个内容生成对应的HTML文件 3.显示前台的数据信息 具体实现 ①创建测试数据表并且写入数据(test.sql文件): #创建数据表 create table news( id int auto_increment, title varchar(100) not null default '', body text, primar

  • PHP自动载入类文件函数__autoload的使用方法

    开发面向对象的应用程序时,往往要对每个类的定义建立一个 PHP 源文件.这样的做法产生的一个很大的烦恼就是不得不在每个脚本(每个类一个文件)开头写一个长长的包含文件的列表. 在PHP开发的系统中,当在一个文件中需要调用另一个PHP文件中声明的类时,就需要通过include或require把这个文件引入.不过有的时候,在文件众多的项目中,要一一将所需类的文件都包含进来,是一个让人很头疼的事,所以我们能不能在用到什么类的时候,再把这个类所在的php文件导入呢?这就是我们这里我们要讲的自动加载类. 在

  • PHP使用mysqli同时执行多条sql查询语句的实例

    PHP数据库操作中,mysqli相对于mysql有很大的优势,建议大家使用:之前我们有介绍过如何在PHP5中使用mysqli的prepare操作数据库,使用mysqli更是支持多查询特性,请看下面这段php代码: <?php $mysqli = new mysqli("localhost","root","","123456"); $mysqli->query("set names 'utf8'"

  • PHP随机数函数rand()与mt_rand()的讲解

    PHP中rand()与mt_rand()都是用于产生一个指定范围内单独随机数的函数,如果需要产生多个不重复的随机数,请参考:PHP生成指定范围内的N个不重复的随机数. 既然他们都是用于产生一个随机数,那么他们有什么区别呢? rand() 函数默认使用 libc 随机数发生器,很多老的 libc 的随机数发生器具有一些不确定和未知的特性而且效率很低:mt_rand() 则是用了 Mersenne Twister 中已知的特性作为随机数发生器,它产生随机数值的平均速度比 libc 提供的 rand(

  • PHP SESSION机制的理解与实例

    PHP SESSION的保存机制有两种方式,session.save_handler = files和session.save_handler = user,具体选用哪种方式保存,可以通过配置php.ini文件实现. 一.使用读写文件的方式保存 SESSION 数据(session.save_handler = files) 1. session_start() (1). session_start()是session机制的开始,它有一定概率开启垃圾回收,因为session是存放在文件中,PHP

  • php微信扫码支付 php公众号支付

    本文实例为大家分享了php微信扫码支付,公众号支付的具体代码,供大家参考,具体内容如下 <?php # 微信统一下单接口 $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $param = [ 'appid' => '公众号id', 'mch_id' => '商户id', 'nonce_str' =>uniqid(), 'sign_type' => 'MD5', 'body' => 'test', 'det

  • PHP错误提示It is not safe to rely on the system……的解决方法

    在php程序开发中有时会出现类似于这样的警告: PHP Warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are

  • PHP生成短网址的思路以及实现方法的详解

    短网址流行已经有一段时间了,尤其是在新浪微博上更是频繁出现,但应该很多人都不知道这个东东是怎么实现的,其实短网址也挺容易的.下面我们对于生成短网址的思路以及使用php生成短网址的实现方法描述一下. 生成短网址的思路:如果把短网址还原了,你知道是个什么样子的吗?可能你看到新浪微博应用里面的短网址都是这个样子: http://t.cn/RzddsXt 其实他还原了说不定就是这个样子: http://t.cn/link.php?url=//www.jb51.net/ 按这个格式可以知道这个短网址其实是

  • PHP中命名空间的使用例子

    程序语言中的命名空间指的是一种特殊的作用域,它包含处于该作用域下的标识符,同时它本身也是一种标识符.可以把命名空间与操作系统的目录对应起来.一个命名空间相当于一个目录,命名空间里的类,函数,常量,相当于目录里的文件.同一个目录(命名空间)里的文件名不能相同,但是不同的目录里可以有相同名字的文件. 使用命名空间可以解决名字冲突,比如定义了一个类,正好这个类与PHP内部的类或是include进来的一个类库里的类重名的时候.同时,命名空间还可以提高代码可读性,命名空间有一个别名功能,它可以帮你给一个长

  • 详解PHP变量传值赋值和引用赋值变量销毁

    本文实例为大家分享了PHP变量传值赋值和引用赋值变量销毁的具体代码,供大家参考,具体内容如下 <?php $a = 100; $b = 200; var_dump($a,$b); //int(100) int(200) ?> php中,上面的代码,变量是怎么存放的呢? 上面的代码变动下,将变量b赋值给变量a,会发生什么? <?php $a = 100; $b = 200; $a = $b;/*多了这个*/ var_dump($a,$b); //int(200) int(200) ?>

随机推荐