PageRenderTime 121ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/includes/AdTag.php

https://github.com/liftiuminc/liftium
PHP | 307 lines | 231 code | 51 blank | 25 comment | 44 complexity | 5dfe739521743545d7d085a003aeb68e MD5 | raw file
  1. <?php
  2. class AdTag {
  3. public $tag_id;
  4. public $tag_name, $notes, $enabled, $network_id, $estimated_cpm, $threshold, $tier,
  5. $value, $tag, $guaranteed_fill, $sample_rate, $freq_cap, $rej_cap, $rej_time,
  6. $auto_update_ecpm, $reported_ecpm, $reported_date;
  7. public $as_ids = null, $options = null;
  8. public function __construct($tag_id=null){
  9. if (!is_null($tag_id)){
  10. $this->loadFromId($tag_id);
  11. }
  12. }
  13. public function loadFromId($tag_id){
  14. $dbr = Framework::getDB("slave");
  15. $sql = "SELECT *, id AS tag_id FROM tags WHERE id = ?";
  16. $sth = $dbr->prepare($sql);
  17. $sth->execute(array($tag_id));
  18. while($row = $sth->fetch(PDO::FETCH_ASSOC)){
  19. foreach($row as $column => $data){
  20. $this->$column = $data;
  21. }
  22. $this->value = round($row['value'], 2);
  23. }
  24. /*
  25. $sql = "SELECT option_name, option_value FROM tag_option WHERE tag_id=" . $dbr->quote($tag_id);
  26. $sth = $dbr->prepare($sql);
  27. $sth->execute(array($tag_id));
  28. $this->options = null;
  29. while($row = $sth->fetch(PDO::FETCH_ASSOC)){
  30. $this->options[$row['option_name']] = $row['option_value'];
  31. }
  32. */
  33. }
  34. public function getSizes(){
  35. $out = array();
  36. $dbr = Framework::getDB("slave");
  37. $sql = "SELECT size FROM ad_formats";
  38. $sth = $dbr->prepare($sql);
  39. $sth->execute();
  40. while($row = $sth->fetch(PDO::FETCH_ASSOC)){
  41. $out[] = $row['size'];
  42. }
  43. return $out;
  44. }
  45. private function saveSlots(){
  46. if (is_null($this->as_ids)){ // Note that if you want to clear slots, set $this->as_ids to an empty array
  47. return false;
  48. }
  49. if(empty($this->tag_id)){
  50. trigger_error("tag_id must be set for saveSlots()", E_USER_WARNING);
  51. return false;
  52. }
  53. $dbw = Framework::getDB("master");
  54. $dbw->exec("BEGIN");
  55. $dbw->exec("DELETE FROM tag_slot_linking WHERE tag_id =" . $dbw->quote($this->tag_id));
  56. if (!empty($this->as_ids)){
  57. $sql = "INSERT INTO tag_slot_linking VALUES ";
  58. foreach($this->as_ids as $as_id){
  59. $sql.="($this->tag_id, $as_id),";
  60. }
  61. $sql = preg_replace('/,$/', ';', $sql);
  62. $ret = $dbw->exec($sql);
  63. }
  64. $dbw->exec("COMMIT");
  65. return $ret;
  66. }
  67. private function saveOptions(){
  68. if (is_null($this->options)){ // Note that if you want to clear options, set $this->options to an empty array
  69. return false;
  70. }
  71. if(empty($this->tag_id)){
  72. trigger_error("tag_id must be set for saveOptions()", E_USER_WARNING);
  73. return false;
  74. }
  75. $dbw = Framework::getDB("master");
  76. $dbw->exec("BEGIN");
  77. $dbw->exec("DELETE FROM tag_option WHERE tag_id = " . $dbw->quote($this->tag_id));
  78. if (!empty($this->options)){
  79. $sql = "INSERT INTO tag_option VALUES ";
  80. $values = 0;
  81. foreach($this->options as $on => $ov){
  82. if ($ov == ''){
  83. continue; // Don't store empty values
  84. }
  85. else {
  86. $values++;
  87. }
  88. $sql .= "($this->tag_id, " . $dbw->quote($on) . "," .$dbw->quote($ov) . "),";
  89. }
  90. $sql = preg_replace('/,$/', ';', $sql);
  91. if($values) {
  92. $ret = $dbw->exec($sql);
  93. }
  94. }
  95. $dbw->exec("COMMIT");
  96. return $ret;
  97. }
  98. static public function searchTags($criteria=array(), $objects = true){
  99. $dbr = Framework::getDB("slave");
  100. /* The idea behind weighted_random_value is that we want to sort items
  101. * within the same tier randomly (to take advantage of cream skimming)
  102. * But we also want to favor the higher paying ads
  103. */
  104. $values = array();
  105. $sql = "SELECT SQL_SMALL_RESULT /* Tell mysql to use in memory temp tables */
  106. tags.id AS tag_id FROM tags
  107. INNER JOIN networks on tags.network_id = networks.id
  108. WHERE 1=1";
  109. if (!empty($criteria['name_search'])){
  110. $search = '%' . $criteria['name_search'] . '%';
  111. $sql .= "\n\tAND tag_name like ? ";
  112. $values[] = $search;
  113. }
  114. if (!empty($criteria['enabled'])){
  115. $sql .= "\n\tAND tags.enabled = ? ";
  116. $values[] = $criteria['enabled'];
  117. $sql .= "\n\tAND networks.enabled = ? ";
  118. $values[] = $criteria['enabled'];
  119. }
  120. if (!empty($criteria['network_id'])){
  121. $sql .= "\n\tAND network_id = ? ";
  122. $values[] = $criteria['network_id'];
  123. }
  124. if (!empty($criteria['pubid'])){
  125. $sql .= "\n\tAND publisher_id = ? ";
  126. $values[] = $criteria['pubid'];
  127. if (!empty($criteria['brand_safety_level_check'])){
  128. $sql .= "\n\tAND networks.brand_safety_level >=" .
  129. " (SELECT brand_safety_level FROM publishers WHERE publishers.id = ? )";
  130. $values[] = $criteria['pubid'];
  131. }
  132. }
  133. if (!empty($criteria['size'])){
  134. $sql .= "\n\tAND size = ? ";
  135. $values[] = $criteria['size'];
  136. }
  137. if (!empty($criteria['auto_update_ecpm'])){
  138. $sql .= "\n\tAND auto_update_ecpm = ? ";
  139. $values[] = $criteria['auto_update_ecpm'];
  140. }
  141. switch (@$criteria['sort']){
  142. case 'name': $sql.= "\n\tORDER BY tag_name"; break;
  143. default: $sql.= "\n\tORDER BY tier DESC, value DESC"; break;
  144. }
  145. if (intval(@$criteria['limit']) > 0 ){
  146. $sql .= " LIMIT ?";
  147. $values[] = $criteria['limit'];
  148. }
  149. if (intval(@$criteria['offset']) > 0 ){
  150. $sql .= " OFFSET ?";
  151. $values[] = $criteria['offset'];
  152. }
  153. if (!empty($_GET['debug'])){
  154. echo "<xmp>" . $sql . ", " . print_r($values, true) . "</xmp>";
  155. }
  156. $out = array();
  157. $sth = $dbr->prepare($sql);
  158. $sth->execute($values);
  159. while($row = $sth->fetch(PDO::FETCH_ASSOC)){
  160. if ($objects){
  161. $out[] = new AdTag($row['tag_id']);
  162. } else {
  163. $out[] = $row['tag_id'];
  164. }
  165. }
  166. return $out;
  167. }
  168. public function getFillStats($criteria, $tag_id = null){
  169. if (is_null($tag_id)){
  170. $tag_id = $this->tag_id;
  171. }
  172. $dbr = Framework::getDB("slave");
  173. $values = array();
  174. $sql = "SELECT SUM(attempts) AS attempts, SUM(rejects) AS rejects,
  175. SUM(loads) AS loads,
  176. SUM(loads)/SUM(attempts) AS fill_rate
  177. FROM fills_minute WHERE
  178. tag_id = ?";
  179. $values[] = $tag_id;
  180. if (!empty($criteria['since'])){
  181. $sql.= " AND minute >= ?";
  182. $values[] = date('Y-m-d H:i:00', $criteria['since']);
  183. } else if (!empty($criteria['minute'])){
  184. $sql.= " AND minute = ?";
  185. $values[] = date('Y-m-d H:i:00', $criteria['minute']);
  186. }
  187. if (!empty($_GET['debug'])){
  188. echo "AdTag::getFillStats(): $sql"; print_r($values);
  189. }
  190. $placeholder = array('attempts'=>0, 'rejects'=>0, 'loads'=>0, 'fill_rate'=>0);
  191. $sth = $dbr->prepare($sql);
  192. $sth->execute($values);
  193. $out = $sth->fetch(PDO::FETCH_ASSOC);
  194. if ($out === false || empty($out['attempts'])){
  195. return $placeholder;
  196. } else {
  197. return $out;
  198. }
  199. }
  200. /* Size is stored as $widthx$size character column. Split here.
  201. * You may be asking, why not just store it as separate values to be begin with?
  202. * Because size is not always height/width. Possible values for size include:
  203. * 728x60
  204. * 300x250,300x600
  205. * 728x*
  206. *
  207. * Do the best you can to return a height/width
  208. */
  209. public static function getHeightWidthFromSize($size){
  210. if (preg_match('/^([0-9]{2,4})x([0-9]{2,4})/', $size, $matches)){
  211. return array('width'=>$matches[1], 'height'=>$matches[2]);
  212. } else if (preg_match('/^([0-9]{2,4})x\*/', $size, $matches)){
  213. return array('width'=>$matches[1], 'height'=>'*');
  214. } else {
  215. return false;
  216. }
  217. }
  218. public static function expandMacros($tag, $tag_options){
  219. // EWW. Got a better idea?
  220. global $expandMacrosTagOptions;
  221. $expandMacrosTagOptions = $tag_options;
  222. return preg_replace_callback("/%@([a-z0-9A-Z_]+)@%/", "AdTag::expandMacrosCallback", $tag);
  223. }
  224. public static function expandMacrosCallback($matches){
  225. global $expandMacrosTagOptions;
  226. if (isset($expandMacrosTagOptions[$matches[1]])){
  227. return $expandMacrosTagOptions[$matches[1]];
  228. } else {
  229. trigger_error("Invalid macro in tag - {$matches[1]}", E_USER_NOTICE);
  230. return null;
  231. }
  232. }
  233. static public function isUnderDailyLimit($tag_id, $limit){
  234. if (empty($limit)){
  235. return true;
  236. }
  237. $dbr = Framework::getDB("slave");
  238. static $sth;
  239. if (empty($sth)){
  240. // Only prepare the statement once
  241. $sth = $dbr->prepare("SELECT SUM(attempts) AS attempts FROM fills_minute
  242. WHERE tag_id = ? AND minute >= ?");
  243. }
  244. $sth->execute(array($tag_id, date('Y-m-d')));
  245. $out = array();
  246. while($row = $sth->fetch(PDO::FETCH_ASSOC)){
  247. if (intval($row['attempts']) <= intval($limit)){
  248. return true;
  249. } else {
  250. return false;
  251. }
  252. }
  253. // Something went wrong
  254. return true;
  255. }
  256. }