]> CyberLeo.Net >> Repos - Github/YOURLS.git/blob - includes/functions.php
More filtering options in yourls_update_clicks(). Fixes issue 1036.
[Github/YOURLS.git] / includes / functions.php
1 <?php\r
2 /*\r
3  * YOURLS\r
4  * Function library\r
5  */\r
6 \r
7 // Determine the allowed character set in short URLs\r
8 function yourls_get_shorturl_charset() {\r
9         static $charset = null;\r
10         if( $charset !== null )\r
11                 return $charset;\r
12                 \r
13         if( !defined('YOURLS_URL_CONVERT') ) {\r
14                 $charset = '0123456789abcdefghijklmnopqrstuvwxyz';\r
15         } else {\r
16                 switch( YOURLS_URL_CONVERT ) {\r
17                         case 36:\r
18                                 $charset = '0123456789abcdefghijklmnopqrstuvwxyz';\r
19                                 break;\r
20                         case 62:\r
21                         case 64: // just because some people get this wrong in their config.php\r
22                                 $charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\r
23                                 break;\r
24                 }\r
25         }\r
26         \r
27         $charset = yourls_apply_filter( 'get_shorturl_charset', $charset );\r
28         return $charset;\r
29 }\r
30  \r
31 // Make an optimized regexp pattern from a string of characters\r
32 function yourls_make_regexp_pattern( $string ) {\r
33         $pattern = preg_quote( $string, '-' ); // add - as an escaped characters -- this is fixed in PHP 5.3\r
34         // TODO: replace char sequences by smart sequences such as 0-9, a-z, A-Z ... ?\r
35         return $pattern;\r
36 }\r
37 \r
38 // Is an URL a short URL?\r
39 function yourls_is_shorturl( $shorturl ) {\r
40         // TODO: make sure this function evolves with the feature set.\r
41         \r
42         $is_short = false;\r
43         $keyword = preg_replace( '!^'.YOURLS_SITE.'/!', '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc'\r
44         if( $keyword && $keyword == yourls_sanitize_string( $keyword ) && yourls_keyword_is_taken( $keyword ) ) {\r
45                 $is_short = true;\r
46         }\r
47         \r
48         return yourls_apply_filter( 'is_shorturl', $is_short, $shorturl );\r
49 }\r
50 \r
51 // Check to see if a given keyword is reserved (ie reserved URL or an existing page)\r
52 // Returns bool\r
53 function yourls_keyword_is_reserved( $keyword ) {\r
54         global $yourls_reserved_URL;\r
55         $keyword = yourls_sanitize_keyword( $keyword );\r
56         $reserved = false;\r
57         \r
58         if ( in_array( $keyword, $yourls_reserved_URL)\r
59                 or file_exists( YOURLS_ABSPATH ."/pages/$keyword.php" )\r
60                 or is_dir( YOURLS_ABSPATH ."/$keyword" )\r
61         )\r
62                 $reserved = true;\r
63         \r
64         return yourls_apply_filter( 'keyword_is_reserved', $reserved, $keyword );\r
65 }\r
66 \r
67 // Function: Get IP Address. Returns a DB safe string.\r
68 function yourls_get_IP() {\r
69         if( !empty( $_SERVER['REMOTE_ADDR'] ) ) {\r
70                 $ip = $_SERVER['REMOTE_ADDR'];\r
71         } else {\r
72                 if(!empty($_SERVER['HTTP_CLIENT_IP'])) {\r
73                         $ip = $_SERVER['HTTP_CLIENT_IP'];\r
74                 } else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {\r
75                         $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];\r
76                 } else if(!empty($_SERVER['HTTP_VIA '])) {\r
77                         $ip = $_SERVER['HTTP_VIA '];\r
78                 }\r
79         }\r
80 \r
81         return yourls_apply_filter( 'get_IP', yourls_sanitize_ip( $ip ) );\r
82 }\r
83 \r
84 // Get next id a new link will have if no custom keyword provided\r
85 function yourls_get_next_decimal() {\r
86         return yourls_apply_filter( 'get_next_decimal', (int)yourls_get_option( 'next_id' ) );\r
87 }\r
88 \r
89 // Update id for next link with no custom keyword\r
90 function yourls_update_next_decimal( $int = '' ) {\r
91         $int = ( $int == '' ) ? yourls_get_next_decimal() + 1 : (int)$int ;\r
92         $update = yourls_update_option( 'next_id', $int );\r
93         yourls_do_action( 'update_next_decimal', $int, $update );\r
94         return $update;\r
95 }\r
96 \r
97 // Delete a link in the DB\r
98 function yourls_delete_link_by_keyword( $keyword ) {\r
99         global $ydb;\r
100 \r
101         $table = YOURLS_DB_TABLE_URL;\r
102         $keyword = yourls_sanitize_string( $keyword );\r
103         $delete = $ydb->query("DELETE FROM `$table` WHERE `keyword` = '$keyword';");\r
104         yourls_do_action( 'delete_link', $keyword, $delete );\r
105         return $delete;\r
106 }\r
107 \r
108 // SQL query to insert a new link in the DB. Returns boolean for success or failure of the inserting\r
109 function yourls_insert_link_in_db( $url, $keyword, $title = '' ) {\r
110         global $ydb;\r
111         \r
112         $url     = addslashes( yourls_sanitize_url( $url ) );\r
113         $keyword = addslashes( yourls_sanitize_keyword( $keyword ) );\r
114         $title   = addslashes( yourls_sanitize_title( $title ) );\r
115 \r
116         $table = YOURLS_DB_TABLE_URL;\r
117         $timestamp = date('Y-m-d H:i:s');\r
118         $ip = yourls_get_IP();\r
119         $insert = $ydb->query("INSERT INTO `$table` (`keyword`, `url`, `title`, `timestamp`, `ip`, `clicks`) VALUES('$keyword', '$url', '$title', '$timestamp', '$ip', 0);");\r
120         \r
121         yourls_do_action( 'insert_link', (bool)$insert, $url, $keyword, $title, $timestamp, $ip );\r
122         \r
123         return (bool)$insert;\r
124 }\r
125 \r
126 // Check if a URL already exists in the DB. Return NULL (doesn't exist) or an object with URL informations.\r
127 function yourls_url_exists( $url ) {\r
128         // Allow plugins to short-circuit the whole function\r
129         $pre = yourls_apply_filter( 'shunt_url_exists', false, $url );\r
130         if ( false !== $pre )\r
131                 return $pre;\r
132 \r
133         global $ydb;\r
134         $table = YOURLS_DB_TABLE_URL;\r
135         $strip_url = stripslashes($url);\r
136         $url_exists = $ydb->get_row("SELECT * FROM `$table` WHERE `url` = '".$strip_url."';");\r
137         \r
138         return yourls_apply_filter( 'url_exists', $url_exists, $url );\r
139 }\r
140 \r
141 // Add a new link in the DB, either with custom keyword, or find one\r
142 function yourls_add_new_link( $url, $keyword = '', $title = '' ) {\r
143         global $ydb;\r
144 \r
145         // Allow plugins to short-circuit the whole function\r
146         $pre = yourls_apply_filter( 'shunt_add_new_link', false, $url, $keyword, $title );\r
147         if ( false !== $pre )\r
148                 return $pre;\r
149 \r
150         if ( !$url || $url == 'http://' || $url == 'https://' ) {\r
151                 $return['status'] = 'fail';\r
152                 $return['code'] = 'error:nourl';\r
153                 $return['message'] = 'Missing URL input';\r
154                 $return['errorCode'] = '400';\r
155                 return yourls_apply_filter( 'add_new_link_fail_nourl', $return, $url, $keyword, $title );\r
156         }\r
157         \r
158         // Prevent DB flood\r
159         $ip = yourls_get_IP();\r
160         yourls_check_IP_flood( $ip );\r
161         \r
162         // Prevent internal redirection loops: cannot shorten a shortened URL\r
163         $url = yourls_escape( yourls_sanitize_url($url) );\r
164         if( preg_match( '!^'.YOURLS_SITE.'/!', $url ) ) {\r
165                 if( yourls_is_shorturl( $url ) ) {\r
166                         $return['status'] = 'fail';\r
167                         $return['code'] = 'error:noloop';\r
168                         $return['message'] = 'URL is a short URL';\r
169                         $return['errorCode'] = '400';\r
170                         return yourls_apply_filter( 'add_new_link_fail_noloop', $return, $url, $keyword, $title );\r
171                 }\r
172         }\r
173 \r
174         yourls_do_action( 'pre_add_new_link', $url, $keyword, $title );\r
175         \r
176         $strip_url = stripslashes($url);\r
177         $return = array();\r
178 \r
179         // duplicates allowed or new URL => store it\r
180         if( yourls_allow_duplicate_longurls() || !yourls_url_exists( $url ) ) {\r
181         \r
182                 if( isset( $title ) && !empty( $title ) ) {\r
183                         $title = yourls_sanitize_title( $title );\r
184                 } else {\r
185                         $title = yourls_get_remote_title( $url );\r
186                 }\r
187                 $title = yourls_apply_filter( 'add_new_title', $title, $url, $keyword );\r
188 \r
189                 // Custom keyword provided\r
190                 if ( $keyword ) {\r
191                         \r
192                         yourls_do_action( 'add_new_link_custom_keyword', $url, $keyword, $title );\r
193                 \r
194                         $keyword = yourls_escape( yourls_sanitize_string($keyword) );\r
195                         $keyword = yourls_apply_filter( 'custom_keyword', $keyword, $url, $title );\r
196                         if ( !yourls_keyword_is_free($keyword) ) {\r
197                                 // This shorturl either reserved or taken already\r
198                                 $return['status'] = 'fail';\r
199                                 $return['code'] = 'error:keyword';\r
200                                 $return['message'] = 'Short URL '.$keyword.' already exists in database or is reserved';\r
201                         } else {\r
202                                 // all clear, store !\r
203                                 yourls_insert_link_in_db( $url, $keyword, $title );\r
204                                 $return['url'] = array('keyword' => $keyword, 'url' => $strip_url, 'title' => $title, 'date' => date('Y-m-d H:i:s'), 'ip' => $ip );\r
205                                 $return['status'] = 'success';\r
206                                 $return['message'] = yourls_trim_long_string( $strip_url ).' added to database';\r
207                                 $return['title'] = $title;\r
208                                 $return['html'] = yourls_table_add_row( $keyword, $url, $title, $ip, 0, time() );\r
209                                 $return['shorturl'] = YOURLS_SITE .'/'. $keyword;\r
210                         }\r
211 \r
212                 // Create random keyword        \r
213                 } else {\r
214                         \r
215                         yourls_do_action( 'add_new_link_create_keyword', $url, $keyword, $title );\r
216                 \r
217                         $timestamp = date('Y-m-d H:i:s');\r
218                         $id = yourls_get_next_decimal();\r
219                         $ok = false;\r
220                         do {\r
221                                 $keyword = yourls_int2string( $id );\r
222                                 $keyword = yourls_apply_filter( 'random_keyword', $keyword, $url, $title );\r
223                                 $free = yourls_keyword_is_free($keyword);\r
224                                 $add_url = @yourls_insert_link_in_db( $url, $keyword, $title );\r
225                                 $ok = ($free && $add_url);\r
226                                 if ( $ok === false && $add_url === 1 ) {\r
227                                         // we stored something, but shouldn't have (ie reserved id)\r
228                                         $delete = yourls_delete_link_by_keyword( $keyword );\r
229                                         $return['extra_info'] .= '(deleted '.$keyword.')';\r
230                                 } else {\r
231                                         // everything ok, populate needed vars\r
232                                         $return['url'] = array('keyword' => $keyword, 'url' => $strip_url, 'title' => $title, 'date' => $timestamp, 'ip' => $ip );\r
233                                         $return['status'] = 'success';\r
234                                         $return['message'] = yourls_trim_long_string( $strip_url ).' added to database';\r
235                                         $return['title'] = $title;\r
236                                         $return['html'] = yourls_table_add_row( $keyword, $url, $title, $ip, 0, time() );\r
237                                         $return['shorturl'] = YOURLS_SITE .'/'. $keyword;\r
238                                 }\r
239                                 $id++;\r
240                         } while (!$ok);\r
241                         @yourls_update_next_decimal($id);\r
242                 }\r
243 \r
244         // URL was already stored\r
245         } else {\r
246                         \r
247                 yourls_do_action( 'add_new_link_already_stored', $url, $keyword, $title );\r
248                 \r
249                 $return['status'] = 'fail';\r
250                 $return['code'] = 'error:url';\r
251                 $return['url'] = array( 'keyword' => $url_exists->keyword, 'url' => $strip_url, 'title' => $url_exists->title, 'date' => $url_exists->timestamp, 'ip' => $url_exists->ip, 'clicks' => $url_exists->clicks );\r
252                 $return['message'] = yourls_trim_long_string( $strip_url ).' already exists in database';\r
253                 $return['title'] = $url_exists->title; \r
254                 $return['shorturl'] = YOURLS_SITE .'/'. $url_exists->keyword;\r
255         }\r
256         \r
257         yourls_do_action( 'post_add_new_link', $url, $keyword, $title );\r
258 \r
259         $return['statusCode'] = 200; // regardless of result, this is still a valid request\r
260         return yourls_apply_filter( 'add_new_link', $return, $url, $keyword, $title );\r
261 }\r
262 \r
263 \r
264 // Edit a link\r
265 function yourls_edit_link( $url, $keyword, $newkeyword='', $title='' ) {\r
266         global $ydb;\r
267 \r
268         $table = YOURLS_DB_TABLE_URL;\r
269         $url = yourls_escape(yourls_sanitize_url($url));\r
270         $keyword = yourls_escape(yourls_sanitize_string( $keyword ));\r
271         $title = yourls_escape(yourls_sanitize_title( $title ));\r
272         $newkeyword = yourls_escape(yourls_sanitize_string( $newkeyword ));\r
273         $strip_url = stripslashes($url);\r
274         $strip_title = stripslashes($title);\r
275         $old_url = $ydb->get_var("SELECT `url` FROM `$table` WHERE `keyword` = '$keyword';");\r
276         \r
277         // Check if new URL is not here already\r
278         if ( $old_url != $url && !yourls_allow_duplicate_longurls() ) {\r
279                 $new_url_already_there = intval($ydb->get_var("SELECT COUNT(keyword) FROM `$table` WHERE `url` = '$strip_url';"));\r
280         } else {\r
281                 $new_url_already_there = false;\r
282         }\r
283         \r
284         // Check if the new keyword is not here already\r
285         if ( $newkeyword != $keyword ) {\r
286                 $keyword_is_ok = yourls_keyword_is_free( $newkeyword );\r
287         } else {\r
288                 $keyword_is_ok = true;\r
289         }\r
290         \r
291         yourls_do_action( 'pre_edit_link', $url, $keyword, $newkeyword, $new_url_already_there, $keyword_is_ok );\r
292         \r
293         // All clear, update\r
294         if ( ( !$new_url_already_there || yourls_allow_duplicate_longurls() ) && $keyword_is_ok ) {\r
295                         $update_url = $ydb->query("UPDATE `$table` SET `url` = '$url', `keyword` = '$newkeyword', `title` = '$title' WHERE `keyword` = '$keyword';");\r
296                 if( $update_url ) {\r
297                         $return['url'] = array( 'keyword' => $newkeyword, 'shorturl' => YOURLS_SITE.'/'.$newkeyword, 'url' => $strip_url, 'display_url' => yourls_trim_long_string( $strip_url ), 'title' => $strip_title, 'display_title' => yourls_trim_long_string( $strip_title ) );\r
298                         $return['status'] = 'success';\r
299                         $return['message'] = 'Link updated in database';\r
300                 } else {\r
301                         $return['status'] = 'fail';\r
302                         $return['message'] = 'Error updating '. yourls_trim_long_string( $strip_url ).' (Short URL: '.$keyword.') to database';\r
303                 }\r
304         \r
305         // Nope\r
306         } else {\r
307                 $return['status'] = 'fail';\r
308                 $return['message'] = 'URL or keyword already exists in database';\r
309         }\r
310         \r
311         return yourls_apply_filter( 'edit_link', $return, $url, $keyword, $newkeyword, $title, $new_url_already_there, $keyword_is_ok );\r
312 }\r
313 \r
314 // Update a title link (no checks for duplicates etc..)\r
315 function yourls_edit_link_title( $keyword, $title ) {\r
316         global $ydb;\r
317         \r
318         $keyword = yourls_escape( yourls_sanitize_keyword( $keyword ) );\r
319         $title = yourls_escape( yourls_sanitize_title( $title ) );\r
320         \r
321         $table = YOURLS_DB_TABLE_URL;\r
322         $update = $ydb->query("UPDATE `$table` SET `title` = '$title' WHERE `keyword` = '$keyword';");\r
323 \r
324         return $update;\r
325 }\r
326 \r
327 \r
328 // Check if keyword id is free (ie not already taken, and not reserved). Return bool.\r
329 function yourls_keyword_is_free( $keyword ) {\r
330         $free = true;\r
331         if ( yourls_keyword_is_reserved( $keyword ) or yourls_keyword_is_taken( $keyword ) )\r
332                 $free = false;\r
333                 \r
334         return yourls_apply_filter( 'keyword_is_free', $free, $keyword );\r
335 }\r
336 \r
337 // Check if a keyword is taken (ie there is already a short URL with this id). Return bool.             \r
338 function yourls_keyword_is_taken( $keyword ) {\r
339         global $ydb;\r
340         $keyword = yourls_sanitize_keyword( $keyword );\r
341         $taken = false;\r
342         $table = YOURLS_DB_TABLE_URL;\r
343         $already_exists = $ydb->get_var("SELECT COUNT(`keyword`) FROM `$table` WHERE `keyword` = '$keyword';");\r
344         if ( $already_exists )\r
345                 $taken = true;\r
346 \r
347         return yourls_apply_filter( 'keyword_is_taken', $taken, $keyword );\r
348 }\r
349 \r
350 \r
351 // Connect to DB\r
352 function yourls_db_connect() {\r
353         global $ydb;\r
354 \r
355         if (!defined('YOURLS_DB_USER')\r
356                 or !defined('YOURLS_DB_PASS')\r
357                 or !defined('YOURLS_DB_NAME')\r
358                 or !defined('YOURLS_DB_HOST')\r
359                 or !class_exists('ezSQL_mysql')\r
360         ) yourls_die ('DB config missing, or could not find DB class', 'Fatal error', 503);\r
361         \r
362         // Are we standalone or in the WordPress environment?\r
363         if ( class_exists('wpdb') ) {\r
364                 $ydb =  new wpdb(YOURLS_DB_USER, YOURLS_DB_PASS, YOURLS_DB_NAME, YOURLS_DB_HOST);\r
365         } else {\r
366                 $ydb =  new ezSQL_mysql(YOURLS_DB_USER, YOURLS_DB_PASS, YOURLS_DB_NAME, YOURLS_DB_HOST);\r
367         }\r
368         if ( $ydb->last_error )\r
369                 yourls_die( $ydb->last_error, 'Fatal error', 503 );\r
370         \r
371         if ( defined('YOURLS_DEBUG') && YOURLS_DEBUG === true )\r
372                 $ydb->show_errors = true;\r
373         \r
374         return $ydb;\r
375 }\r
376 \r
377 // Return XML output.\r
378 function yourls_xml_encode($array) {\r
379         require_once(YOURLS_INC.'/functions-xml.php');\r
380         $converter= new yourls_array2xml;\r
381         return $converter->array2xml($array);\r
382 }\r
383 \r
384 // Return array of all informations associated with keyword. Returns false if keyword not found. Set optional $use_cache to false to force fetching from DB\r
385 function yourls_get_keyword_infos( $keyword, $use_cache = true ) {\r
386         global $ydb;\r
387         $keyword = yourls_sanitize_string( $keyword );\r
388 \r
389         yourls_do_action( 'pre_get_keyword', $keyword, $use_cache );\r
390 \r
391         if( isset( $ydb->infos[$keyword] ) && $use_cache == true ) {\r
392                 return yourls_apply_filter( 'get_keyword_infos', $ydb->infos[$keyword], $keyword );\r
393         }\r
394         \r
395         yourls_do_action( 'get_keyword_not_cached', $keyword );\r
396         \r
397         $table = YOURLS_DB_TABLE_URL;\r
398         $infos = $ydb->get_row("SELECT * FROM `$table` WHERE `keyword` = '$keyword'");\r
399         \r
400         if( $infos ) {\r
401                 $infos = (array)$infos;\r
402                 $ydb->infos[$keyword] = $infos;\r
403         } else {\r
404                 $ydb->infos[$keyword] = false;\r
405         }\r
406                 \r
407         return yourls_apply_filter( 'get_keyword_infos', $ydb->infos[$keyword], $keyword );\r
408 }\r
409 \r
410 // Return (string) selected information associated with a keyword. Optional $notfound = string default message if nothing found\r
411 function yourls_get_keyword_info( $keyword, $field, $notfound = false ) {\r
412 \r
413         // Allow plugins to short-circuit the whole function\r
414         $pre = yourls_apply_filter( 'shunt_get_keyword_info', false, $keyword, $field, $notfound );\r
415         if ( false !== $pre )\r
416                 return $pre;\r
417 \r
418         $keyword = yourls_sanitize_string( $keyword );\r
419         $infos = yourls_get_keyword_infos( $keyword );\r
420         \r
421         $return = $notfound;\r
422         if ( isset($infos[$field]) && $infos[$field] !== false )\r
423                 $return = $infos[$field];\r
424 \r
425         return yourls_apply_filter( 'get_keyword_info', $return, $keyword, $field, $notfound ); \r
426 }\r
427 \r
428 // Return title associated with keyword. Optional $notfound = string default message if nothing found\r
429 function yourls_get_keyword_title( $keyword, $notfound = false ) {\r
430         return yourls_get_keyword_info( $keyword, 'title', $notfound );\r
431 }\r
432 \r
433 // Return long URL associated with keyword. Optional $notfound = string default message if nothing found\r
434 function yourls_get_keyword_longurl( $keyword, $notfound = false ) {\r
435         return yourls_get_keyword_info( $keyword, 'url', $notfound );\r
436 }\r
437 \r
438 // Return number of clicks on a keyword. Optional $notfound = string default message if nothing found\r
439 function yourls_get_keyword_clicks( $keyword, $notfound = false ) {\r
440         return yourls_get_keyword_info( $keyword, 'clicks', $notfound );\r
441 }\r
442 \r
443 // Return IP that added a keyword. Optional $notfound = string default message if nothing found\r
444 function yourls_get_keyword_IP( $keyword, $notfound = false ) {\r
445         return yourls_get_keyword_info( $keyword, 'ip', $notfound );\r
446 }\r
447 \r
448 // Return timestamp associated with a keyword. Optional $notfound = string default message if nothing found\r
449 function yourls_get_keyword_timestamp( $keyword, $notfound = false ) {\r
450         return yourls_get_keyword_info( $keyword, 'timestamp', $notfound );\r
451 }\r
452 \r
453 // Update click count on a short URL. Return 0/1 for error/success.\r
454 function yourls_update_clicks( $keyword, $clicks = false ) {\r
455         // Allow plugins to short-circuit the whole function\r
456         $pre = yourls_apply_filter( 'shunt_update_clicks', false, $keyword, $clicks );\r
457         if ( false !== $pre )\r
458                 return $pre;\r
459 \r
460         global $ydb;\r
461         $keyword = yourls_sanitize_string( $keyword );\r
462         $table = YOURLS_DB_TABLE_URL;\r
463         if ( $clicks !== false && is_int( $clicks ) && $clicks >= 0 )\r
464                 $update = $ydb->query("UPDATE `$table` SET `clicks` = $clicks WHERE `keyword` = '$keyword'");\r
465         else\r
466                 $update = $ydb->query("UPDATE `$table` SET `clicks` = clicks + 1 WHERE `keyword` = '$keyword'");\r
467 \r
468         yourls_do_action( 'update_clicks', $keyword, $update, $clicks );\r
469         return $update;\r
470 }\r
471 \r
472 // Return array of stats. (string)$filter is 'bottom', 'last', 'rand' or 'top'. (int)$limit is the number of links to return\r
473 function yourls_get_stats( $filter = 'top', $limit = 10, $start = 0 ) {\r
474         global $ydb;\r
475 \r
476         switch( $filter ) {\r
477                 case 'bottom':\r
478                         $sort_by = 'clicks';\r
479                         $sort_order = 'asc';\r
480                         break;\r
481                 case 'last':\r
482                         $sort_by = 'timestamp';\r
483                         $sort_order = 'desc';\r
484                         break;\r
485                 case 'rand':\r
486                 case 'random':\r
487                         $sort_by = 'RAND()';\r
488                         $sort_order = '';\r
489                         break;\r
490                 case 'top':\r
491                 default:\r
492                         $sort_by = 'clicks';\r
493                         $sort_order = 'desc';\r
494                         break;\r
495         }\r
496         \r
497         // Fetch links\r
498         $limit = intval( $limit );\r
499         $start = intval( $start );\r
500         if ( $limit > 0 ) {\r
501 \r
502                 $table_url = YOURLS_DB_TABLE_URL;\r
503                 $results = $ydb->get_results("SELECT * FROM `$table_url` WHERE 1=1 ORDER BY `$sort_by` $sort_order LIMIT $start, $limit;");\r
504                 \r
505                 $return = array();\r
506                 $i = 1;\r
507                 \r
508                 foreach ( (array)$results as $res) {\r
509                         $return['links']['link_'.$i++] = array(\r
510                                 'shorturl' => YOURLS_SITE .'/'. $res->keyword,\r
511                                 'url'      => $res->url,\r
512                                 'title'    => $res->title,\r
513                                 'timestamp'=> $res->timestamp,\r
514                                 'ip'       => $res->ip,\r
515                                 'clicks'   => $res->clicks,\r
516                         );\r
517                 }\r
518         }\r
519 \r
520         $return['stats'] = yourls_get_db_stats();\r
521         \r
522         $return['statusCode'] = 200;\r
523 \r
524         return yourls_apply_filter( 'get_stats', $return, $filter, $limit, $start );\r
525 }\r
526 \r
527 // Return array of stats. (string)$filter is 'bottom', 'last', 'rand' or 'top'. (int)$limit is the number of links to return\r
528 function yourls_get_link_stats( $shorturl ) {\r
529         global $ydb;\r
530 \r
531         $table_url = YOURLS_DB_TABLE_URL;\r
532         $res = $ydb->get_row("SELECT * FROM `$table_url` WHERE keyword = '$shorturl';");\r
533         $return = array();\r
534 \r
535         if( !$res ) {\r
536                 // non existent link\r
537                 $return = array(\r
538                         'statusCode' => 404,\r
539                         'message'    => 'Error: short URL not found',\r
540                 );\r
541         } else {\r
542                 $return = array(\r
543                         'statusCode' => 200,\r
544                         'message'    => 'success',\r
545                         'link'       => array(\r
546                         'shorturl' => YOURLS_SITE .'/'. $res->keyword,\r
547                         'url'      => $res->url,\r
548                         'title'    => $res->title,\r
549                         'timestamp'=> $res->timestamp,\r
550                         'ip'       => $res->ip,\r
551                         'clicks'   => $res->clicks,\r
552                         )\r
553                 );\r
554         }\r
555 \r
556         return yourls_apply_filter( 'get_link_stats', $return, $shorturl );\r
557 }\r
558 \r
559 // Return array for API stat requests\r
560 function yourls_api_stats( $filter = 'top', $limit = 10, $start = 0 ) {\r
561         $return = yourls_get_stats( $filter, $limit, $start );\r
562         $return['simple']  = 'Need either XML or JSON format for stats';\r
563         $return['message'] = 'success';\r
564         return yourls_apply_filter( 'api_stats', $return, $filter, $limit, $start );\r
565 }\r
566 \r
567 // Return array for counts of shorturls and clicks\r
568 function yourls_api_db_stats() {\r
569         $return = yourls_get_db_stats();\r
570         $return['simple']  = 'Need either XML or JSON format for stats';\r
571         $return['message'] = 'success';\r
572         return yourls_apply_filter( 'api_db_stats', $return );\r
573 }\r
574 \r
575 // Return array for API stat requests\r
576 function yourls_api_url_stats($shorturl) {\r
577         $keyword = str_replace( YOURLS_SITE . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc'\r
578         $keyword = yourls_sanitize_string( $keyword );\r
579 \r
580         $return = yourls_get_link_stats( $keyword );\r
581         $return['simple']  = 'Need either XML or JSON format for stats';\r
582         return yourls_apply_filter( 'api_url_stats', $return, $shorturl );\r
583 }\r
584 \r
585 // Expand short url to long url\r
586 function yourls_api_expand( $shorturl ) {\r
587         $keyword = str_replace( YOURLS_SITE . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc'\r
588         $keyword = yourls_sanitize_string( $keyword );\r
589         \r
590         $longurl = yourls_get_keyword_longurl( $keyword );\r
591         \r
592         if( $longurl ) {\r
593                 $return = array(\r
594                         'keyword'  => $keyword,\r
595                         'shorturl' => YOURLS_SITE . "/$keyword",\r
596                         'longurl'  => $longurl,\r
597                         'simple'   => $longurl,\r
598                         'message'  => 'success',\r
599                         'statusCode' => 200,\r
600                 );\r
601         } else {\r
602                 $return = array(\r
603                         'keyword'  => $keyword,\r
604                         'simple'   => 'not found',\r
605                         'message'  => 'Error: short URL not found',\r
606                         'errorCode' => 404,\r
607                 );\r
608         }\r
609         \r
610         return yourls_apply_filter( 'api_expand', $return, $shorturl );\r
611 }\r
612 \r
613 \r
614 // Get total number of URLs and sum of clicks. Input: optional "AND WHERE" clause. Returns array\r
615 function yourls_get_db_stats( $where = '' ) {\r
616         global $ydb;\r
617         $table_url = YOURLS_DB_TABLE_URL;\r
618 \r
619         $totals = $ydb->get_row("SELECT COUNT(keyword) as count, SUM(clicks) as sum FROM `$table_url` WHERE 1=1 $where");\r
620         $return = array( 'total_links' => $totals->count, 'total_clicks' => $totals->sum );\r
621         \r
622         return yourls_apply_filter( 'get_db_stats', $return, $where );\r
623 }\r
624 \r
625 // Return API result. Dies after this\r
626 function yourls_api_output( $mode, $return ) {\r
627         if( isset( $return['simple'] ) ) {\r
628                 $simple = $return['simple'];\r
629                 unset( $return['simple'] );\r
630         }\r
631         \r
632         yourls_do_action( 'pre_api_output', $mode, $return );\r
633         \r
634         switch ( $mode ) {\r
635                 case 'jsonp':\r
636                         header('Content-type: application/javascript');\r
637                         echo $return['callback'] . '(' . json_encode($return) . ')';\r
638                         break;\r
639     \r
640                 case 'json':\r
641                         header('Content-type: application/json');\r
642                         echo json_encode($return);\r
643                         break;\r
644                 \r
645                 case 'xml':\r
646                         header('Content-type: application/xml');\r
647                         echo yourls_xml_encode($return);\r
648                         break;\r
649                         \r
650                 case 'simple':\r
651                 default:\r
652                         if( isset( $simple ) )\r
653                                 echo $simple;\r
654                         break;\r
655         }\r
656 \r
657         yourls_do_action( 'api_output', $mode, $return );\r
658         \r
659         die();\r
660 }\r
661 \r
662 // Get number of SQL queries performed\r
663 function yourls_get_num_queries() {\r
664         global $ydb;\r
665 \r
666         return yourls_apply_filter( 'get_num_queries', $ydb->num_queries );\r
667 }\r
668 \r
669 // Returns a sanitized a user agent string. Given what I found on http://www.user-agents.org/ it should be OK.\r
670 function yourls_get_user_agent() {\r
671         if ( !isset( $_SERVER['HTTP_USER_AGENT'] ) )\r
672                 return '-';\r
673         \r
674         $ua = strip_tags( html_entity_decode( $_SERVER['HTTP_USER_AGENT'] ));\r
675         $ua = preg_replace('![^0-9a-zA-Z\':., /{}\(\)\[\]\+@&\!\?;_\-=~\*\#]!', '', $ua );\r
676                 \r
677         return yourls_apply_filter( 'get_user_agent', substr( $ua, 0, 254 ) );\r
678 }\r
679 \r
680 // Redirect to another page\r
681 function yourls_redirect( $location, $code = 301 ) {\r
682         yourls_do_action( 'pre_redirect', $location, $code );\r
683         $location = yourls_apply_filter( 'redirect', $location, $code );\r
684         // Redirect, either properly if possible, or via Javascript otherwise\r
685         if( !headers_sent() ) {\r
686                 yourls_status_header( $code );\r
687                 header( "Location: $location" );\r
688         } else {\r
689                 yourls_redirect_javascript( $location );\r
690         }\r
691         die();\r
692 }\r
693 \r
694 // Set HTTP status header\r
695 function yourls_status_header( $code = 200 ) {\r
696         if( headers_sent() )\r
697                 return;\r
698                 \r
699         $protocol = $_SERVER["SERVER_PROTOCOL"];\r
700         if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )\r
701                 $protocol = 'HTTP/1.0';\r
702 \r
703         $code = intval( $code );\r
704         $desc = yourls_get_HTTP_status( $code );\r
705 \r
706         @header ("$protocol $code $desc"); // This causes problems on IIS and some FastCGI setups\r
707         yourls_do_action( 'status_header', $code );\r
708 }\r
709 \r
710 // Redirect to another page using Javascript. Set optional (bool)$dontwait to false to force manual redirection (make sure a message has been read by user)\r
711 function yourls_redirect_javascript( $location, $dontwait = true ) {\r
712         yourls_do_action( 'pre_redirect_javascript', $location, $dontwait );\r
713         $location = yourls_apply_filter( 'redirect_javascript', $location, $dontwait );\r
714         if( $dontwait ) {\r
715                 echo <<<REDIR\r
716                 <script type="text/javascript">\r
717                 window.location="$location";\r
718                 </script>\r
719                 <small>(if you are not redirected after 10 seconds, please <a href="$location">click here</a>)</small>\r
720 REDIR;\r
721         } else {\r
722                 echo <<<MANUAL\r
723                 <p>Please <a href="$location">click here</a></p>\r
724 MANUAL;\r
725         }\r
726         yourls_do_action( 'post_redirect_javascript', $location );\r
727 }\r
728 \r
729 // Return a HTTP status code\r
730 function yourls_get_HTTP_status( $code ) {\r
731         $code = intval( $code );\r
732         $headers_desc = array(\r
733                 100 => 'Continue',\r
734                 101 => 'Switching Protocols',\r
735                 102 => 'Processing',\r
736 \r
737                 200 => 'OK',\r
738                 201 => 'Created',\r
739                 202 => 'Accepted',\r
740                 203 => 'Non-Authoritative Information',\r
741                 204 => 'No Content',\r
742                 205 => 'Reset Content',\r
743                 206 => 'Partial Content',\r
744                 207 => 'Multi-Status',\r
745                 226 => 'IM Used',\r
746 \r
747                 300 => 'Multiple Choices',\r
748                 301 => 'Moved Permanently',\r
749                 302 => 'Found',\r
750                 303 => 'See Other',\r
751                 304 => 'Not Modified',\r
752                 305 => 'Use Proxy',\r
753                 306 => 'Reserved',\r
754                 307 => 'Temporary Redirect',\r
755 \r
756                 400 => 'Bad Request',\r
757                 401 => 'Unauthorized',\r
758                 402 => 'Payment Required',\r
759                 403 => 'Forbidden',\r
760                 404 => 'Not Found',\r
761                 405 => 'Method Not Allowed',\r
762                 406 => 'Not Acceptable',\r
763                 407 => 'Proxy Authentication Required',\r
764                 408 => 'Request Timeout',\r
765                 409 => 'Conflict',\r
766                 410 => 'Gone',\r
767                 411 => 'Length Required',\r
768                 412 => 'Precondition Failed',\r
769                 413 => 'Request Entity Too Large',\r
770                 414 => 'Request-URI Too Long',\r
771                 415 => 'Unsupported Media Type',\r
772                 416 => 'Requested Range Not Satisfiable',\r
773                 417 => 'Expectation Failed',\r
774                 422 => 'Unprocessable Entity',\r
775                 423 => 'Locked',\r
776                 424 => 'Failed Dependency',\r
777                 426 => 'Upgrade Required',\r
778 \r
779                 500 => 'Internal Server Error',\r
780                 501 => 'Not Implemented',\r
781                 502 => 'Bad Gateway',\r
782                 503 => 'Service Unavailable',\r
783                 504 => 'Gateway Timeout',\r
784                 505 => 'HTTP Version Not Supported',\r
785                 506 => 'Variant Also Negotiates',\r
786                 507 => 'Insufficient Storage',\r
787                 510 => 'Not Extended'\r
788         );\r
789 \r
790         if ( isset( $headers_desc[$code] ) )\r
791                 return $headers_desc[$code];\r
792         else\r
793                 return '';\r
794 }\r
795 \r
796 \r
797 // Log a redirect (for stats)\r
798 function yourls_log_redirect( $keyword ) {\r
799         // Allow plugins to short-circuit the whole function\r
800         $pre = yourls_apply_filter( 'shunt_log_redirect', false, $keyword );\r
801         if ( false !== $pre )\r
802                 return $pre;\r
803 \r
804         if ( !yourls_do_log_redirect() )\r
805                 return true;\r
806 \r
807         global $ydb;\r
808         $table = YOURLS_DB_TABLE_LOG;\r
809         \r
810         $keyword = yourls_sanitize_string( $keyword );\r
811         $referrer = ( isset( $_SERVER['HTTP_REFERER'] ) ? yourls_sanitize_url( $_SERVER['HTTP_REFERER'] ) : 'direct' );\r
812         $ua = yourls_get_user_agent();\r
813         $ip = yourls_get_IP();\r
814         $location = yourls_geo_ip_to_countrycode( $ip );\r
815         \r
816         return $ydb->query( "INSERT INTO `$table` (click_time, shorturl, referrer, user_agent, ip_address, country_code) VALUES (NOW(), '$keyword', '$referrer', '$ua', '$ip', '$location')" );\r
817 }\r
818 \r
819 // Check if we want to not log redirects (for stats)\r
820 function yourls_do_log_redirect() {\r
821         return ( !defined('YOURLS_NOSTATS') || YOURLS_NOSTATS != true );\r
822 }\r
823 \r
824 // Converts an IP to a 2 letter country code, using GeoIP database if available in includes/geo/\r
825 function yourls_geo_ip_to_countrycode( $ip = '', $default = '' ) {\r
826         // Allow plugins to short-circuit the Geo IP API\r
827         $location = yourls_apply_filter( 'shunt_geo_ip_to_countrycode', false, $ip, $default ); // at this point $ip can be '', check if your plugin hooks in here\r
828         if ( false !== $location )\r
829                 return $location;\r
830 \r
831         if ( !file_exists( YOURLS_INC.'/geo/GeoIP.dat') || !file_exists( YOURLS_INC.'/geo/geoip.inc') )\r
832                 return $default;\r
833 \r
834         if ( $ip == '' )\r
835                 $ip = yourls_get_IP();\r
836         \r
837         require_once( YOURLS_INC.'/geo/geoip.inc') ;\r
838         $gi = geoip_open( YOURLS_INC.'/geo/GeoIP.dat', GEOIP_STANDARD);\r
839         $location = geoip_country_code_by_addr($gi, $ip);\r
840         geoip_close($gi);\r
841 \r
842         return yourls_apply_filter( 'geo_ip_to_countrycode', $location, $ip, $default );\r
843 }\r
844 \r
845 // Converts a 2 letter country code to long name (ie AU -> Australia)\r
846 function yourls_geo_countrycode_to_countryname( $code ) {\r
847         // Allow plugins to short-circuit the Geo IP API\r
848         $country = yourls_apply_filter( 'shunt_geo_countrycode_to_countryname', false, $code );\r
849         if ( false !== $country )\r
850                 return $country;\r
851 \r
852         // Load the Geo class if not already done\r
853         if( !class_exists('GeoIP') ) {\r
854                 $temp = yourls_geo_ip_to_countrycode('127.0.0.1');\r
855         }\r
856         \r
857         if( class_exists('GeoIP') ) {\r
858                 $geo = new GeoIP;\r
859                 $id = $geo->GEOIP_COUNTRY_CODE_TO_NUMBER[$code];\r
860                 $long = $geo->GEOIP_COUNTRY_NAMES[$id];\r
861                 return $long;\r
862         } else {\r
863                 return false;\r
864         }\r
865 }\r
866 \r
867 // Return flag URL from 2 letter country code\r
868 function yourls_geo_get_flag( $code ) {\r
869         if( file_exists( YOURLS_INC.'/geo/flags/flag_'.strtolower($code).'.gif' ) ) {\r
870                 $img = yourls_match_current_protocol( YOURLS_SITE.'/includes/geo/flags/flag_'.(strtolower($code)).'.gif' );\r
871         } else {\r
872                 $img = false;\r
873         }\r
874         return yourls_apply_filter( 'geo_get_flag', $img, $code );\r
875 }\r
876 \r
877 \r
878 // Check if an upgrade is needed\r
879 function yourls_upgrade_is_needed() {\r
880         // check YOURLS_DB_VERSION exist && match values stored in YOURLS_DB_TABLE_OPTIONS\r
881         list( $currentver, $currentsql ) = yourls_get_current_version_from_sql();\r
882         if( $currentsql < YOURLS_DB_VERSION )\r
883                 return true;\r
884                 \r
885         return false;\r
886 }\r
887 \r
888 // Get current version & db version as stored in the options DB. Prior to 1.4 there's no option table.\r
889 function yourls_get_current_version_from_sql() {\r
890         $currentver = yourls_get_option( 'version' );\r
891         $currentsql = yourls_get_option( 'db_version' );\r
892 \r
893         // Values if version is 1.3\r
894         if( !$currentver )\r
895                 $currentver = '1.3';\r
896         if( !$currentsql )\r
897                 $currentsql = '100';\r
898                 \r
899         return array( $currentver, $currentsql);\r
900 }\r
901 \r
902 // Read an option from DB (or from cache if available). Return value or $default if not found\r
903 function yourls_get_option( $option_name, $default = false ) {\r
904         global $ydb;\r
905         \r
906         // Allow plugins to short-circuit options\r
907         $pre = yourls_apply_filter( 'shunt_option_'.$option_name, false );\r
908         if ( false !== $pre )\r
909                 return $pre;\r
910 \r
911         // If option not cached already, get its value from the DB\r
912         if ( !isset( $ydb->option[$option_name] ) ) {\r
913                 $table = YOURLS_DB_TABLE_OPTIONS;\r
914                 $option_name = yourls_escape( $option_name );\r
915                 $row = $ydb->get_row( "SELECT `option_value` FROM `$table` WHERE `option_name` = '$option_name' LIMIT 1" );\r
916                 if ( is_object( $row) ) { // Has to be get_row instead of get_var because of funkiness with 0, false, null values\r
917                         $value = $row->option_value;\r
918                 } else { // option does not exist, so we must cache its non-existence\r
919                         $value = $default;\r
920                 }\r
921                 $ydb->option[$option_name] = yourls_maybe_unserialize( $value );\r
922         }\r
923 \r
924         return yourls_apply_filter( 'get_option_'.$option_name, $ydb->option[$option_name] );\r
925 }\r
926 \r
927 // Read all options from DB at once\r
928 function yourls_get_all_options() {\r
929         global $ydb;\r
930 \r
931         // Allow plugins to short-circuit all options. (Note: regular plugins are loaded after all options)\r
932         $pre = yourls_apply_filter( 'shunt_all_options', false );\r
933         if ( false !== $pre )\r
934                 return $pre;\r
935 \r
936         $table = YOURLS_DB_TABLE_OPTIONS;\r
937         \r
938         $allopt = $ydb->get_results("SELECT `option_name`, `option_value` FROM `$table` WHERE 1=1");\r
939         \r
940         foreach( (array)$allopt as $option ) {\r
941                 $ydb->option[$option->option_name] = yourls_maybe_unserialize( $option->option_value );\r
942         }\r
943         \r
944         $ydb->option = yourls_apply_filter( 'get_all_options', $ydb->option );\r
945 }\r
946 \r
947 // Update (add if doesn't exist) an option to DB\r
948 function yourls_update_option( $option_name, $newvalue ) {\r
949         global $ydb;\r
950         $table = YOURLS_DB_TABLE_OPTIONS;\r
951 \r
952         $safe_option_name = yourls_escape( $option_name );\r
953 \r
954         $oldvalue = yourls_get_option( $safe_option_name );\r
955 \r
956         // If the new and old values are the same, no need to update.\r
957         if ( $newvalue === $oldvalue )\r
958                 return false;\r
959 \r
960         if ( false === $oldvalue ) {\r
961                 yourls_add_option( $option_name, $newvalue );\r
962                 return true;\r
963         }\r
964 \r
965         $_newvalue = yourls_escape( yourls_maybe_serialize( $newvalue ) );\r
966         \r
967         yourls_do_action( 'update_option', $option_name, $oldvalue, $newvalue );\r
968 \r
969         $ydb->query( "UPDATE `$table` SET `option_value` = '$_newvalue' WHERE `option_name` = '$option_name'");\r
970 \r
971         if ( $ydb->rows_affected == 1 ) {\r
972                 $ydb->option[$option_name] = $newvalue;\r
973                 return true;\r
974         }\r
975         return false;\r
976 }\r
977 \r
978 // Add an option to the DB\r
979 function yourls_add_option( $name, $value = '' ) {\r
980         global $ydb;\r
981         $table = YOURLS_DB_TABLE_OPTIONS;\r
982         $safe_name = yourls_escape( $name );\r
983 \r
984         // Make sure the option doesn't already exist\r
985         if ( false !== yourls_get_option( $safe_name ) )\r
986                 return;\r
987 \r
988         $_value = yourls_escape( yourls_maybe_serialize( $value ) );\r
989 \r
990         yourls_do_action( 'add_option', $safe_name, $_value );\r
991 \r
992         $ydb->query( "INSERT INTO `$table` (`option_name`, `option_value`) VALUES ('$name', '$_value')" );\r
993         $ydb->option[$name] = $value;\r
994         return;\r
995 }\r
996 \r
997 \r
998 // Delete an option from the DB\r
999 function yourls_delete_option( $name ) {\r
1000         global $ydb;\r
1001         $table = YOURLS_DB_TABLE_OPTIONS;\r
1002         $name = yourls_escape( $name );\r
1003 \r
1004         // Get the ID, if no ID then return\r
1005         $option = $ydb->get_row( "SELECT option_id FROM `$table` WHERE `option_name` = '$name'" );\r
1006         if ( is_null($option) || !$option->option_id )\r
1007                 return false;\r
1008                 \r
1009         yourls_do_action( 'delete_option', $option_name );\r
1010                 \r
1011         $ydb->query( "DELETE FROM `$table` WHERE `option_name` = '$name'" );\r
1012         return true;\r
1013 }\r
1014 \r
1015 \r
1016 \r
1017 // Serialize data if needed. Stolen from WordPress\r
1018 function yourls_maybe_serialize( $data ) {\r
1019         if ( is_array( $data ) || is_object( $data ) )\r
1020                 return serialize( $data );\r
1021 \r
1022         if ( yourls_is_serialized( $data ) )\r
1023                 return serialize( $data );\r
1024 \r
1025         return $data;\r
1026 }\r
1027 \r
1028 // Check value to find if it was serialized. Stolen from WordPress\r
1029 function yourls_is_serialized( $data ) {\r
1030         // if it isn't a string, it isn't serialized\r
1031         if ( !is_string( $data ) )\r
1032                 return false;\r
1033         $data = trim( $data );\r
1034         if ( 'N;' == $data )\r
1035                 return true;\r
1036         if ( !preg_match( '/^([adObis]):/', $data, $badions ) )\r
1037                 return false;\r
1038         switch ( $badions[1] ) {\r
1039                 case 'a' :\r
1040                 case 'O' :\r
1041                 case 's' :\r
1042                         if ( preg_match( "/^{$badions[1]}:[0-9]+:.*[;}]\$/s", $data ) )\r
1043                                 return true;\r
1044                         break;\r
1045                 case 'b' :\r
1046                 case 'i' :\r
1047                 case 'd' :\r
1048                         if ( preg_match( "/^{$badions[1]}:[0-9.E-]+;\$/", $data ) )\r
1049                                 return true;\r
1050                         break;\r
1051         }\r
1052         return false;\r
1053 }\r
1054 \r
1055 // Unserialize value only if it was serialized. Stolen from WP\r
1056 function yourls_maybe_unserialize( $original ) {\r
1057         if ( yourls_is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in\r
1058                 return @unserialize( $original );\r
1059         return $original;\r
1060 }\r
1061 \r
1062 // Determine if the current page is private\r
1063 function yourls_is_private() {\r
1064         $private = false;\r
1065 \r
1066         if ( defined('YOURLS_PRIVATE') && YOURLS_PRIVATE == true ) {\r
1067 \r
1068                 // Allow overruling for particular pages:\r
1069                 \r
1070                 // API\r
1071                 if( yourls_is_API() ) {\r
1072                         if( !defined('YOURLS_PRIVATE_API') || YOURLS_PRIVATE_API != false )\r
1073                                 $private = true;                \r
1074 \r
1075                 // Infos\r
1076                 } elseif( yourls_is_infos() ) {\r
1077                         if( !defined('YOURLS_PRIVATE_INFOS') || YOURLS_PRIVATE_INFOS !== false )\r
1078                                 $private = true;\r
1079                 \r
1080                 // Others\r
1081                 } else {\r
1082                         $private = true;\r
1083                 }\r
1084                 \r
1085         }\r
1086                         \r
1087         return yourls_apply_filter( 'is_private', $private );\r
1088 }\r
1089 \r
1090 // Show login form if required\r
1091 function yourls_maybe_require_auth() {\r
1092         if( yourls_is_private() )\r
1093                 require_once( YOURLS_INC.'/auth.php' );\r
1094 }\r
1095 \r
1096 // Allow several short URLs for the same long URL ?\r
1097 function yourls_allow_duplicate_longurls() {\r
1098         // special treatment if API to check for WordPress plugin requests\r
1099         if( yourls_is_API() ) {\r
1100                 if ( isset($_REQUEST['source']) && $_REQUEST['source'] == 'plugin' ) \r
1101                         return false;\r
1102         }\r
1103         return ( defined( 'YOURLS_UNIQUE_URLS' ) && YOURLS_UNIQUE_URLS == false );\r
1104 }\r
1105 \r
1106 // Return list of all shorturls associated to the same long URL. Returns NULL or array of keywords.\r
1107 function yourls_get_duplicate_keywords( $longurl ) {\r
1108         if( !yourls_allow_duplicate_longurls() )\r
1109                 return NULL;\r
1110         \r
1111         global $ydb;\r
1112         $longurl = yourls_escape( yourls_sanitize_url($longurl) );\r
1113         $table = YOURLS_DB_TABLE_URL;\r
1114         \r
1115         $return = $ydb->get_col( "SELECT `keyword` FROM `$table` WHERE `url` = '$longurl'" );\r
1116         return yourls_apply_filter( 'get_duplicate_keywords', $return, $longurl );\r
1117 }\r
1118 \r
1119 // Check if an IP shortens URL too fast to prevent DB flood. Return true, or die.\r
1120 function yourls_check_IP_flood( $ip = '' ) {\r
1121 \r
1122         // Allow plugins to short-circuit the whole function\r
1123         $pre = yourls_apply_filter( 'shunt_check_IP_flood', false, $ip );\r
1124         if ( false !== $pre )\r
1125                 return $pre;\r
1126 \r
1127         yourls_do_action( 'pre_check_ip_flood', $ip ); // at this point $ip can be '', check it if your plugin hooks in here\r
1128 \r
1129         if(\r
1130                 ( defined('YOURLS_FLOOD_DELAY_SECONDS') && YOURLS_FLOOD_DELAY_SECONDS === 0 ) ||\r
1131                 !defined('YOURLS_FLOOD_DELAY_SECONDS')\r
1132         )\r
1133                 return true;\r
1134 \r
1135         $ip = ( $ip ? yourls_sanitize_ip( $ip ) : yourls_get_IP() );\r
1136 \r
1137         // Don't throttle whitelist IPs\r
1138         if( defined('YOURLS_FLOOD_IP_WHITELIST' && YOURLS_FLOOD_IP_WHITELIST ) ) {\r
1139                 $whitelist_ips = explode( ',', YOURLS_FLOOD_IP_WHITELIST );\r
1140                 foreach( (array)$whitelist_ips as $whitelist_ip ) {\r
1141                         $whitelist_ip = trim( $whitelist_ip );\r
1142                         if ( $whitelist_ip == $ip )\r
1143                                 return true;\r
1144                 }\r
1145         }\r
1146         \r
1147         // Don't throttle logged in users\r
1148         if( yourls_is_private() ) {\r
1149                  if( yourls_is_valid_user() === true )\r
1150                         return true;\r
1151         }\r
1152         \r
1153         yourls_do_action( 'check_ip_flood', $ip );\r
1154         \r
1155         global $ydb;\r
1156         $table = YOURLS_DB_TABLE_URL;\r
1157         \r
1158         $lasttime = $ydb->get_var( "SELECT `timestamp` FROM $table WHERE `ip` = '$ip' ORDER BY `timestamp` DESC LIMIT 1" );\r
1159         if( $lasttime ) {\r
1160                 $now = date( 'U' );\r
1161                 $then = date( 'U', strtotime( $lasttime ) );\r
1162                 if( ( $now - $then ) <= YOURLS_FLOOD_DELAY_SECONDS ) {\r
1163                         // Flood!\r
1164                         yourls_do_action( 'ip_flood', $ip, $now - $then );\r
1165                         yourls_die( 'Too many URLs added too fast. Slow down please.', 'Forbidden', 403 );\r
1166                 }\r
1167         }\r
1168         \r
1169         return true;\r
1170 }\r
1171 \r
1172 // Check if YOURLS is installed\r
1173 function yourls_is_installed() {\r
1174         static $is_installed = false;\r
1175         if ( $is_installed === false ) {\r
1176                 $check_14 = $check_13 = false;\r
1177                 global $ydb;\r
1178                 if( defined('YOURLS_DB_TABLE_NEXTDEC') )\r
1179                         $check_13 = $ydb->get_var('SELECT `next_id` FROM '.YOURLS_DB_TABLE_NEXTDEC);\r
1180                 $check_14 = yourls_get_option( 'version' );\r
1181                 $is_installed = $check_13 || $check_14;\r
1182         }\r
1183         return yourls_apply_filter( 'is_installed', $is_installed );\r
1184 }\r
1185 \r
1186 // Generate random string of (int)$length length and type $type (see function for details)\r
1187 function yourls_rnd_string ( $length = 5, $type = 0, $charlist = '' ) {\r
1188         $str = '';\r
1189         $length = intval( $length );\r
1190 \r
1191         // define possible characters\r
1192         switch ( $type ) {\r
1193 \r
1194                 // custom char list, or comply to charset as defined in config\r
1195                 case '0':\r
1196                         $possible = $charlist ? $charlist : yourls_get_shorturl_charset() ;\r
1197                         break;\r
1198         \r
1199                 // no vowels to make no offending word, no 0/1/o/l to avoid confusion between letters & digits. Perfect for passwords.\r
1200                 case '1':\r
1201                         $possible = "23456789bcdfghjkmnpqrstvwxyz";\r
1202                         break;\r
1203                 \r
1204                 // Same, with lower + upper\r
1205                 case '2':\r
1206                         $possible = "23456789bcdfghjkmnpqrstvwxyzBCDFGHJKMNPQRSTVWXYZ";\r
1207                         break;\r
1208                 \r
1209                 // all letters, lowercase\r
1210                 case '3':\r
1211                         $possible = "abcdefghijklmnopqrstuvwxyz";\r
1212                         break;\r
1213                 \r
1214                 // all letters, lowercase + uppercase\r
1215                 case '4':\r
1216                         $possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";\r
1217                         break;\r
1218                 \r
1219                 // all digits & letters lowercase \r
1220                 case '5':\r
1221                         $possible = "0123456789abcdefghijklmnopqrstuvwxyz";\r
1222                         break;\r
1223                 \r
1224                 // all digits & letters lowercase + uppercase\r
1225                 case '6':\r
1226                         $possible = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";\r
1227                         break;\r
1228                 \r
1229         }\r
1230 \r
1231         $i = 0;\r
1232         while ($i < $length) {\r
1233                 $str .= substr($possible, mt_rand(0, strlen($possible)-1), 1);\r
1234                 $i++;\r
1235         }\r
1236         \r
1237         return yourls_apply_filter( 'rnd_string', $str, $length, $type, $charlist );\r
1238 }\r
1239 \r
1240 // Return salted string\r
1241 function yourls_salt( $string ) {\r
1242         $salt = defined('YOURLS_COOKIEKEY') ? YOURLS_COOKIEKEY : md5(__FILE__) ;\r
1243         return yourls_apply_filter( 'yourls_salt', md5 ($string . $salt), $string );\r
1244 }\r
1245 \r
1246 // Add a query var to a URL and return URL. Completely stolen from WP.\r
1247 // Works with one of these parameter patterns:\r
1248 //     array( 'var' => 'value' )\r
1249 //     array( 'var' => 'value' ), $url\r
1250 //     'var', 'value'\r
1251 //     'var', 'value', $url\r
1252 // If $url ommited, uses $_SERVER['REQUEST_URI']\r
1253 function yourls_add_query_arg() {\r
1254         $ret = '';\r
1255         if ( is_array( func_get_arg(0) ) ) {\r
1256                 if ( @func_num_args() < 2 || false === @func_get_arg( 1 ) )\r
1257                         $uri = $_SERVER['REQUEST_URI'];\r
1258                 else\r
1259                         $uri = @func_get_arg( 1 );\r
1260         } else {\r
1261                 if ( @func_num_args() < 3 || false === @func_get_arg( 2 ) )\r
1262                         $uri = $_SERVER['REQUEST_URI'];\r
1263                 else\r
1264                         $uri = @func_get_arg( 2 );\r
1265         }\r
1266         \r
1267         $uri = str_replace( '&amp;', '&', $uri );\r
1268 \r
1269         \r
1270         if ( $frag = strstr( $uri, '#' ) )\r
1271                 $uri = substr( $uri, 0, -strlen( $frag ) );\r
1272         else\r
1273                 $frag = '';\r
1274 \r
1275         if ( preg_match( '|^https?://|i', $uri, $matches ) ) {\r
1276                 $protocol = $matches[0];\r
1277                 $uri = substr( $uri, strlen( $protocol ) );\r
1278         } else {\r
1279                 $protocol = '';\r
1280         }\r
1281 \r
1282         if ( strpos( $uri, '?' ) !== false ) {\r
1283                 $parts = explode( '?', $uri, 2 );\r
1284                 if ( 1 == count( $parts ) ) {\r
1285                         $base = '?';\r
1286                         $query = $parts[0];\r
1287                 } else {\r
1288                         $base = $parts[0] . '?';\r
1289                         $query = $parts[1];\r
1290                 }\r
1291         } elseif ( !empty( $protocol ) || strpos( $uri, '=' ) === false ) {\r
1292                 $base = $uri . '?';\r
1293                 $query = '';\r
1294         } else {\r
1295                 $base = '';\r
1296                 $query = $uri;\r
1297         }\r
1298 \r
1299         parse_str( $query, $qs );\r
1300         $qs = yourls_urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string\r
1301         if ( is_array( func_get_arg( 0 ) ) ) {\r
1302                 $kayvees = func_get_arg( 0 );\r
1303                 $qs = array_merge( $qs, $kayvees );\r
1304         } else {\r
1305                 $qs[func_get_arg( 0 )] = func_get_arg( 1 );\r
1306         }\r
1307 \r
1308         foreach ( (array) $qs as $k => $v ) {\r
1309                 if ( $v === false )\r
1310                         unset( $qs[$k] );\r
1311         }\r
1312 \r
1313         $ret = http_build_query( $qs );\r
1314         $ret = trim( $ret, '?' );\r
1315         $ret = preg_replace( '#=(&|$)#', '$1', $ret );\r
1316         $ret = $protocol . $base . $ret . $frag;\r
1317         $ret = rtrim( $ret, '?' );\r
1318         return $ret;\r
1319 }\r
1320 \r
1321 // Navigates through an array and encodes the values to be used in a URL. Stolen from WP, used in yourls_add_query_arg()\r
1322 function yourls_urlencode_deep($value) {\r
1323         $value = is_array($value) ? array_map('yourls_urlencode_deep', $value) : urlencode($value);\r
1324         return $value;\r
1325 }\r
1326 \r
1327 // Remove arg from query. Opposite of yourls_add_query_arg. Stolen from WP.\r
1328 function yourls_remove_query_arg( $key, $query = false ) {\r
1329         if ( is_array( $key ) ) { // removing multiple keys\r
1330                 foreach ( $key as $k )\r
1331                         $query = yourls_add_query_arg( $k, false, $query );\r
1332                 return $query;\r
1333         }\r
1334         return yourls_add_query_arg( $key, false, $query );\r
1335 }\r
1336 \r
1337 // Return a time-dependent string for nonce creation\r
1338 function yourls_tick() {\r
1339         return ceil( time() / YOURLS_NONCE_LIFE );\r
1340 }\r
1341 \r
1342 // Create a time limited, action limited and user limited token\r
1343 function yourls_create_nonce( $action, $user = false ) {\r
1344         if( false == $user )\r
1345                 $user = defined('YOURLS_USER') ? YOURLS_USER : '-1';\r
1346         $tick = yourls_tick();\r
1347         return substr( yourls_salt($tick . $action . $user), 0, 10 );\r
1348 }\r
1349 \r
1350 // Create a nonce field for inclusion into a form\r
1351 function yourls_nonce_field( $action, $name = 'nonce', $user = false, $echo = true ) {\r
1352         $field = '<input type="hidden" id="'.$name.'" name="'.$name.'" value="'.yourls_create_nonce( $action, $user ).'" />';\r
1353         if( $echo )\r
1354                 echo $field."\n";\r
1355         return $field;\r
1356 }\r
1357 \r
1358 // Add a nonce to a URL. If URL omitted, adds nonce to current URL\r
1359 function yourls_nonce_url( $action, $url = false, $name = 'nonce', $user = false ) {\r
1360         $nonce = yourls_create_nonce( $action, $user );\r
1361         return yourls_add_query_arg( $name, $nonce, $url );\r
1362 }\r
1363 \r
1364 // Check validity of a nonce (ie time span, user and action match).\r
1365 // Returns true if valid, dies otherwise (yourls_die() or die($return) if defined)\r
1366 // if $nonce is false or unspecified, it will use $_REQUEST['nonce']\r
1367 function yourls_verify_nonce( $action, $nonce = false, $user = false, $return = '' ) {\r
1368         // get user\r
1369         if( false == $user )\r
1370                 $user = defined('YOURLS_USER') ? YOURLS_USER : '-1';\r
1371                 \r
1372         // get current nonce value\r
1373         if( false == $nonce && isset( $_REQUEST['nonce'] ) )\r
1374                 $nonce = $_REQUEST['nonce'];\r
1375 \r
1376         // what nonce should be\r
1377         $valid = yourls_create_nonce( $action, $user );\r
1378         \r
1379         if( $nonce == $valid ) {\r
1380                 return true;\r
1381         } else {\r
1382                 if( $return )\r
1383                         die( $return );\r
1384                 yourls_die( 'Unauthorized action or expired link', 'Error', 403 );\r
1385         }\r
1386 }\r
1387 \r
1388 // Converts keyword into short link (prepend with YOURLS base URL)\r
1389 function yourls_link( $keyword = '' ) {\r
1390         $link = YOURLS_SITE . '/' . yourls_sanitize_keyword( $keyword );\r
1391         return yourls_apply_filter( 'yourls_link', $link, $keyword );\r
1392 }\r
1393 \r
1394 // Converts keyword into stat link (prepend with YOURLS base URL, append +)\r
1395 function yourls_statlink( $keyword = '' ) {\r
1396         $link = YOURLS_SITE . '/' . yourls_sanitize_keyword( $keyword ) . '+';\r
1397         return yourls_apply_filter( 'yourls_statlink', $link, $keyword );\r
1398 }\r
1399 \r
1400 // Check if we're in API mode. Returns bool\r
1401 function yourls_is_API() {\r
1402         if ( defined('YOURLS_API') && YOURLS_API == true )\r
1403                 return true;\r
1404         return false;\r
1405 }\r
1406 \r
1407 // Check if we're in Ajax mode. Returns bool\r
1408 function yourls_is_Ajax() {\r
1409         if ( defined('YOURLS_AJAX') && YOURLS_AJAX == true )\r
1410                 return true;\r
1411         return false;\r
1412 }\r
1413 \r
1414 // Check if we're in GO mode (yourls-go.php). Returns bool\r
1415 function yourls_is_GO() {\r
1416         if ( defined('YOURLS_GO') && YOURLS_GO == true )\r
1417                 return true;\r
1418         return false;\r
1419 }\r
1420 \r
1421 // Check if we're displaying stats infos (yourls-infos.php). Returns bool\r
1422 function yourls_is_infos() {\r
1423         if ( defined('YOURLS_INFOS') && YOURLS_INFOS == true )\r
1424                 return true;\r
1425         return false;\r
1426 }\r
1427 \r
1428 // Check if we'll need interface display function (ie not API or redirection)\r
1429 function yourls_has_interface() {\r
1430         if( yourls_is_API() or yourls_is_GO() )\r
1431                 return false;\r
1432         return true;\r
1433 }\r
1434 \r
1435 // Check if we're in the admin area. Returns bool\r
1436 function yourls_is_admin() {\r
1437         if ( defined('YOURLS_ADMIN') && YOURLS_ADMIN == true )\r
1438                 return true;\r
1439         return false;\r
1440 }\r
1441 \r
1442 // Check if the server seems to be running on Windows. Not exactly sure how reliable this is.\r
1443 function yourls_is_windows() {\r
1444         return defined( 'DIRECTORY_SEPARATOR' ) && DIRECTORY_SEPARATOR == '\\';\r
1445 }\r
1446 \r
1447 // Check if SSL is required. Returns bool.\r
1448 function yourls_needs_ssl() {\r
1449         if ( defined('YOURLS_ADMIN_SSL') && YOURLS_ADMIN_SSL == true )\r
1450                 return true;\r
1451         return false;\r
1452 }\r
1453 \r
1454 // Return admin link, with SSL preference if applicable.\r
1455 function yourls_admin_url( $page = '' ) {\r
1456         $admin = YOURLS_SITE . '/admin/' . $page;\r
1457         if( yourls_is_ssl() or yourls_needs_ssl() )\r
1458                 $admin = str_replace('http://', 'https://', $admin);\r
1459         return yourls_apply_filter( 'admin_url', $admin, $page );\r
1460 }\r
1461 \r
1462 // Return YOURLS_SITE, with SSL preference\r
1463 function yourls_site_url( $echo = true ) {\r
1464         $site = YOURLS_SITE;\r
1465         // Do not enforce (checking yourls_need_ssl() ) but check current usage so it won't force SSL on non-admin pages\r
1466         if( yourls_is_ssl() )\r
1467                 $site = str_replace( 'http://', 'https://', $site );\r
1468         $site = yourls_apply_filter( 'site_url', $site );\r
1469         if( $echo )\r
1470                 echo $site;\r
1471         return $site;\r
1472 }\r
1473 \r
1474 // Check if SSL is used, returns bool. Stolen from WP.\r
1475 function yourls_is_ssl() {\r
1476         $is_ssl = false;\r
1477         if ( isset($_SERVER['HTTPS']) ) {\r
1478                 if ( 'on' == strtolower($_SERVER['HTTPS']) )\r
1479                         $is_ssl = true;\r
1480                 if ( '1' == $_SERVER['HTTPS'] )\r
1481                         $is_ssl = true;\r
1482         } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {\r
1483                 $is_ssl = true;\r
1484         }\r
1485         return yourls_apply_filter( 'is_ssl', $is_ssl );\r
1486 }\r
1487 \r
1488 \r
1489 // Get a remote page <title>, return a string (either title or url)\r
1490 function yourls_get_remote_title( $url ) {\r
1491         // Allow plugins to short-circuit the whole function\r
1492         $pre = yourls_apply_filter( 'shunt_get_remote_title', false, $url );\r
1493         if ( false !== $pre )\r
1494                 return $pre;\r
1495 \r
1496         require_once( YOURLS_INC.'/functions-http.php' );\r
1497 \r
1498         $url = yourls_sanitize_url( $url );\r
1499 \r
1500         $title = $charset = false;\r
1501         \r
1502         $content = yourls_get_remote_content( $url );\r
1503         \r
1504         // If false, return url as title.\r
1505         // Todo: improve this with temporary title when shorturl_meta available?\r
1506         if( false === $content )\r
1507                 return $url;\r
1508 \r
1509         if( $content !== false ) {\r
1510                 // look for <title>\r
1511                 if ( preg_match('/<title>(.*?)<\/title>/is', $content, $found ) ) {\r
1512                         $title = $found[1];\r
1513                         unset( $found );\r
1514                 }\r
1515 \r
1516                 // look for charset\r
1517                 // <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\r
1518                 if ( preg_match('/<meta[^>]*?charset=([^>]*?)\/?>/is', $content, $found ) ) {\r
1519                         $charset = trim($found[1], '"\' ');\r
1520                         unset( $found );\r
1521                 }\r
1522         }\r
1523         \r
1524         // if title not found, guess if returned content was actually an error message\r
1525         if( $title == false && strpos( $content, 'Error' ) === 0 ) {\r
1526                 $title = $content;\r
1527         }\r
1528         \r
1529         if( $title == false )\r
1530                 $title = $url;\r
1531         \r
1532         /*\r
1533         if( !yourls_seems_utf8( $title ) )\r
1534                 $title = utf8_encode( $title );\r
1535         */\r
1536         \r
1537         // Charset conversion. We use @ to remove warnings (mb_ functions are easily bitching about illegal chars)\r
1538         if( function_exists( 'mb_convert_encoding' ) ) {\r
1539                 if( $charset ) {\r
1540                         $title = @mb_convert_encoding( $title, 'UTF-8', $charset );\r
1541                 } else {\r
1542                         $title = @mb_convert_encoding( $title, 'UTF-8' );\r
1543                 }\r
1544         }\r
1545         \r
1546         // Remove HTML entities\r
1547         $title = html_entity_decode( $title, ENT_QUOTES, 'UTF-8' );\r
1548         \r
1549         // Strip out evil things\r
1550         $title = yourls_sanitize_title( $title );\r
1551         \r
1552         return yourls_apply_filter( 'get_remote_title', $title, $url );\r
1553 }\r
1554 \r
1555 // Check for maintenance mode that will shortcut everything\r
1556 function yourls_check_maintenance_mode() {\r
1557         \r
1558         // TODO: all cases that always display the sites (is_admin but not is_ajax?)\r
1559         if( 1 )\r
1560                 return;\r
1561 \r
1562         // first case: /user/maintenance.php file\r
1563         if( file_exists( YOURLS_USERDIR.'/maintenance.php' ) ) {\r
1564                 include( YOURLS_USERDIR.'/maintenance.php' );\r
1565                 die();  \r
1566         }\r
1567         \r
1568         // second case: option in DB\r
1569         if( yourls_get_option( 'maintenance_mode' ) !== false ) {\r
1570                 require_once( YOURLS_INC.'/functions-html.php' );\r
1571                 $title = 'Service temporarily unavailable';\r
1572                 $message = 'Our service is currently undergoing scheduled maintenance.</p>\r
1573                 <p>Things should not last very long, thank you for your patience and please excuse the inconvenience';\r
1574                 yourls_die( $message, $title , 503 );\r
1575         }\r
1576         \r
1577 }\r
1578 \r
1579 // Toggle maintenance mode\r
1580 function yourls_maintenance_mode( $maintenance = true ) {\r
1581         yourls_update_option( 'maintenance_mode', (bool)$maintenance );\r
1582 }\r
1583 \r
1584 // Quick UA check for mobile devices. Return boolean.\r
1585 function yourls_is_mobile_device() {\r
1586         // Strings searched\r
1587         $mobiles = array(\r
1588                 'android', 'blackberry', 'blazer',\r
1589                 'compal', 'elaine', 'fennec', 'hiptop',\r
1590                 'iemobile', 'iphone', 'ipod', 'ipad',\r
1591                 'iris', 'kindle', 'opera mobi', 'opera mini',\r
1592                 'palm', 'phone', 'pocket', 'psp', 'symbian',\r
1593                 'treo', 'wap', 'windows ce', 'windows phone'\r
1594         );\r
1595         \r
1596         // Current user-agent\r
1597         $current = strtolower( $_SERVER['HTTP_USER_AGENT'] );\r
1598         \r
1599         // Check and return\r
1600         $is_mobile = ( str_replace( $mobiles, '', $current ) != $current );\r
1601         return yourls_apply_filter( 'is_mobile_device', $is_mobile );\r
1602 }\r
1603 \r
1604 // Get request in YOURLS base (eg in 'http://site.com/yourls/abcd' get 'abdc')\r
1605 function yourls_get_request() {\r
1606         // Allow plugins to short-circuit the whole function\r
1607         $pre = yourls_apply_filter( 'shunt_get_request', false );\r
1608         if ( false !== $pre )\r
1609                 return $pre;\r
1610                 \r
1611         yourls_do_action( 'pre_get_request' );\r
1612         \r
1613         // Ignore protocol, www. prefix and extract keyword\r
1614         $base = str_replace( array( 'https://', 'http://', 'https://www.', 'http://www.' ), '', YOURLS_SITE );\r
1615         $request = str_replace( $base.'/', '', $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );\r
1616         \r
1617         // Strip query string from keyword\r
1618         $request = current( explode( '?', $request ) );\r
1619         \r
1620         return yourls_apply_filter( 'get_request', $request );\r
1621 }\r
1622 \r
1623 // Change protocol to match current scheme used (http or https)\r
1624 function yourls_match_current_protocol( $url, $normal = 'http', $ssl = 'https' ) {\r
1625         if( yourls_is_ssl() )\r
1626                 $url = str_replace( $normal, $ssl, $url );\r
1627         return yourls_apply_filter( 'match_current_protocol', $url );\r
1628 }\r
1629 \r
1630 // Fix $_SERVER['REQUEST_URI'] variable for various setups. Stolen from WP.\r
1631 function yourls_fix_request_uri() {\r
1632 \r
1633         $default_server_values = array(\r
1634                 'SERVER_SOFTWARE' => '',\r
1635                 'REQUEST_URI' => '',\r
1636         );\r
1637         $_SERVER = array_merge( $default_server_values, $_SERVER );\r
1638 \r
1639         // Fix for IIS when running with PHP ISAPI\r
1640         if ( empty( $_SERVER['REQUEST_URI'] ) || ( php_sapi_name() != 'cgi-fcgi' && preg_match( '/^Microsoft-IIS\//', $_SERVER['SERVER_SOFTWARE'] ) ) ) {\r
1641 \r
1642                 // IIS Mod-Rewrite\r
1643                 if ( isset( $_SERVER['HTTP_X_ORIGINAL_URL'] ) ) {\r
1644                         $_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_ORIGINAL_URL'];\r
1645                 }\r
1646                 // IIS Isapi_Rewrite\r
1647                 else if ( isset( $_SERVER['HTTP_X_REWRITE_URL'] ) ) {\r
1648                         $_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_REWRITE_URL'];\r
1649                 } else {\r
1650                         // Use ORIG_PATH_INFO if there is no PATH_INFO\r
1651                         if ( !isset( $_SERVER['PATH_INFO'] ) && isset( $_SERVER['ORIG_PATH_INFO'] ) )\r
1652                                 $_SERVER['PATH_INFO'] = $_SERVER['ORIG_PATH_INFO'];\r
1653 \r
1654                         // Some IIS + PHP configurations puts the script-name in the path-info (No need to append it twice)\r
1655                         if ( isset( $_SERVER['PATH_INFO'] ) ) {\r
1656                                 if ( $_SERVER['PATH_INFO'] == $_SERVER['SCRIPT_NAME'] )\r
1657                                         $_SERVER['REQUEST_URI'] = $_SERVER['PATH_INFO'];\r
1658                                 else\r
1659                                         $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];\r
1660                         }\r
1661 \r
1662                         // Append the query string if it exists and isn't null\r
1663                         if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {\r
1664                                 $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];\r
1665                         }\r
1666                 }\r
1667         }\r
1668 }\r
1669 \r
1670 // Shutdown function, runs just before PHP shuts down execution. Stolen from WP\r
1671 function yourls_shutdown() {\r
1672         yourls_do_action( 'shutdown' );\r
1673 }