/lib/ConsumerStrategies/CurlConsumer.php

https://gitlab.com/Blueprint-Marketing/mixpanel-php · PHP · 221 lines · 118 code · 38 blank · 65 comment · 24 complexity · ea182301f1f7f65b1c970be6d987c1b4 MD5 · raw file

  1. <?php
  2. require_once(dirname(__FILE__) . "/AbstractConsumer.php");
  3. /**
  4. * Consumes messages and sends them to a host/endpoint using cURL
  5. */
  6. class ConsumerStrategies_CurlConsumer extends ConsumerStrategies_AbstractConsumer {
  7. /**
  8. * @var string the host to connect to (e.g. api.mixpanel.com)
  9. */
  10. protected $_host;
  11. /**
  12. * @var string the host-relative endpoint to write to (e.g. /engage)
  13. */
  14. protected $_endpoint;
  15. /**
  16. * @var int connect_timeout The number of seconds to wait while trying to connect. Default is 5 seconds.
  17. */
  18. protected $_connect_timeout;
  19. /**
  20. * @var int timeout The maximum number of seconds to allow cURL call to execute. Default is 30 seconds.
  21. */
  22. protected $_timeout;
  23. /**
  24. * @var string the protocol to use for the cURL connection
  25. */
  26. protected $_protocol;
  27. /**
  28. * @var bool|null true to fork the cURL process (using exec) or false to use PHP's cURL extension. false by default
  29. */
  30. protected $_fork = null;
  31. /**
  32. * Creates a new CurlConsumer and assigns properties from the $options array
  33. * @param array $options
  34. * @throws Exception
  35. */
  36. function __construct($options) {
  37. parent::__construct($options);
  38. $this->_host = $options['host'];
  39. $this->_endpoint = $options['endpoint'];
  40. $this->_connect_timeout = array_key_exists('connect_timeout', $options) ? $options['connect_timeout'] : 5;
  41. $this->_timeout = array_key_exists('timeout', $options) ? $options['timeout'] : 30;
  42. $this->_protocol = array_key_exists('use_ssl', $options) && $options['use_ssl'] == true ? "https" : "http";
  43. $this->_fork = array_key_exists('fork', $options) ? ($options['fork'] == true) : false;
  44. // ensure the environment is workable for the given settings
  45. if ($this->_fork == true) {
  46. $exists = function_exists('exec');
  47. if (!$exists) {
  48. throw new Exception('The "exec" function must exist to use the cURL consumer in "fork" mode. Try setting fork = false or use another consumer.');
  49. }
  50. $disabled = explode(', ', ini_get('disable_functions'));
  51. $enabled = !in_array('exec', $disabled);
  52. if (!$enabled) {
  53. throw new Exception('The "exec" function must be enabled to use the cURL consumer in "fork" mode. Try setting fork = false or use another consumer.');
  54. }
  55. } else {
  56. if (!function_exists('curl_init')) {
  57. throw new Exception('The cURL PHP extension is required to use the cURL consumer with fork = false. Try setting fork = true or use another consumer.');
  58. }
  59. }
  60. }
  61. /**
  62. * Write to the given host/endpoint using either a forked cURL process or using PHP's cURL extension
  63. * @param array $batch
  64. * @return bool
  65. */
  66. public function persist($batch) {
  67. if (count($batch) > 0) {
  68. $data = "data=" . $this->_encode($batch);
  69. $url = $this->_protocol . "://" . $this->_host . $this->_endpoint;
  70. if ($this->_fork) {
  71. return $this->_execute_forked($url, $data);
  72. } else {
  73. return $this->_execute($url, $data);
  74. }
  75. } else {
  76. return true;
  77. }
  78. }
  79. /**
  80. * Write using the cURL php extension
  81. * @param $url
  82. * @param $data
  83. * @return bool
  84. */
  85. protected function _execute($url, $data) {
  86. if ($this->_debug()) {
  87. $this->_log("Making blocking cURL call to $url");
  88. }
  89. $ch = curl_init();
  90. curl_setopt($ch, CURLOPT_URL, $url);
  91. curl_setopt($ch, CURLOPT_HEADER, 0);
  92. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->_connect_timeout);
  93. curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout);
  94. curl_setopt($ch, CURLOPT_POST, 1);
  95. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  96. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  97. $response = curl_exec($ch);
  98. if (false === $response) {
  99. $curl_error = curl_error($ch);
  100. $curl_errno = curl_errno($ch);
  101. curl_close($ch);
  102. $this->_handleError($curl_errno, $curl_error);
  103. return false;
  104. } else {
  105. curl_close($ch);
  106. if (trim($response) == "1") {
  107. return true;
  108. } else {
  109. $this->_handleError(0, $response);
  110. return false;
  111. }
  112. }
  113. }
  114. /**
  115. * Write using a forked cURL process
  116. * @param $url
  117. * @param $data
  118. * @return bool
  119. */
  120. protected function _execute_forked($url, $data) {
  121. if ($this->_debug()) {
  122. $this->_log("Making forked cURL call to $url");
  123. }
  124. $exec = 'curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d ' . $data . ' "' . $url . '"';
  125. if(!$this->_debug()) {
  126. $exec .= " >/dev/null 2>&1 &";
  127. }
  128. exec($exec, $output, $return_var);
  129. if ($return_var != 0) {
  130. $this->_handleError($return_var, $output);
  131. }
  132. return $return_var == 0;
  133. }
  134. /**
  135. * @return int
  136. */
  137. public function getConnectTimeout()
  138. {
  139. return $this->_connect_timeout;
  140. }
  141. /**
  142. * @return string
  143. */
  144. public function getEndpoint()
  145. {
  146. return $this->_endpoint;
  147. }
  148. /**
  149. * @return bool|null
  150. */
  151. public function getFork()
  152. {
  153. return $this->_fork;
  154. }
  155. /**
  156. * @return string
  157. */
  158. public function getHost()
  159. {
  160. return $this->_host;
  161. }
  162. /**
  163. * @return array
  164. */
  165. public function getOptions()
  166. {
  167. return $this->_options;
  168. }
  169. /**
  170. * @return string
  171. */
  172. public function getProtocol()
  173. {
  174. return $this->_protocol;
  175. }
  176. /**
  177. * @return int
  178. */
  179. public function getTimeout()
  180. {
  181. return $this->_timeout;
  182. }
  183. }