PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/phpab.php

http://github.com/briancray/phpA-B
PHP | 301 lines | 252 code | 42 blank | 7 comment | 50 complexity | 095ca27df2a5ed551b36b0198a5dcb94 MD5 | raw file
  1. <?php
  2. /*
  3. Name : phpA/B v1.2
  4. Author : Brian Cray
  5. License : GPL 2.0
  6. License URL : http://www.gnu.org/licenses/gpl-2.0.html
  7. URL : phpabtest.com
  8. */
  9. class phpab
  10. {
  11. private $variations = array();
  12. private $current_variation = '!unset';
  13. private $current_variation_key;
  14. private $test_name;
  15. private $test_ran = FALSE;
  16. private $trial_mode = FALSE;
  17. private $content;
  18. private $tag = 'phpab';
  19. private $auto_ga = TRUE;
  20. private $ga_slot = 1;
  21. private $test_domain;
  22. private $detect_bots = TRUE;
  23. private $is_bot = FALSE;
  24. private $version = '1.2';
  25. function __construct ($n, $t = FALSE)
  26. {
  27. if($this->detect_bots == TRUE)
  28. {
  29. $bots = array('googlebot', 'msnbot', 'slurp', 'ask jeeves', 'crawl', 'ia_archiver', 'lycos');
  30. foreach($bots as $botname)
  31. {
  32. if(stripos($_SERVER['HTTP_USER_AGENT'], $botname) !== FALSE)
  33. {
  34. $this->trial_mode = TRUE;
  35. $this->is_bot = TRUE;
  36. break;
  37. }
  38. }
  39. }
  40. if($this->is_bot == FALSE)
  41. {
  42. $this->trial_mode = $t;
  43. }
  44. ob_start(array($this, 'execute'));
  45. $this->test_domain = '.' . $_SERVER['HTTP_HOST'];
  46. $n = trim(strtolower($n));
  47. $n = preg_replace('/[^a-z0-9 _]*/', '', $n);
  48. $n = str_replace(' ', '_', $n);
  49. $this->test_name = $n;
  50. }
  51. function __destruct ()
  52. {
  53. ob_end_flush();
  54. }
  55. private function grab_content ()
  56. {
  57. if(empty($this->content))
  58. {
  59. $this->content = ob_get_contents();
  60. }
  61. }
  62. private function setup_ga ()
  63. {
  64. $try_auto = FALSE;
  65. $sync = '{' . $this->tag . ' ' . $this->test_name . ' ga_sync}';
  66. $async = '{' . $this->tag . ' ' . $this->test_name . ' ga_async}';
  67. $syncPos = strpos($this->content, $sync);
  68. if($syncPos !== FALSE)
  69. {
  70. $this->content = str_replace($sync, 'pageTracker._setCustomVar(' . $this->ga_slot . ', "' . $this->test_name . '", "' . $this->current_variation . '", 3);', $this->content);
  71. }
  72. else
  73. {
  74. $asyncPos = strpos($this->content, $async);
  75. if($asyncPos !== FALSE)
  76. {
  77. $this->content = str_replace($async, '_gaq.push(["_setCustomVar", ' . $this->ga_slot . ', "' . $this->test_name . '", "' . $this->current_variation . '", 3]);', $this->content);
  78. }
  79. else
  80. {
  81. $try_auto = TRUE;
  82. }
  83. }
  84. if($this->auto_ga == TRUE && $try_auto == TRUE)
  85. {
  86. $sync = strpos($this->content, 'pageTracker._trackPageview');
  87. if($sync === FALSE)
  88. {
  89. $async = preg_match('/_gaq\.push\(\[[\'\"]_trackPageview[\'\"]\]\)/', $this->content, $matches, PREG_OFFSET_CAPTURE);
  90. if($async == FALSE)
  91. {
  92. $auto_fail = TRUE;
  93. $async = FALSE;
  94. }
  95. else
  96. {
  97. $auto_fail = FALSE;
  98. $async = $matches[0][1];
  99. }
  100. }
  101. else
  102. {
  103. $auto_fail = FALSE;
  104. }
  105. if($auto_fail === FALSE && $sync !== FALSE)
  106. {
  107. $this->content = substr($this->content, 0, $sync - 1) . 'pageTracker._setCustomVar(' . $this->ga_slot . ', "' . $this->test_name . '", "' . $this->current_variation . '", 3);' . substr($this->content, $sync);
  108. }
  109. elseif($auto_fail === FALSE && $async !== FALSE)
  110. {
  111. $this->content = substr($this->content, 0, $async - 1) . ' _gaq.push(["_setCustomVar", ' . $this->ga_slot . ', "' . $this->test_name . '", "' . $this->current_variation . '", 3]); ' . substr($this->content, $async);
  112. }
  113. }
  114. }
  115. private function record_user_segment ()
  116. {
  117. $cookie_domain = (($colon_position = strrpos($this->test_domain, ":")) === false) ? $this->test_domain : substr($this->test_domain, 0, $colon_position);
  118. setcookie($this->tag . '-' . $this->test_name, $this->current_variation, time() + (60 * 60 * 24 * 365), '/', $cookie_domain);
  119. }
  120. public function set_domain ($d)
  121. {
  122. $this->test_domain = !empty($d) ? $d : '.' . $_SERVER['HTTP_HOST'];
  123. }
  124. public function set_ga_slot ($s)
  125. {
  126. $this->ga_slot = $s;
  127. }
  128. public function set_ga_mode ($m)
  129. {
  130. $this->ga_auto = $m;
  131. }
  132. public function set_tag ($t)
  133. {
  134. $this->tag = $t;
  135. }
  136. public function add_variation ($n, $v = '')
  137. {
  138. $n = trim(strtolower($n));
  139. $n = preg_replace('/[^a-z0-9 _]*/', '', $n);
  140. $n = str_replace(' ', '_', $n);
  141. array_push($this->variations, array('name' => $n, 'value' => $v));
  142. }
  143. public function get_user_segment ()
  144. {
  145. if($this->current_variation != '!unset' && $this->current_variation_key != -1)
  146. {
  147. return $this->current_variation;
  148. }
  149. if ($this->is_bot == TRUE)
  150. {
  151. $this->current_variation = 'control';
  152. return $this->current_variation;
  153. }
  154. if (get_magic_quotes_gpc() == TRUE)
  155. {
  156. $_COOKIE[$this->tag . '-' . $this->test_name] = stripslashes($_COOKIE[$this->tag . '-' . $this->test_name]);
  157. }
  158. if($this->trial_mode == FALSE)
  159. {
  160. $key = $this->tag . '-' . $this->test_name;
  161. if(array_key_exists($key, $_COOKIE))
  162. {
  163. $this->current_variation = $_COOKIE[$key];
  164. }
  165. if(empty($this->current_variation))
  166. {
  167. $this->current_variation = '!unset';
  168. }
  169. }
  170. else
  171. {
  172. $this->current_variation = '!unset';
  173. }
  174. array_unshift($this->variations, array('name' => 'control', 'value' => ''));
  175. $valid = FALSE;
  176. $this->current_variation_key = 0;
  177. foreach($this->variations as $n => $v)
  178. {
  179. if($v['name'] == $this->current_variation)
  180. {
  181. $valid = TRUE;
  182. break;
  183. }
  184. $this->current_variation_key++;
  185. }
  186. if($this->current_variation == '!unset' || $valid == FALSE)
  187. {
  188. srand((double)microtime() * 1000003);
  189. $this->current_variation_key = array_rand($this->variations);
  190. $this->current_variation = $this->variations[$this->current_variation_key]['name'];
  191. }
  192. return $this->current_variation;
  193. }
  194. public function execute ($buffer)
  195. {
  196. $this->content = $buffer;
  197. if($this->test_ran == FALSE)
  198. {
  199. $this->run_test();
  200. }
  201. if($this->trial_mode != TRUE)
  202. {
  203. $this->setup_ga();
  204. }
  205. $tmp = $this->content;
  206. $this->content = preg_replace('/<body([^>]*?)class="([^"]*?)"([^>]*?)>/i', '<body${1}class="${2} ' . $this->tag . '-' . $this->current_variation . '"${3}>', $this->content);
  207. if($tmp == $this->content)
  208. {
  209. $this->content = preg_replace('/<body([^>]*?)>/i', '<body${1} class="' . $this->tag . '-' . $this->current_variation . '">', $this->content);
  210. }
  211. unset($tmp);
  212. $pos = strrpos($this->content, '</body>');
  213. if($pos !== false)
  214. {
  215. $this->content = substr_replace($this->content, '<!--A/B tests active with phpA/B ' . $this->version . '--></body>', $pos, strlen('</body>'));
  216. }
  217. $this->content = str_replace('{' . $this->tag . ' ' . $this->test_name . ' current_varation}', $this->current_variation, $this->content);
  218. if($this->trial_mode != TRUE)
  219. {
  220. $this->record_user_segment();
  221. }
  222. return $this->content;
  223. }
  224. public function run_test ()
  225. {
  226. $this->get_user_segment();
  227. $this->grab_content();
  228. $open_tag = '{' . $this->tag . ' ' . $this->test_name . '}';
  229. $close_tag = '{/' . $this->tag . ' ' . $this->test_name . '}';
  230. $test_open = strpos($this->content, $open_tag);
  231. $test_close = strpos($this->content, $close_tag);
  232. while($test_open !== FALSE)
  233. {
  234. if($this->current_variation != 'control')
  235. {
  236. if($test_close === FALSE && $test_open !== FALSE)
  237. {
  238. $this->content = substr_replace($this->content, $this->variations[$this->current_variation_key]['value'], $test_open, strlen($open_tag));
  239. }
  240. elseif($test_close !== FALSE && $test_open !== FALSE)
  241. {
  242. $diff = $test_close + strlen($close_tag) - $test_open;
  243. $this->content = substr_replace($this->content, $this->variations[$this->current_variation_key]['value'], $test_open, $diff);
  244. }
  245. else
  246. {
  247. }
  248. }
  249. else
  250. {
  251. $this->content = str_replace($open_tag, $this->variations[$this->current_variation_key]['value'], $this->content);
  252. $this->content = str_replace($close_tag, '', $this->content);
  253. }
  254. $test_open = strpos($this->content, $open_tag, $test_open);
  255. $test_close = strpos($this->content, $close_tag, $test_open);
  256. }
  257. $this->test_ran = TRUE;
  258. }
  259. }