| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Class CRM_Cxn_CiviCxnHttp |
| 5 | * |
| 6 | * This extends the PhpHttp client used by CiviConnect and adds: |
| 7 | * - Force-cache support for GET requests |
| 8 | * - Compliance with SSL policy |
| 9 | */ |
| 10 | class CRM_Cxn_CiviCxnHttp extends \Civi\Cxn\Rpc\Http\PhpHttp { |
| 11 | |
| 12 | protected static $singleton = NULL; |
| 13 | |
| 14 | /** |
| 15 | * @var CRM_Utils_Cache_Interface|null |
| 16 | */ |
| 17 | protected $cache; |
| 18 | |
| 19 | /** |
| 20 | * @param bool $fresh |
| 21 | * @return CRM_Cxn_CiviCxnHttp |
| 22 | */ |
| 23 | public static function singleton($fresh = FALSE) { |
| 24 | if (self::$singleton === NULL || $fresh) { |
| 25 | $cache = CRM_Utils_Cache::create(array( |
| 26 | 'name' => 'CiviCxnHttp', |
| 27 | 'type' => Civi::settings()->get('debug_enabled') ? 'ArrayCache' : array('SqlGroup', 'ArrayCache'), |
| 28 | 'prefetch' => FALSE, |
| 29 | )); |
| 30 | |
| 31 | self::$singleton = new CRM_Cxn_CiviCxnHttp($cache); |
| 32 | } |
| 33 | return self::$singleton; |
| 34 | } |
| 35 | |
| 36 | /** |
| 37 | * @param CRM_Utils_Cache_Interface|NULL $cache |
| 38 | * The cache data store. |
| 39 | */ |
| 40 | public function __construct($cache) { |
| 41 | $this->cache = $cache; |
| 42 | } |
| 43 | |
| 44 | /** |
| 45 | * @param string $verb |
| 46 | * @param string $url |
| 47 | * @param string $blob |
| 48 | * @param array $headers |
| 49 | * Array of headers (e.g. "Content-type" => "text/plain"). |
| 50 | * @return array |
| 51 | * array($headers, $blob, $code) |
| 52 | */ |
| 53 | public function send($verb, $url, $blob, $headers = array()) { |
| 54 | $lowVerb = strtolower($verb); |
| 55 | |
| 56 | if ($lowVerb === 'get' && $this->cache) { |
| 57 | $cachePath = 'get/' . md5($url); |
| 58 | $cacheLine = $this->cache->get($cachePath); |
| 59 | if ($cacheLine && $cacheLine['expires'] > CRM_Utils_Time::getTimeRaw()) { |
| 60 | return $cacheLine['data']; |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | $result = parent::send($verb, $url, $blob, $headers); |
| 65 | |
| 66 | if ($lowVerb === 'get' && $this->cache) { |
| 67 | $expires = CRM_Utils_Http::parseExpiration($result[0]); |
| 68 | if ($expires !== NULL) { |
| 69 | $cachePath = 'get/' . md5($url); |
| 70 | $cacheLine = array( |
| 71 | 'url' => $url, |
| 72 | 'expires' => $expires, |
| 73 | 'data' => $result, |
| 74 | ); |
| 75 | $this->cache->set($cachePath, $cacheLine); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | return $result; |
| 80 | } |
| 81 | |
| 82 | /** |
| 83 | * Create stream options. |
| 84 | * |
| 85 | * @param string $verb |
| 86 | * @param string $url |
| 87 | * @param string $blob |
| 88 | * @param array $headers |
| 89 | * |
| 90 | * @return array |
| 91 | * @throws \Exception |
| 92 | */ |
| 93 | protected function createStreamOpts($verb, $url, $blob, $headers) { |
| 94 | $result = parent::createStreamOpts($verb, $url, $blob, $headers); |
| 95 | |
| 96 | $caConfig = CA_Config_Stream::probe(array( |
| 97 | 'verify_peer' => (bool) Civi::settings()->get('verifySSL'), |
| 98 | )); |
| 99 | if ($caConfig->isEnableSSL()) { |
| 100 | $result['ssl'] = $caConfig->toStreamOptions(); |
| 101 | } |
| 102 | if (!$caConfig->isEnableSSL() && preg_match('/^https:/', $url)) { |
| 103 | CRM_Core_Error::fatal('Cannot fetch document - system does not support SSL'); |
| 104 | } |
| 105 | |
| 106 | return $result; |
| 107 | } |
| 108 | |
| 109 | } |