Shortlinks by Pretty Links – Best WordPress Link Tracking Plugin - Version 1.3.14

Version Description

Download this release

Release Info

Developer supercleanse
Plugin Icon 128x128 Shortlinks by Pretty Links – Best WordPress Link Tracking Plugin
Version 1.3.14
Comparing to
See all releases

Version 1.3.14

Files changed (220) hide show
  1. classes/models/PrliClick.php +230 -0
  2. classes/models/PrliLink.php +214 -0
  3. classes/models/PrliUtils.php +392 -0
  4. classes/models/models.inc.php +9 -0
  5. classes/views/prli-clicks/csv.php +24 -0
  6. classes/views/prli-clicks/head.php +105 -0
  7. classes/views/prli-clicks/list.php +149 -0
  8. classes/views/prli-links/edit.php +87 -0
  9. classes/views/prli-links/head.php +44 -0
  10. classes/views/prli-links/list.php +136 -0
  11. classes/views/prli-links/new.php +87 -0
  12. classes/views/shared/errors.php +19 -0
  13. classes/views/shared/table-nav.php +93 -0
  14. images/arrow_down.png +0 -0
  15. images/arrow_up.png +0 -0
  16. images/bookmark.png +0 -0
  17. images/browser/abilon.png +0 -0
  18. images/browser/adobe.png +0 -0
  19. images/browser/akregator.png +0 -0
  20. images/browser/alcatel.png +0 -0
  21. images/browser/amaya.png +0 -0
  22. images/browser/amigavoyager.png +0 -0
  23. images/browser/analogx.png +0 -0
  24. images/browser/apt.png +0 -0
  25. images/browser/avant.png +0 -0
  26. images/browser/aweb.png +0 -0
  27. images/browser/bpftp.png +0 -0
  28. images/browser/bytel.png +0 -0
  29. images/browser/chimera.png +0 -0
  30. images/browser/chrome.png +0 -0
  31. images/browser/cyberdog.png +0 -0
  32. images/browser/da.png +0 -0
  33. images/browser/dillo.png +0 -0
  34. images/browser/doris.png +0 -0
  35. images/browser/dreamcast.png +0 -0
  36. images/browser/ecatch.png +0 -0
  37. images/browser/encompass.png +0 -0
  38. images/browser/epiphany.png +0 -0
  39. images/browser/ericsson.png +0 -0
  40. images/browser/feeddemon.png +0 -0
  41. images/browser/feedreader.png +0 -0
  42. images/browser/firefox.png +0 -0
  43. images/browser/flashget.png +0 -0
  44. images/browser/fpexpress.png +0 -0
  45. images/browser/fresco.png +0 -0
  46. images/browser/freshdownload.png +0 -0
  47. images/browser/frontpage.png +0 -0
  48. images/browser/galeon.png +0 -0
  49. images/browser/getright.png +0 -0
  50. images/browser/gnome.png +0 -0
  51. images/browser/gnus.png +0 -0
  52. images/browser/gozilla.png +0 -0
  53. images/browser/hotjava.png +0 -0
  54. images/browser/httrack.png +0 -0
  55. images/browser/ibrowse.png +0 -0
  56. images/browser/icab.png +0 -0
  57. images/browser/java.png +0 -0
  58. images/browser/jetbrains_omea.png +0 -0
  59. images/browser/kmeleon.png +0 -0
  60. images/browser/konqueror.png +0 -0
  61. images/browser/leechget.png +0 -0
  62. images/browser/lg.png +0 -0
  63. images/browser/lotusnotes.png +0 -0
  64. images/browser/lynx.png +0 -0
  65. images/browser/macweb.png +0 -0
  66. images/browser/mediaplayer.png +0 -0
  67. images/browser/motorola.png +0 -0
  68. images/browser/mozilla.png +0 -0
  69. images/browser/mplayer.png +0 -0
  70. images/browser/msie.png +0 -0
  71. images/browser/msie_large.png +0 -0
  72. images/browser/multizilla.png +0 -0
  73. images/browser/ncsa_mosaic.png +0 -0
  74. images/browser/neon.png +0 -0
  75. images/browser/netnewswire.png +0 -0
  76. images/browser/netpositive.png +0 -0
  77. images/browser/netscape.png +0 -0
  78. images/browser/netscape_large.png +0 -0
  79. images/browser/netshow.png +0 -0
  80. images/browser/newsfire.png +0 -0
  81. images/browser/newsgator.png +0 -0
  82. images/browser/newzcrawler.png +0 -0
  83. images/browser/nokia.png +0 -0
  84. images/browser/notavailable.png +0 -0
  85. images/browser/omniweb.png +0 -0
  86. images/browser/opera.png +0 -0
  87. images/browser/panasonic.png +0 -0
  88. images/browser/pdaphone.png +0 -0
  89. images/browser/philips.png +0 -0
  90. images/browser/phoenix.png +0 -0
  91. images/browser/pluck.png +0 -0
  92. images/browser/pulpfiction.png +0 -0
  93. images/browser/real.png +0 -0
  94. images/browser/rss.png +0 -0
  95. images/browser/rssbandit.png +0 -0
  96. images/browser/rssowl.png +0 -0
  97. images/browser/rssreader.png +0 -0
  98. images/browser/rssxpress.png +0 -0
  99. images/browser/safari.png +0 -0
  100. images/browser/sagem.png +0 -0
  101. images/browser/samsung.png +0 -0
  102. images/browser/sharp.png +0 -0
  103. images/browser/sharpreader.png +0 -0
  104. images/browser/shrook.png +0 -0
  105. images/browser/siemens.png +0 -0
  106. images/browser/sony.png +0 -0
  107. images/browser/staroffice.png +0 -0
  108. images/browser/subversion.png +0 -0
  109. images/browser/teleport.png +0 -0
  110. images/browser/trium.png +0 -0
  111. images/browser/unknown.png +0 -0
  112. images/browser/w3c.png +0 -0
  113. images/browser/webcopier.png +0 -0
  114. images/browser/webreaper.png +0 -0
  115. images/browser/webtv.png +0 -0
  116. images/browser/webzip.png +0 -0
  117. images/browser/winxbox.png +0 -0
  118. images/browser/wizz.png +0 -0
  119. images/forward_params.png +0 -0
  120. images/os/aix.png +0 -0
  121. images/os/amigaos.png +0 -0
  122. images/os/apple.png +0 -0
  123. images/os/atari.png +0 -0
  124. images/os/beos.png +0 -0
  125. images/os/bsd.png +0 -0
  126. images/os/bsdfreebsd.png +0 -0
  127. images/os/bsdi.png +0 -0
  128. images/os/bsdnetbsd.png +0 -0
  129. images/os/bsdopenbsd.png +0 -0
  130. images/os/commodore.png +0 -0
  131. images/os/cpm.png +0 -0
  132. images/os/debian.png +0 -0
  133. images/os/digital.png +0 -0
  134. images/os/dos.png +0 -0
  135. images/os/dreamcast.png +0 -0
  136. images/os/freebsd.png +0 -0
  137. images/os/gnu.png +0 -0
  138. images/os/hpux.png +0 -0
  139. images/os/ibm.png +0 -0
  140. images/os/imode.png +0 -0
  141. images/os/irix.png +0 -0
  142. images/os/java.png +0 -0
  143. images/os/kfreebsd.png +0 -0
  144. images/os/linux.png +0 -0
  145. images/os/linuxcentos.png +0 -0
  146. images/os/linuxdebian.png +0 -0
  147. images/os/linuxfedora.png +0 -0
  148. images/os/linuxgentoo.png +0 -0
  149. images/os/linuxmandr.png +0 -0
  150. images/os/linuxredhat.png +0 -0
  151. images/os/linuxsuse.png +0 -0
  152. images/os/linuxubuntu.png +0 -0
  153. images/os/mac.png +0 -0
  154. images/os/macintosh.png +0 -0
  155. images/os/macosx.png +0 -0
  156. images/os/netbsd.png +0 -0
  157. images/os/netware.png +0 -0
  158. images/os/next.png +0 -0
  159. images/os/openbsd.png +0 -0
  160. images/os/os2.png +0 -0
  161. images/os/osf.png +0 -0
  162. images/os/psp.png +0 -0
  163. images/os/qnx.png +0 -0
  164. images/os/riscos.png +0 -0
  165. images/os/sco.png +0 -0
  166. images/os/sunos.png +0 -0
  167. images/os/symbian.png +0 -0
  168. images/os/unix.png +0 -0
  169. images/os/unknown.png +0 -0
  170. images/os/vms.png +0 -0
  171. images/os/webtv.png +0 -0
  172. images/os/win.png +0 -0
  173. images/os/win16.png +0 -0
  174. images/os/win2000.png +0 -0
  175. images/os/win2003.png +0 -0
  176. images/os/win95.png +0 -0
  177. images/os/win98.png +0 -0
  178. images/os/wince.png +0 -0
  179. images/os/winlong.png +0 -0
  180. images/os/winme.png +0 -0
  181. images/os/winnt.png +0 -0
  182. images/os/winunknown.png +0 -0
  183. images/os/winxbox.png +0 -0
  184. images/os/winxp.png +0 -0
  185. images/pixel_track.png +0 -0
  186. images/pretty-link-add.png +0 -0
  187. images/pretty-link-med.png +0 -0
  188. images/pretty-link-small.png +0 -0
  189. images/url_icon.gif +0 -0
  190. includes/jquery/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  191. includes/jquery/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  192. includes/jquery/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
  193. includes/jquery/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  194. includes/jquery/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  195. includes/jquery/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  196. includes/jquery/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  197. includes/jquery/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  198. includes/jquery/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  199. includes/jquery/css/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
  200. includes/jquery/css/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
  201. includes/jquery/css/ui-lightness/images/ui-icons_ef8c08_256x240.png +0 -0
  202. includes/jquery/css/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
  203. includes/jquery/css/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
  204. includes/jquery/css/ui-lightness/jquery-ui-1.7.1.custom.css +404 -0
  205. includes/jquery/js/jquery-1.3.2.min.js +19 -0
  206. includes/jquery/js/jquery-ui-1.7.1.custom.min.js +273 -0
  207. includes/php/php_browsecap.ini +16810 -0
  208. includes/version-2-ichor/README.txt +8 -0
  209. includes/version-2-ichor/js/README.txt +12 -0
  210. includes/version-2-ichor/js/json/json2.js +461 -0
  211. includes/version-2-ichor/js/swfobject.js +5 -0
  212. includes/version-2-ichor/open-flash-chart.swf +0 -0
  213. pretty-link.php +269 -0
  214. prli-add-link.php +6 -0
  215. prli-clicks.php +218 -0
  216. prli-config.php +13 -0
  217. prli-image-lookups.php +136 -0
  218. prli-links.php +233 -0
  219. prli-options.php +73 -0
  220. readme.txt +99 -0
classes/models/PrliClick.php ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class PrliClick
3
+ {
4
+ function table_name()
5
+ {
6
+ global $wpdb;
7
+ return $wpdb->prefix . 'prli_clicks';
8
+ }
9
+
10
+ function get_ip_exclude_list()
11
+ {
12
+ $exclude_list = get_option('prli_exclude_ips');
13
+ $exclude_list = preg_replace('#[ \t]#','',$exclude_list);
14
+
15
+ if($exclude_list)
16
+ return "'" . implode("','", explode(',',$exclude_list)) . "'";
17
+ else
18
+ return '';
19
+ }
20
+
21
+ function get_exclude_where_clause( $where = '')
22
+ {
23
+ $exclude_list = $this->get_ip_exclude_list();
24
+
25
+ if($where == '')
26
+ $starts_with = '';
27
+ else
28
+ $starts_with = ' AND';
29
+
30
+ if( $exclude_list != '')
31
+ return $starts_with . ' cl.ip NOT IN (' . $exclude_list . ')';
32
+ else
33
+ return '';
34
+ }
35
+
36
+ function prepend_and_or_where( $starts_with = ' WHERE', $where = '' )
37
+ {
38
+ return (( $where == '' )?'':$starts_with . $where);
39
+ }
40
+
41
+ function getOne( $id )
42
+ {
43
+ global $wpdb, $prli_link;
44
+ $click_table = $wpdb->prefix . "prli_clicks";
45
+ $query = 'SELECT cl.*, (SELECT count(*) FROM '. $this->table_name() .' cl2 WHERE cl2.ip = cl.ip) as ip_count, (SELECT count(*) FROM '. $this->table_name() .' cl3 WHERE cl3.vuid = cl.vuid) as vuid_count, li.name as link_name FROM ' . $this->table_name() . ' cl, ' . $prli_link->table_name() . ' li WHERE li.id = cl.link_id AND id=' . $id . $this->prepend_and_or_where(' AND',$this->get_exclude_where_clause());
46
+
47
+ return $wpdb->get_row($query);
48
+ }
49
+
50
+ // SELECT cl.*,li.name as link_name FROM wp_prli_clicks cl, wp_prli_links li WHERE li.id = cl.link_id ORDER BY created_at DESC
51
+ function getAll($where = '', $order = '')
52
+ {
53
+ global $wpdb, $prli_link;
54
+ $click_table = $wpdb->prefix . "prli_clicks";
55
+ $where .= $this->get_exclude_where_clause( $where );
56
+ $where = $this->prepend_and_or_where(' AND', $where);
57
+ $query = 'SELECT cl.*, (SELECT count(*) FROM '. $this->table_name() .' cl2 WHERE cl2.ip = cl.ip) as ip_count, (SELECT count(*) FROM '. $this->table_name() .' cl3 WHERE cl3.vuid = cl.vuid) as vuid_count, li.name as link_name FROM ' . $this->table_name() . ' cl, ' . $prli_link->table_name() . ' li WHERE li.id = cl.link_id' . $where . $order;
58
+ return $wpdb->get_results($query);
59
+ }
60
+
61
+ // Pagination Methods
62
+ function getRecordCount($where='')
63
+ {
64
+ global $wpdb, $prli_link;
65
+ $where .= $this->get_exclude_where_clause( $where );
66
+ $where = $this->prepend_and_or_where(' WHERE', $where);
67
+ $query = 'SELECT COUNT(*) FROM ' . $this->table_name() . ' cl'. $where;
68
+ return $wpdb->get_var($query);
69
+ }
70
+
71
+ function getPageCount($p_size, $where='')
72
+ {
73
+ return ceil((int)$this->getRecordCount($where) / (int)$p_size);
74
+ }
75
+
76
+ function getPage($current_p,$p_size, $where = '', $order = '')
77
+ {
78
+ global $wpdb, $prli_link;
79
+ $click_table = $wpdb->prefix . "prli_clicks";
80
+ $end_index = $current_p * $p_size;
81
+ $start_index = $end_index - $p_size;
82
+ $where .= $this->get_exclude_where_clause( $where );
83
+ $where = $this->prepend_and_or_where(' AND', $where);
84
+ $query = 'SELECT cl.*, (SELECT count(*) FROM '. $this->table_name() .' cl2 WHERE cl2.ip = cl.ip) as ip_count, (SELECT count(*) FROM '. $this->table_name() .' cl3 WHERE cl3.vuid = cl.vuid) as vuid_count, li.name as link_name FROM ' . $this->table_name() . ' cl, ' . $prli_link->table_name() . ' li WHERE li.id = cl.link_id' . $where . $order . ' LIMIT ' . $start_index . ',' . $p_size . ';';
85
+ $results = $wpdb->get_results($query);
86
+ return $results;
87
+ }
88
+
89
+ function generateUniqueVisitorId($num_chars = 6)
90
+ {
91
+ global $wpdb, $prli_utils;
92
+
93
+ // We're doing a base 36 hash which is why we're always doing everything by 36
94
+ $max_vuid_value = pow(36,$num_chars);
95
+ $min_vuid_value = 37;
96
+ $vuid = base_convert( mt_rand($min_vuid_value,$max_vuid_value), 10, 36 );
97
+
98
+ $query = "SELECT DISTINCT vuid FROM ".$this->table_name();
99
+ $vuids = $wpdb->get_col($query,0);
100
+
101
+ // It is highly unlikely that we'll ever see 2 identical random vuids
102
+ // but just in case, here's some code to prevent collisions
103
+ while( in_array($vuid,$vuids) )
104
+ $vuid = base_convert( mt_rand($min_vuid_value,$max_vuid_value), 10, 36 );
105
+
106
+ return $vuid;
107
+ }
108
+
109
+ function get_counts_by_days($start_timestamp, $end_timestamp, $link_id = "all", $type = "all")
110
+ {
111
+ global $wpdb;
112
+
113
+ $query = "SELECT DATE(cl.created_at) as cldate,COUNT(*) as clcount FROM ".$this->table_name()." cl WHERE DATE(cl.created_at) BETWEEN '".date("Y-n-j",$start_timestamp)."' AND '".date("Y-n-j",$end_timestamp)."'".$search_where.$this->get_exclude_where_clause( ' AND' );
114
+
115
+ if($link_id != "all")
116
+ $query .= " AND link_id=$link_id";
117
+
118
+ if($type == "unique")
119
+ $query .= " AND first_click=1";
120
+
121
+ $query .= ' GROUP BY DATE(cl.created_at)';
122
+
123
+ $clicks_array = $wpdb->get_results($query);
124
+
125
+ $temp_array = array();
126
+ $counts_array = array();
127
+ $dates_array = array();
128
+
129
+ // Refactor Array for use later on
130
+ foreach($clicks_array as $c)
131
+ $temp_array[$c->cldate] = $c->clcount;
132
+
133
+ // Get the dates array
134
+ for($c = $start_timestamp; $c <= $end_timestamp; $c += 60*60*24)
135
+ $dates_array[] = date("Y-m-d",$c);
136
+
137
+ // Make sure counts array is in order and includes zero click days
138
+ foreach($dates_array as $date_str)
139
+ {
140
+ if(isset($temp_array[$date_str]))
141
+ $counts_array[$date_str] = $temp_array[$date_str];
142
+ else
143
+ $counts_array[$date_str] = 0;
144
+ }
145
+
146
+ return $counts_array;
147
+ }
148
+
149
+
150
+ function setupClickLineGraph($start_timestamp,$end_timestamp, $link_id = "all", $type = "all")
151
+ {
152
+ global $wpdb, $prli_utils, $prli_link;
153
+
154
+ $dates_array = $this->get_counts_by_days($start_timestamp,$end_timestamp,$link_id,$type);
155
+
156
+ $top_click_count = $prli_utils->getTopValue(array_values($dates_array));
157
+
158
+ if($link_id == "all")
159
+ $link_slug = "all links";
160
+ else
161
+ $link_slug = "'/".$wpdb->get_var("SELECT slug FROM ".$prli_link->table_name()." WHERE id=$link_id") . "'";
162
+
163
+ if($type == "all")
164
+ $type_string = "All hits";
165
+ else
166
+ $type_string = "Unique hits";
167
+
168
+ $json_array = array(
169
+ "elements" => array( array(
170
+ "type" => "line",
171
+ "values" => array_values($dates_array),
172
+ "dot-style" => array(
173
+ "type" => "dot",
174
+ "dot-size" => 4,
175
+ "colour" => "#ffc94e",
176
+ "halo-size" => 1,
177
+ "tip" => "#val# hits"
178
+ ),
179
+ "width" => 2
180
+ ) ),
181
+ "title" => array(
182
+ "text" => 'Pretty Link: '.$type_string.' on '.$link_slug. ' between ' . date("Y-n-j",$start_timestamp) . ' and ' . date("Y-n-j",$end_timestamp),
183
+ "style" => "font-size: 16px; font-weight: bold; color: #3030d0; text-align: center; padding-bottom: 5px;"
184
+ ),
185
+ "bg_colour" => "-1",
186
+ "y_axis" => array(
187
+ "min" => 0,
188
+ "max" => $top_click_count,
189
+ "steps" => (int)(($top_click_count>=10)?$top_click_count/10:1),
190
+ "colour" => "#A2ACBA"
191
+ ),
192
+ "x_axis" => array(
193
+ "colour" => "#A2ACBA",
194
+ "grid-colour" => "#ffefa7",
195
+ "offset" => false,
196
+ "steps" => 4,
197
+ "labels" => array(
198
+ "steps" => 2,
199
+ "rotate" => 45,
200
+ "colour" => "#000000",
201
+ "labels" => array_keys($dates_array)
202
+ )
203
+ )
204
+ );
205
+
206
+ return $prli_utils->prli_json_encode($json_array);
207
+ }
208
+
209
+
210
+ // Set defaults and grab get or post of each possible param
211
+ function get_params_array()
212
+ {
213
+ $values = array(
214
+ 'paged' => (isset($_GET['paged'])?$_GET['paged']:(isset($_POST['paged'])?$_POST['paged']:1)),
215
+ 'l' => (isset($_GET['l'])?$_GET['l']:(isset($_POST['l'])?$_POST['l']:'all')),
216
+ 'ip' => (isset($_GET['ip'])?$_GET['ip']:(isset($_POST['ip'])?$_POST['ip']:'')),
217
+ 'vuid' => (isset($_GET['vuid'])?$_GET['vuid']:(isset($_POST['vuid'])?$_POST['vuid']:'')),
218
+ 'sdate' => (isset($_GET['sdate'])?$_GET['sdate']:(isset($_POST['sdate'])?$_POST['sdate']:'')),
219
+ 'edate' => (isset($_GET['edate'])?$_GET['edate']:(isset($_POST['edate'])?$_POST['edate']:'')),
220
+ 'type' => (isset($_GET['type'])?$_GET['type']:(isset($_POST['type'])?$_POST['type']:'all')),
221
+ 'search' => (isset($_GET['search'])?$_GET['search']:(isset($_POST['search'])?$_POST['search']:'')),
222
+ 'sort' => (isset($_GET['sort'])?$_GET['sort']:(isset($_POST['sort'])?$_POST['sort']:'')),
223
+ 'sdir' => (isset($_GET['sdir'])?$_GET['sdir']:(isset($_POST['sdir'])?$_POST['sdir']:''))
224
+ );
225
+
226
+ return $values;
227
+ }
228
+
229
+ }
230
+ ?>
classes/models/PrliLink.php ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class PrliLink
3
+ {
4
+ function table_name()
5
+ {
6
+ global $wpdb;
7
+ return $wpdb->prefix . 'prli_links';
8
+ }
9
+
10
+ function create( $values )
11
+ {
12
+ global $wpdb, $wp_rewrite;
13
+
14
+ $values['name'] = (!empty($values['name'])?$values['name']:$values['slug']);
15
+ $query = 'INSERT INTO ' . $this->table_name() .
16
+ ' (url,slug,name,param_forwarding,param_struct,redirect_type,description,track_as_img,created_at) VALUES (\'' .
17
+ $values['url'] . '\',\'' .
18
+ $values['slug'] . '\',\'' .
19
+ $values['name'] . '\',\'' .
20
+ $values['param_forwarding'] . '\',\'' .
21
+ $values['param_struct'] . '\',\'' .
22
+ $values['redirect_type'] . '\',\'' .
23
+ $values['description'] . '\',' .
24
+ (int)isset($values['track_as_img']) . ',' .
25
+ 'NOW())';
26
+ $query_results = $wpdb->query($query);
27
+ $wp_rewrite->flush_rules();
28
+ return $query_results;
29
+ }
30
+
31
+ function update( $id, $values )
32
+ {
33
+ global $wpdb, $wp_rewrite;
34
+
35
+ $values['name'] = (!empty($values['name'])?$values['name']:$values['slug']);
36
+ $query = 'UPDATE ' . $this->table_name() .
37
+ ' SET url=\'' . $values['url'] . '\', ' .
38
+ ' slug=\'' . $values['slug'] . '\', ' .
39
+ ' name=\'' . $values['name'] . '\', ' .
40
+ ' param_forwarding=\'' . $values['param_forwarding'] . '\', ' .
41
+ ' param_struct=\'' . $values['param_struct'] . '\', ' .
42
+ ' redirect_type=\'' . $values['redirect_type'] . '\', ' .
43
+ ' description=\'' . $values['description'] . '\', ' .
44
+ ' track_as_img=' . (int)isset($values['track_as_img']) .
45
+ ' WHERE id='.$id;
46
+ $query_results = $wpdb->query($query);
47
+ $wp_rewrite->flush_rules();
48
+ return $query_results;
49
+ }
50
+
51
+ function destroy( $id )
52
+ {
53
+ require_once(PRLI_MODELS_PATH.'/models.inc.php');
54
+ global $wpdb, $prli_click, $wp_rewrite;
55
+
56
+ $reset = 'DELETE FROM ' . $prli_click->table_name() . ' WHERE link_id=' . $id;
57
+ $destroy = 'DELETE FROM ' . $this->table_name() . ' WHERE id=' . $id;
58
+
59
+ $wp_rewrite->flush_rules();
60
+
61
+ $wpdb->query($reset);
62
+ return $wpdb->query($destroy);
63
+ }
64
+
65
+ function reset( $id )
66
+ {
67
+ require_once(PRLI_MODELS_PATH.'/models.inc.php');
68
+ global $wpdb, $wp_rewrite, $prli_click;
69
+
70
+ $reset = 'DELETE FROM ' . $prli_click->table_name() . ' WHERE link_id=' . $id;
71
+ return $wpdb->query($reset);
72
+ }
73
+
74
+ function getOneFromSlug( $slug )
75
+ {
76
+ global $wpdb;
77
+ $click_table = $wpdb->prefix . "prli_clicks";
78
+ $query = 'SELECT * FROM ' . $this->table_name() . ' WHERE slug=\'' . $slug . '\'';
79
+ return $wpdb->get_row($query);
80
+ }
81
+
82
+ function getOne( $id )
83
+ {
84
+ global $wpdb, $prli_click;
85
+ $click_table = $wpdb->prefix . "prli_clicks";
86
+ $query = 'SELECT li.*, (SELECT COUNT(*) FROM ' . $click_table . ' cl WHERE cl.link_id = li.id' . $prli_click->get_exclude_where_clause( ' AND' ) . ') as clicks FROM ' . $this->table_name() . ' li WHERE id=' . $id . ';';
87
+ return $wpdb->get_row($query);
88
+ }
89
+
90
+ function getAll()
91
+ {
92
+ global $wpdb, $prli_click;
93
+ $click_table = $wpdb->prefix . "prli_clicks";
94
+ $query = 'SELECT li.*, (SELECT COUNT(*) FROM ' . $click_table . ' cl WHERE cl.link_id = li.id' . $prli_click->get_exclude_where_clause( ' AND' ) . ') as clicks FROM ' . $this->table_name() . ' li;';
95
+ return $wpdb->get_results($query);
96
+ }
97
+
98
+ // Pagination Methods
99
+ function getRecordCount($where="")
100
+ {
101
+ global $wpdb;
102
+ $query = 'SELECT COUNT(*) FROM ' . $this->table_name() . $where;
103
+ return $wpdb->get_var($query);
104
+ }
105
+
106
+ function getPageCount($p_size, $where="")
107
+ {
108
+ return ceil((int)$this->getRecordCount($where) / (int)$p_size);
109
+ }
110
+
111
+ function getPage($current_p,$p_size, $where = "")
112
+ {
113
+ global $wpdb, $prli_click;
114
+ $click_table = $wpdb->prefix . "prli_clicks";
115
+ $end_index = $current_p * $p_size;
116
+ $start_index = $end_index - $p_size;
117
+ $query = 'SELECT li.*, (SELECT COUNT(*) FROM ' . $click_table . ' cl WHERE cl.link_id = li.id' . $prli_click->get_exclude_where_clause( ' AND' ) . ') as clicks FROM ' . $this->table_name() . ' li' . $where . ' LIMIT ' . $start_index . ',' . $p_size . ';';
118
+ $results = $wpdb->get_results($query);
119
+ return $results;
120
+ }
121
+
122
+ /** I'm generating a slug that is by default 2-3 characters long.
123
+ * This gives us a possibility of 36^3 - 37 = 46,619 possible
124
+ * random slugs. That should be *more* than enough slugs for
125
+ * any website -- if I get any feedback that we need more then
126
+ * I can always make a config option to raise the # of chars.
127
+ */
128
+ function generateValidSlug($num_chars = 3)
129
+ {
130
+ global $wpdb, $prli_utils;
131
+
132
+ // We're doing a base 36 hash which is why we're always doing everything by 36
133
+ $max_slug_value = pow(36,$num_chars);
134
+ $min_slug_value = 37; // we want to have at least 2 characters in the slug
135
+ $slug = base_convert( rand($min_slug_value,$max_slug_value), 10, 36 );
136
+
137
+ $query = "SELECT slug FROM " . $this->table_name(); // . " WHERE slug='" . $slug . "'";
138
+ $slugs = $wpdb->get_col($query,0);
139
+
140
+ // It is highly unlikely that we'll ever see 2 identical random slugs
141
+ // but just in case, here's some code to prevent collisions
142
+ while( in_array($slug,$slugs) or !$prli_utils->slugIsAvailable($slug) )
143
+ $slug = base_convert( rand($min_slug_value,$max_slug_value), 10, 36 );
144
+
145
+ return $slug;
146
+ }
147
+
148
+ function get_pretty_link_url($slug)
149
+ {
150
+ global $prli_blogurl;
151
+
152
+ $link = $this->getOneFromSlug($slug);
153
+
154
+ if((isset($link->param_forwarding) and $link->param_forwarding == 'custom') and
155
+ (isset($link->track_as_img) and $link->track_as_img == 1))
156
+ return "&lt;img src=\"".$prli_blogurl . '/' . $link->slug . $link->param_struct . "\" width=\"1\" height=\"1\" style=\"display: none\" /&gt;";
157
+ else if((!isset($link->param_forwarding) or $link->param_forwarding != 'custom') and
158
+ (isset($link->track_as_img) and $link->track_as_img == 1))
159
+ return "&lt;img src=\"".$prli_blogurl . '/' . $link->slug . "\" width=\"1\" height=\"1\" style=\"display: none\" /&gt;";
160
+ else if((isset($link->param_forwarding) and $link->param_forwarding == 'custom') and
161
+ (!isset($link->track_as_img) or $link->track_as_img == 0))
162
+ return $prli_blogurl . '/' . $link->slug . $link->param_struct;
163
+ else
164
+ return $prli_blogurl . '/' . $link->slug;
165
+ }
166
+
167
+ function validate( $values )
168
+ {
169
+ global $wpdb, $prli_utils;
170
+
171
+ $errors = array();
172
+ if( ( $values['url'] == null or $values['url'] == '') and $values['track_as_img'] != 'on' )
173
+ $errors[] = "Target URL can't be blank -- unless this Pretty Link is being used as a tracking pixel (see Advanced Options on this page)";
174
+
175
+ if( $values['slug'] == null or $values['slug'] == '' )
176
+ $errors[] = "Pretty Link can't be blank";
177
+
178
+ if( !empty($values['url']) and !preg_match('/^http.?:\/\/.*\..*$/', $values['url'] ) )
179
+ $errors[] = "Link URL must be a correctly formatted url";
180
+
181
+ if( !preg_match('/^[a-zA-Z0-9\.\-_]+$/', $values['slug'] ) )
182
+ $errors[] = "Pretty Link must not contain spaces or special characters";
183
+
184
+ if($values['id'] != null and $values['id'] != '')
185
+ $query = "SELECT slug FROM " . $this->table_name() . " WHERE slug='" . $values['slug'] . "' AND id <> " . $values['id'];
186
+ else
187
+ $query = "SELECT slug FROM " . $this->table_name() . " WHERE slug='" . $values['slug'] . "'";
188
+
189
+ $slug_already_exists = $wpdb->get_var($query);
190
+
191
+ if( $slug_already_exists or !$prli_utils->slugIsAvailable($values['slug']) )
192
+ $errors[] = "This pretty link slug is already taken, please choose a different one";
193
+
194
+ if( isset($values['param_forwarding']) and $values['param_forwarding'] == 'custom' and empty($values['param_struct']) )
195
+ $errors[] = "If Custom Parameter Forwarding has been selected then you must specify a forwarding format.";
196
+
197
+ if( isset($values['param_forwarding']) and $values['param_forwarding'] == 'custom' and !preg_match('#%.*?%#', $values['param_struct']) )
198
+ $errors[] = "Your parameter forwarding must have at least one parameter specified in the format ex: <code>/%var1%/%var_two%/%varname3% ...</code>";
199
+
200
+ /*
201
+ if(isset($values['track_as_img']) and $values['track_as_img'] == 'on' and $values['url'] != null and $values['url'] != '')
202
+ {
203
+ $size = getimagesize($values['url']);
204
+ if(!preg_match('#image#',$size['mime']))
205
+ {
206
+ $errors[] = "If you want to track this pretty link as an image then your target url must be an image (png, jpeg, gif, etc.)";
207
+ }
208
+ }
209
+ */
210
+
211
+ return $errors;
212
+ }
213
+ }
214
+ ?>
classes/models/PrliUtils.php ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once 'models.inc.php';
3
+
4
+ class PrliUtils
5
+ {
6
+
7
+ /** Okay I realize that Percentagize isn't really a word but
8
+ * this is so that the values we have will work with google
9
+ * charts.
10
+ */
11
+ function percentagizeArray($data,$max_value)
12
+ {
13
+ $new_data = array();
14
+ foreach($data as $point)
15
+ {
16
+ if( $max_value > 0 )
17
+ {
18
+ $new_data[] = $point / $max_value * 100;
19
+ }
20
+ else
21
+ {
22
+ $new_data[] = 0;
23
+ }
24
+ }
25
+ return $new_data;
26
+ }
27
+
28
+ function getTopValue($values_array)
29
+ {
30
+ rsort($values_array);
31
+ return $values_array[0];
32
+ }
33
+
34
+ function getFirstClickDate()
35
+ {
36
+ global $wpdb;
37
+
38
+ $clicks_table = $wpdb->prefix . "prli_clicks";
39
+ $query = "SELECT created_at FROM $clicks_table ORDER BY created_at LIMIT 1";
40
+ $first_click = $wpdb->get_var($query);
41
+
42
+ if(isset($first_click))
43
+ {
44
+ return strtotime($first_click);
45
+ }
46
+ else
47
+ return null;
48
+ }
49
+
50
+ function getMonthsArray()
51
+ {
52
+ global $wpdb;
53
+ global $prli_click;
54
+
55
+ $months = array();
56
+ $year = date("Y");
57
+ $month = date("m");
58
+ $current_timestamp = time();
59
+ $current_month_timestamp = mktime(0, 0, 0, date("m", $current_timestamp), 1, date("Y", $current_timestamp));
60
+
61
+ $clicks_table = $prli_click->tableName();
62
+ $first_click = $wpdb->get_var("SELECT created_at FROM $clicks_table ORDER BY created_at LIMIT 1;");
63
+ $first_timestamp = ((empty($first_click))?$current_timestamp:strtotime($first_click));
64
+ $first_date = mktime(0, 0, 0, date("m", $first_timestamp), 1, date("Y", $first_timestamp));
65
+
66
+ while($current_month_timestamp >= $first_date)
67
+ {
68
+ $months[] = $current_month_timestamp;
69
+ if(date("m") == 1)
70
+ {
71
+ $current_month_timestamp = mktime(0, 0, 0, 12, 1, date("Y", $current_month_timestamp)-1);
72
+ }
73
+ else
74
+ {
75
+ $current_month_timestamp = mktime(0, 0, 0, date("m", $current_month_timestamp)-1, 1, date("Y", $current_month_timestamp));
76
+ }
77
+ }
78
+ return $months;
79
+ }
80
+
81
+ // For Pagination
82
+ function getLastRecordNum($r_count,$current_p,$p_size)
83
+ {
84
+ return (($r_count < ($current_p * $p_size))?$r_count:($current_p * $p_size));
85
+ }
86
+
87
+ // For Pagination
88
+ function getFirstRecordNum($r_count,$current_p,$p_size)
89
+ {
90
+ if($current_p == 1)
91
+ {
92
+ return 1;
93
+ }
94
+ else
95
+ {
96
+ return ($this->getLastRecordNum($r_count,($current_p - 1),$p_size) + 1);
97
+ }
98
+ }
99
+
100
+ function slugIsAvailable($slug)
101
+ {
102
+ global $wpdb;
103
+
104
+ $posts_table = $wpdb->prefix . "posts";
105
+ $terms_table = $wpdb->prefix . "terms";
106
+
107
+ $post_slug = $wpdb->get_var("SELECT post_name FROM $posts_table WHERE post_name='$slug'");
108
+ $term_slug = $wpdb->get_col("SELECT slug FROM $terms_table WHERE slug='$slug'");
109
+
110
+ return ( $post_slug != $slug and $term_slug != $slug );
111
+ }
112
+
113
+ /* Needed because we don't know if the target uesr will have a browsercap file installed
114
+ on their server ... particularly in a shared hosting environment this is difficult
115
+ */
116
+ function php_get_browser($agent = NULL)
117
+ {
118
+ $agent=$agent?$agent:$_SERVER['HTTP_USER_AGENT'];
119
+ $yu=array();
120
+ $q_s=array("#\.#","#\*#","#\?#");
121
+ $q_r=array("\.",".*",".?");
122
+ $brows=parse_ini_file(PRLI_PATH."/includes/php/php_browsecap.ini",true);
123
+ foreach($brows as $k=>$t)
124
+ {
125
+ if(fnmatch($k,$agent))
126
+ {
127
+ $yu['browser_name_pattern']=$k;
128
+ $pat=preg_replace($q_s,$q_r,$k);
129
+ $yu['browser_name_regex']=strtolower("^$pat$");
130
+ foreach($brows as $g=>$r)
131
+ {
132
+ if($t['Parent']==$g)
133
+ {
134
+ foreach($brows as $a=>$b)
135
+ {
136
+ if($r['Parent']==$a)
137
+ {
138
+ $yu=array_merge($yu,$b,$r,$t);
139
+ foreach($yu as $d=>$z)
140
+ {
141
+ $l=strtolower($d);
142
+ $hu[$l]=$z;
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ break;
150
+ }
151
+ }
152
+
153
+ return $hu;
154
+ }
155
+
156
+ // This is where the magic happens!
157
+ function track_link($slug,$values)
158
+ {
159
+ global $wpdb, $prli_click, $prli_link;
160
+
161
+ $query = "SELECT * FROM ".$prli_link->table_name()." WHERE slug='$slug' LIMIT 1";
162
+ $pretty_link = $wpdb->get_row($query);
163
+
164
+ $first_click = false;
165
+
166
+ $click_ip = $_SERVER['REMOTE_ADDR'];
167
+ $click_referer = $_SERVER['HTTP_REFERER'];
168
+ $click_host = gethostbyaddr($click_ip);
169
+
170
+ $click_uri = $_SERVER['REQUEST_URI'];
171
+ $click_user_agent = $_SERVER['HTTP_USER_AGENT'];
172
+ $click_browser = $this->php_get_browser();
173
+
174
+ //Set Cookie if it doesn't exist
175
+ $cookie_name = 'prli_click_' . $pretty_link->id;
176
+ //Used for unique click tracking
177
+ $cookie_expire_time = time()+60*60*24*30; // Expire in 30 days
178
+
179
+ $visitor_cookie = 'prli_visitor';
180
+ //Used for visitor activity
181
+ $visitor_cookie_expire_time = time()+60*60*24*365; // Expire in 1 year
182
+
183
+
184
+ if($_COOKIE[$cookie_name] == null)
185
+ {
186
+ setcookie($cookie_name,$slug,$cookie_expire_time);
187
+ $first_click = true;
188
+ }
189
+
190
+ // Retrieve / Generate visitor id
191
+ if($_COOKIE[$visitor_cookie] == null)
192
+ {
193
+ $visitor_uid = $prli_click->generateUniqueVisitorId();
194
+ setcookie($visitor_cookie,$visitor_uid,$visitor_cookie_expire_time);
195
+ }
196
+ else
197
+ $visitor_uid = $_COOKIE[$visitor_cookie];
198
+
199
+ //Record Click in DB
200
+ $insert = "INSERT INTO ".$prli_click->table_name()." (link_id,vuid,ip,browser,btype,bversion,os,referer,uri,host,first_click,created_at) VALUES ($pretty_link->id,'$visitor_uid','$click_ip','$click_user_agent','".$click_browser['browser']."','".$click_browser['version']."','".$click_browser['platform']."','$click_referer','$click_uri','$click_host','$first_click',NOW())";
201
+
202
+ $results = $wpdb->query( $insert );
203
+
204
+ // Reformat Parameters
205
+ $param_string = '';
206
+
207
+ if(isset($pretty_link->param_forwarding) and $pretty_link->param_forwarding and isset($values) and count($values) > 1)
208
+ {
209
+ $first_param = true;
210
+ foreach($values as $key => $value)
211
+ {
212
+ // Ignore the 'sprli' parameter
213
+ if($key != 'sprli')
214
+ {
215
+ if($first_param)
216
+ {
217
+ $param_string = (preg_match("#\?#", $pretty_link->url)?"&":"?");
218
+ $first_param = false;
219
+ }
220
+ else
221
+ $param_string .= "&";
222
+
223
+ $param_string .= "$key=$value";
224
+ }
225
+ }
226
+ }
227
+
228
+ //Redirect to Product URL
229
+ if(!isset($pretty_link->track_as_img) or $pretty_link->track_as_img == 0)
230
+ {
231
+ wp_redirect($pretty_link->url.$param_string, (int)$pretty_link->redirect_type);
232
+ }
233
+ }
234
+
235
+ function get_custom_forwarding_rule($param_struct)
236
+ {
237
+ $param_struct = preg_replace('#%.*?%#','(.*?)',$param_struct);
238
+ return preg_replace('#\(\.\*\?\)$#','(.*)',$param_struct); // replace the last one with a greedy operator
239
+ }
240
+
241
+ function get_custom_forwarding_params($param_struct, $start_index = 1)
242
+ {
243
+ preg_match_all('#%(.*?)%#', $param_struct, $matches);
244
+
245
+ $param_string = '';
246
+ $match_index = $start_index;
247
+ for($i = 0; $i < count($matches[1]); $i++)
248
+ {
249
+ if($i == 0 and $start_index == 1)
250
+ $param_string .= "?";
251
+ else
252
+ $param_string .= "&";
253
+
254
+ $param_string .= $matches[1][$i] . "=$$match_index";
255
+ $match_index++;
256
+ }
257
+
258
+ return $param_string;
259
+ }
260
+
261
+ function decode_custom_param_str($param_struct, $uri_string)
262
+ {
263
+ // Get the structure matches (param names)
264
+ preg_match_all('#%(.*?)%#', $param_struct, $struct_matches);
265
+
266
+ // Get the uri matches (param values)
267
+ $match_str = '#'.$this->get_custom_forwarding_rule($param_struct).'#';
268
+ preg_match($match_str, $uri_string, $uri_matches);
269
+
270
+ $param_array = array();
271
+ for($i = 0; $i < count($struct_matches[1]); $i++)
272
+ $param_array[$struct_matches[1][$i]] = $uri_matches[$i+1];
273
+
274
+ return $param_array;
275
+ }
276
+
277
+ // Detects whether an array is a true numerical array or an
278
+ // associative array (or hash).
279
+ function prli_array_type($item)
280
+ {
281
+ $array_type = 'unknown';
282
+
283
+ if(is_array($item))
284
+ {
285
+ $array_type = 'array';
286
+
287
+ foreach($item as $key => $value)
288
+ {
289
+ if(!is_numeric($key))
290
+ {
291
+ $array_type = 'hash';
292
+ break;
293
+ }
294
+ }
295
+ }
296
+
297
+ return $array_type;
298
+ }
299
+
300
+ // This eliminates the need to use php's built in json_encoder
301
+ // which only works with PHP 5.2 and above.
302
+ function prli_json_encode($json_array)
303
+ {
304
+ $json_str = '';
305
+
306
+ if(is_array($json_array))
307
+ {
308
+ if($this->prli_array_type($json_array) == 'array')
309
+ {
310
+ $first = true;
311
+ $json_str .= "[";
312
+ foreach($json_array as $item)
313
+ {
314
+ if(!$first)
315
+ $json_str .= ",";
316
+
317
+ if(is_numeric($item))
318
+ $json_str .= (($item < 0)?"\"$item\"":$item);
319
+ else if(is_array($item))
320
+ $json_str .= $this->prli_json_encode($item);
321
+ else if(is_string($item))
322
+ $json_str .= '"'.$item.'"';
323
+ else if(is_bool($item))
324
+ $json_str .= (($item)?"true":"false");
325
+
326
+ $first = false;
327
+ }
328
+ $json_str .= "]";
329
+ }
330
+ else if($this->prli_array_type($json_array) == 'hash')
331
+ {
332
+ $first = true;
333
+ $json_str .= "{";
334
+ foreach($json_array as $key => $item)
335
+ {
336
+ if(!$first)
337
+ $json_str .= ",";
338
+
339
+ $json_str .= "\"$key\":";
340
+
341
+ if(is_numeric($item))
342
+ $json_str .= (($item < 0)?"\"$item\"":$item);
343
+ else if(is_array($item))
344
+ $json_str .= $this->prli_json_encode($item);
345
+ else if(is_string($item))
346
+ $json_str .= "\"$item\"";
347
+ else if(is_bool($item))
348
+ $json_str .= (($item)?"true":"false");
349
+
350
+ $first = false;
351
+ }
352
+ $json_str .= "}";
353
+ }
354
+ }
355
+
356
+ return $json_str;
357
+ }
358
+
359
+ // Get the timestamp of the start date
360
+ function get_start_date($values,$min_date = '')
361
+ {
362
+ // set default to 30 days ago
363
+ if(empty($min_date))
364
+ $min_date = 30;
365
+
366
+ if(!empty($values['sdate']))
367
+ {
368
+ $sdate = explode("-",$values['sdate']);
369
+ $start_timestamp = mktime(0,0,0,$sdate[1],$sdate[2],$sdate[0]);
370
+ }
371
+ else
372
+ $start_timestamp = time()-60*60*24*(int)$min_date;
373
+
374
+ return $start_timestamp;
375
+ }
376
+
377
+ // Get the timestamp of the end date
378
+ function get_end_date($values)
379
+ {
380
+ if(!empty($values['edate']))
381
+ {
382
+ $edate = explode("-",$values['edate']);
383
+ $end_timestamp = mktime(0,0,0,$edate[1],$edate[2],$edate[0]);
384
+ }
385
+ else
386
+ $end_timestamp = time();
387
+
388
+ return $end_timestamp;
389
+ }
390
+
391
+ }
392
+ ?>
classes/models/models.inc.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(PRLI_MODELS_PATH.'/PrliLink.php');
3
+ require_once(PRLI_MODELS_PATH.'/PrliClick.php');
4
+ require_once(PRLI_MODELS_PATH.'/PrliUtils.php');
5
+
6
+ $prli_link = new PrliLink();
7
+ $prli_click = new PrliClick();
8
+ $prli_utils = new PrliUtils();
9
+ ?>
classes/views/prli-clicks/csv.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once('prli-config.php');
3
+
4
+ if(is_user_logged_in() and $current_user->user_level >= 8)
5
+ {
6
+ $filename = date("ymdHis",time()) . '_' . $link_name . '_pretty_link_clicks.csv';
7
+ header("Content-Type: text/x-csv");
8
+ header("Content-Disposition: attachment; filename=\"$filename\"");
9
+ header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
10
+ header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
11
+ header("Cache-Control: no-cache, must-revalidate");
12
+ header("Pragma: no-cache");
13
+
14
+ echo '"Browser","Browser Version","Platform","IP","Visitor ID","Timestamp","Host","URI","Referrer","Link"' . "\n";
15
+ foreach($clicks as $click)
16
+ {
17
+ $link = $prli_link->getOne($click->link_id);
18
+
19
+ echo "\"$click->btype\",\"$click->bversion\",\"$click->os\",\"$click->ip\",\"$click->vuid\",\"$click->created_at\",\"$click->host\",\"$click->uri\",\"$click->referer\",\"" . ((empty($link->name))?$link->slug:$link->name) . "\"\n";
20
+ }
21
+ }
22
+ else
23
+ header("Location: " . $prli_blogurl);
24
+ ?>
classes/views/prli-clicks/head.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- JQuery UI Includes -->
2
+ <link type="text/css" href="<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/includes/jquery/css/ui-lightness/jquery-ui-1.7.1.custom.css" rel="stylesheet" />
3
+ <script type="text/javascript" src="<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/includes/jquery/js/jquery-1.3.2.min.js"></script>
4
+ <script type="text/javascript" src="<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/includes/jquery/js/jquery-ui-1.7.1.custom.min.js"></script>
5
+
6
+ <script type="text/javascript">
7
+ $(document).ready(function(){
8
+ $("#sdate").datepicker({ dateFormat: 'yy-mm-dd', defaultDate: -30, minDate: -<?php echo $min_date; ?>, maxDate: 0 });
9
+ $("#edate").datepicker({ dateFormat: 'yy-mm-dd', minDate: -<?php echo $min_date; ?>, maxDate: 0 });
10
+ });
11
+ </script>
12
+
13
+ <script type="text/javascript">
14
+ $(document).ready(function(){
15
+ $(".filter_pane").hide();
16
+ $(".filter_toggle").click( function () {
17
+ $(".filter_pane").slideToggle("slow");
18
+ });
19
+ });
20
+ </script>
21
+
22
+ <style type="text/css">
23
+ .filter_toggle {
24
+ line-height: 34px;
25
+ font-size: 14px;
26
+ font-weight: bold;
27
+ padding-bottom: 10px;
28
+ }
29
+
30
+ .filter_pane {
31
+ background-color: white;
32
+ border: 2px solid #777777;
33
+ height: 275px;
34
+ width: 600px;
35
+ padding-left: 20px;
36
+ padding-top: 10px;
37
+ }
38
+
39
+ </style>
40
+
41
+ <!-- Open Flash Chart Includes -->
42
+ <script type="text/javascript" src="<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/includes/version-2-ichor/js/json/json2.js"></script>
43
+ <script type="text/javascript" src="<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/includes/version-2-ichor/js/swfobject.js"></script>
44
+ <script type="text/javascript">
45
+ swfobject.embedSWF("<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/includes/version-2-ichor/open-flash-chart.swf", "my_chart", "100%", "250", "9.0.0");
46
+ </script>
47
+
48
+ <script type="text/javascript">
49
+
50
+ function ofc_ready()
51
+ {
52
+ //alert('ofc_ready');
53
+ }
54
+
55
+ function open_flash_chart_data()
56
+ {
57
+ //alert( 'reading data' );
58
+ return JSON.stringify(data);
59
+ }
60
+
61
+ function findSWF(movieName) {
62
+ if (navigator.appName.indexOf("Microsoft")!= -1) {
63
+ return window[movieName];
64
+ } else {
65
+ return document[movieName];
66
+ }
67
+ }
68
+
69
+ OFC = {};
70
+
71
+ OFC.jquery = {
72
+ name: "jQuery",
73
+ version: function(src) { return $('#'+ src)[0].get_version() },
74
+ rasterize: function (src, dst) { $('#'+ dst).replaceWith(OFC.jquery.image(src)) },
75
+ image: function(src) { return "<img src='data:image/png;base64," + $('#'+src)[0].get_img_binary() + "' />"},
76
+ popup: function(src) {
77
+ var img_win = window.open('', 'Charts: Export as Image')
78
+ with(img_win.document) {
79
+ write('<html><head><title>Charts: Export as Image<\/title><\/head><body>' + OFC.jquery.image(src) + '<div>Right-Click on the above Image to Save<\/div><\/body><\/html>') }
80
+ // stop the 'loading...' message
81
+ img_win.document.close();
82
+ }
83
+ }
84
+
85
+ // Using an object as namespaces is JS Best Practice. I like the Control.XXX style.
86
+ //if (!Control) {var Control = {}}
87
+ //if (typeof(Control == "undefined")) {var Control = {}}
88
+ if (typeof(Control == "undefined")) {var Control = {OFC: OFC.jquery}}
89
+
90
+
91
+ // By default, right-clicking on OFC and choosing "save image locally" calls this function.
92
+ // You are free to change the code in OFC and call my wrapper (Control.OFC.your_favorite_save_method)
93
+ // function save_image() { alert(1); Control.OFC.popup('my_chart') }
94
+ function save_image() {
95
+ //alert(1);
96
+ OFC.jquery.popup('my_chart')
97
+ }
98
+
99
+ function moo() {
100
+ //alert(99);
101
+ };
102
+
103
+ var data = <?php echo $prli_click->setupClickLineGraph($start_timestamp,$end_timestamp,$link_id,$type); ?>;
104
+
105
+ </script>
classes/views/prli-clicks/list.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+ <p style="font-size: 14px; font-weight: bold; float: right; padding-top: 25px;"><a href="http://blairwilliams.com/faq" target="_blank">Get Help</a>&nbsp;|&nbsp;<a href="http://blairwilliams.com/blog" target="_blank">Blog</a>&nbsp;|&nbsp;<a href="http://blairwilliams.com/don" target="_blank">Donate</a></p>
3
+ <h2><img src="<?php echo PRLI_URL.'/images/pretty-link-med.png'; ?>"/>&nbsp;Pretty Link: Hits</h2>
4
+ <span style="font-size: 14px; font-weight: bold;">For <?php echo $link_name; ?>: </span>
5
+ <?php
6
+ // Don't show this sheesh if we're displaying the vuid or ip grouping
7
+ if(empty($params['ip']) and empty($params['vuid']))
8
+ {
9
+ ?>
10
+ <a href="#" style="display:inline;" class="filter_toggle">Customize Report</a>
11
+ <?php
12
+ }
13
+ ?>
14
+ <?php
15
+ if(!empty($params['l']) and $params['l'] != 'all')
16
+ echo '<br/><a href="?page='. PRLI_PLUGIN_NAME .'/prli-links.php">&laquo Back to Links</a>';
17
+ else if(!empty($params['ip']) or !empty($params['vuid']))
18
+ echo '<br/><a href="?page='. PRLI_PLUGIN_NAME .'/prli-clicks.php">&laquo Back to Hits</a>';
19
+
20
+ if(empty($params['ip']) and empty($params['vuid']))
21
+ {
22
+ ?>
23
+
24
+
25
+ <div class="filter_pane">
26
+ <form class="form-fields" name="form2" method="post" action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>">
27
+ <?php wp_nonce_field('prli-reports'); ?>
28
+ <span>Type:</span>&nbsp;
29
+ <select id="type" name="type" style="display: inline;">
30
+ <option value="all"<?php print ((empty($params['type']) or $params['type'] == "all")?" selected=\"true\"":""); ?>>All Hits&nbsp;</option>
31
+ <option value="unique"<?php print (($params['type'] == "unique")?" selected=\"true\"":""); ?>>Unique Hits&nbsp;</option>
32
+ </select>
33
+ <br/>
34
+ <br/>
35
+ <span>Date Range:</span>
36
+ <div id="dateselectors" style="display: inline;">
37
+ <input type="text" name="sdate" id="sdate" value="<?php echo $params['sdate']; ?>" style="display:inline;"/>&nbsp;to&nbsp;<input type="text" name="edate" id="edate" value="<?php echo $params['edate']; ?>" style="display:inline;"/>
38
+ </div>
39
+ <br/>
40
+ <br/>
41
+ <div class="submit" style="display: inline;"><input type="submit" name="Submit" value="Customize"/> or <a href="#" class="filter_toggle">Cancel</a></div>
42
+ </form>
43
+ </div>
44
+
45
+ <div id="my_chart"></div>
46
+
47
+ <?php
48
+ }
49
+ $navstyle = "float: right;";
50
+ require(PRLI_VIEWS_PATH.'/shared/table-nav.php');
51
+ ?>
52
+
53
+ <div id="search_pane" style="padding-top: 5px;">
54
+ <form class="form-fields" name="click_form" method="post" action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>">
55
+ <?php wp_nonce_field('prli-clicks'); ?>
56
+
57
+ <input type="hidden" name="sort" id="sort" value="<?php echo $sort_str; ?>" />
58
+ <input type="hidden" name="sdir" id="sort" value="<?php echo $sdir_str; ?>" />
59
+ <input type="text" name="search" id="search" value="<?php echo $search_str; ?>" style="display:inline;"/>
60
+ <div class="submit" style="display: inline;"><input type="submit" name="Submit" value="Search Hits"/>
61
+ <?php
62
+ if(!empty($search_str))
63
+ {
64
+ ?>
65
+ or <a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo (!empty($params['l'])?'&l='.$params['l']:''); ?>">Reset</a>
66
+ <?php
67
+ }
68
+ ?>
69
+ </div>
70
+ </form>
71
+ </div>
72
+ <table class="widefat post fixed" cellspacing="0">
73
+ <thead>
74
+ <tr>
75
+ <th class="manage-column" width="5%"><a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo $sort_params; ?>&sort=btype<?php echo (($sort_str == 'btype' and $sdir_str == 'asc')?'&sdir=desc':''); ?>">Browser<?php echo (($sort_str == 'btype')?'&nbsp;&nbsp;&nbsp;<img src="'.$prli_siteurl.'/wp-content/plugins/'.PRLI_PLUGIN_NAME.'/images/'.(($sdir_str == 'desc')?'arrow_down.png':'arrow_up.png').'"/>':'') ?></a>
76
+ </th>
77
+ <th class="manage-column" width="12%">
78
+ <a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo $sort_params; ?>&sort=ip<?php echo (($sort_str == 'ip' and $sdir_str == 'asc')?'&sdir=desc':''); ?>">IP<?php echo (($sort_str == 'ip')?'&nbsp;&nbsp;&nbsp;<img src="'.$prli_siteurl.'/wp-content/plugins/'.PRLI_PLUGIN_NAME.'/images/'.(($sdir_str == 'desc')?'arrow_down.png':'arrow_up.png').'"/>':'') ?></a>
79
+ </th>
80
+ <th class="manage-column" width="12%">
81
+ <a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo $sort_params; ?>&sort=vuid<?php echo (($sort_str == 'vuid' and $sdir_str == 'asc')?'&sdir=desc':''); ?>">Visitor<?php echo (($sort_str == 'vuid')?'&nbsp;&nbsp;&nbsp;<img src="'.$prli_siteurl.'/wp-content/plugins/'.PRLI_PLUGIN_NAME.'/images/'.(($sdir_str == 'desc')?'arrow_down.png':'arrow_up.png').'"/>':'') ?></a>
82
+ </th>
83
+ <th class="manage-column" width="13%">
84
+ <a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo $sort_params; ?>&sort=created_at<?php echo (($sort_str == 'created_at' and $sdir_str == 'asc')?'&sdir=desc':''); ?>">Timestamp<?php echo ((empty($sort_str) or $sort_str == 'created_at')?'&nbsp;&nbsp;&nbsp;<img src="'.$prli_siteurl.'/wp-content/plugins/'.PRLI_PLUGIN_NAME.'/images/'.((empty($sort_str) or $sdir_str == 'desc')?'arrow_down.png':'arrow_up.png').'"/>':'') ?></a>
85
+ </th>
86
+ <th class="manage-column" width="16%">
87
+ <a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo $sort_params; ?>&sort=host<?php echo (($sort_str == 'host' and $sdir_str == 'asc')?'&sdir=desc':''); ?>">Host<?php echo (($sort_str == 'host')?'&nbsp;&nbsp;&nbsp;<img src="'.$prli_siteurl.'/wp-content/plugins/'.PRLI_PLUGIN_NAME.'/images/'.(($sdir_str == 'desc')?'arrow_down.png':'arrow_up.png').'"/>':'') ?></a>
88
+ </th>
89
+ <th class="manage-column" width="16%">
90
+ <a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo $sort_params; ?>&sort=uri<?php echo (($sort_str == 'uri' and $sdir_str == 'asc')?'&sdir=desc':''); ?>">URI<?php echo (($sort_str == 'uri')?'&nbsp;&nbsp;&nbsp;<img src="'.$prli_siteurl.'/wp-content/plugins/'.PRLI_PLUGIN_NAME.'/images/'.(($sdir_str == 'desc')?'arrow_down.png':'arrow_up.png').'"/>':'') ?></a>
91
+ </th>
92
+ <th class="manage-column" width="16%">
93
+ <a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo $sort_params; ?>&sort=referer<?php echo (($sort_str == 'referer' and $sdir_str == 'asc')?'&sdir=desc':''); ?>">Referrer<?php echo (($sort_str == 'referer')?'&nbsp;&nbsp;&nbsp;<img src="'.$prli_siteurl.'/wp-content/plugins/'.PRLI_PLUGIN_NAME.'/images/'.(($sdir_str == 'desc')?'arrow_down.png':'arrow_up.png').'"/>':'') ?></a>
94
+ </th>
95
+ <th class="manage-column" width="13%">
96
+ <a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php<?php echo $sort_params; ?>&sort=link<?php echo (($sort_str == 'link' and $sdir_str == 'asc')?'&sdir=desc':''); ?>">Link<?php echo (($sort_str == 'link')?'&nbsp;&nbsp;&nbsp;<img src="'.$prli_siteurl.'/wp-content/plugins/'.PRLI_PLUGIN_NAME.'/images/'.(($sdir_str == 'desc')?'arrow_down.png':'arrow_up.png').'"/>':'') ?></a>
97
+ </th>
98
+ </tr>
99
+ </thead>
100
+ <?php
101
+
102
+ if(count($clicks) <= 0)
103
+ {
104
+ ?>
105
+ <tr>
106
+ <td colspan="7">No Hits have been recorded yet</td>
107
+ </tr>
108
+ <?php
109
+ }
110
+ else
111
+ {
112
+ foreach($clicks as $click)
113
+ {
114
+ ?>
115
+ <tr>
116
+ <td><img src="<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/images/browser/<?php echo prli_browser_image($click->btype); ?>" alt="<?php echo $click->btype . " v" . $click->bversion; ?>" title="<?php echo $click->btype . " v" . $click->bversion; ?>"/>&nbsp;<img src="<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/images/os/<?php echo prli_os_image($click->os); ?>" alt="<?php echo $click->os; ?>" title="<?php echo $click->os; ?>"/></td>
117
+ <td><a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php&ip=<?php echo $click->ip; ?>" title="View All Activity for IP Address: <?php echo $click->ip; ?>"><?php echo $click->ip; ?> (<?php echo $click->ip_count; ?>)</a></td>
118
+ <td><a href="?page=<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php&vuid=<?php echo $click->vuid; ?>" title="View All Activity for Visitor: <?php echo $click->vuid; ?>"><?php echo $click->vuid; ?><?php echo (($click->vuid != null)?" ($click->vuid_count)":''); ?></a></td>
119
+ <td><?php echo $click->created_at; ?></td>
120
+ <td><?php echo $click->host; ?></td>
121
+ <td><?php echo $click->uri; ?></td>
122
+ <td><?php echo $click->referer; ?></td>
123
+ <td><a href="?page=<?php print PRLI_PLUGIN_NAME; ?>/prli-clicks.php&l=<?php echo $click->link_id; ?>" title="View clicks for <?php echo $click->link_name; ?>"><?php echo $click->link_name; ?></a></td>
124
+ </tr>
125
+ <?php
126
+ }
127
+ }
128
+ ?>
129
+ <tfoot>
130
+ <tr>
131
+ <th class="manage-column">Browser</th>
132
+ <th class="manage-column">IP</th>
133
+ <th class="manage-column">Visitor</th>
134
+ <th class="manage-column">Timestamp</th>
135
+ <th class="manage-column">Host</th>
136
+ <th class="manage-column">URI</th>
137
+ <th class="manage-column">Referrer</th>
138
+ <th class="manage-column">Link</th>
139
+ </tr>
140
+ </tfoot>
141
+ </table>
142
+
143
+ <a href="<?php echo $prli_siteurl; ?>/wp-content/plugins/<?php echo PRLI_PLUGIN_NAME; ?>/prli-clicks.php?action=csv<?php echo $page_params; ?>">Download CSV (<?php echo $link_name; ?>)</a>
144
+
145
+ <?php
146
+ require(PRLI_VIEWS_PATH.'/shared/table-nav.php');
147
+ ?>
148
+
149
+ </div>
classes/views/prli-links/edit.php ADDED
@@ -0,0 +1,87 @@