]> CyberLeo.Net >> Repos - Github/YOURLS.git/blob - includes/functions.php
Allow https://
[Github/YOURLS.git] / includes / functions.php
1 <?php\r
2 /*\r
3  * YOURLS\r
4  * Function library\r
5  */\r
6  \r
7 // Bump this when updating the SVN repo\r
8 define('YOURLS_VERSION', '1.1');\r
9 \r
10 // function to convert an integer (1337) to a string (3jk). Input integer processed as a string to beat PHP's int max value\r
11 function yourls_int2string( $id ) {\r
12         $str = yourls_base2base(trim(strval($id)), 10, YOURLS_URL_CONVERT);\r
13         if (YOURLS_URL_CONVERT <= 37)\r
14                 $str = strtolower($str);\r
15         return $str;\r
16 }\r
17 \r
18 // function to convert a string (3jk) to an integer (1337)\r
19 function yourls_string2int( $str ) {\r
20         if (YOURLS_URL_CONVERT <= 37)\r
21                 $str = strtolower($str);\r
22         return yourls_base2base(trim($str), YOURLS_URL_CONVERT, 10);\r
23 }\r
24 \r
25 // Make sure a link id (site.com/1fv) is valid.\r
26 function yourls_sanitize_string ($in) {\r
27         if (YOURLS_URL_CONVERT <= 37)\r
28                 $in = strtolower($in);\r
29         return substr(preg_replace('/[^a-zA-Z0-9]/', '', $in), 0, 12);\r
30 }\r
31 \r
32 // make sure there's one and only one 'http://' at the beginning (prevents omitting or pasting a URL right after the default 'http://')\r
33 function yourls_sanitize_url($url) {\r
34         if(substr($url, 0, 5) == 'https') {\r
35                 return preg_replace('#^(https://)+#', 'https://', 'https://'.$url);\r
36         } else {\r
37                 return preg_replace('#^(http://)+#', 'http://', 'http://'.$url);\r
38         }\r
39 }\r
40 \r
41 // Make sure an id link is a valid integer (PHP's intval() limits to too small numbers)\r
42 function yourls_sanitize_int($in) {\r
43         return ( substr(preg_replace('/[^0-9]/', '', strval($in) ), 0, 20) );\r
44 }\r
45 \r
46 // Make sure a integer is safe\r
47 // Note: this is not checking for integers, since integers on 32bits system are way too limited\r
48 // TODO: find a way to validate as integer\r
49 function yourls_intval($in) {\r
50         return mysql_real_escape_string($in);\r
51 }\r
52 \r
53 \r
54 // Check to see if a given integer id is reserved (ie reserved URL or an existing page)\r
55 // Returns bool\r
56 function yourls_is_reserved_id($id) {\r
57         global $yourls_reserved_URL;\r
58         $keyword = yourls_int2string( yourls_intval($id) );\r
59         if ( in_array( $keyword, $yourls_reserved_URL)\r
60                 or file_exists(dirname(dirname(__FILE__))."/pages/$keyword.php")\r
61                 or is_dir(dirname(dirname(__FILE__))."$keyword")\r
62         )\r
63                 return true;\r
64         \r
65         return false;\r
66 }\r
67 \r
68 // Function: Get IP Address\r
69 function yourls_get_IP() {\r
70         if(!empty($_SERVER['HTTP_CLIENT_IP'])) {\r
71                 $ip_address = $_SERVER['HTTP_CLIENT_IP'];\r
72         } else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {\r
73                 $ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];\r
74         } else if(!empty($_SERVER['REMOTE_ADDR'])) {\r
75                 $ip_address = $_SERVER['REMOTE_ADDR'];\r
76         } else {\r
77                 $ip_address = '';\r
78         }\r
79         if(strpos($ip_address, ',') !== false) {\r
80                 $ip_address = explode(',', $ip_address);\r
81                 $ip_address = $ip_address[0];\r
82         }\r
83         return $ip_address;\r
84 }\r
85 \r
86 // Add the "Edit" row\r
87 function yourls_table_edit_row($id, $db) {\r
88         $id = yourls_intval($id);\r
89         $table = YOURLS_DB_TABLE_URL;\r
90         $url = $db->get_row("SELECT `url` FROM `$table` WHERE `id` = '$id';");\r
91         $safe_url = stripslashes($url->url);\r
92         $keyword = yourls_int2string($id);\r
93         if($url) {\r
94                 $return = <<<RETURN\r
95                 <tr id="edit-$id" class="edit-row">\r
96                 <td colspan="6">Edit: <strong>original URL</strong>:<input type="text" id="edit-url-$id" name="edit-url-$id" value="$safe_url" class="text" size="100" />\r
97                         <strong>short URL</strong>:<input type="text" id="edit-id-$id" name="edit-id-$id" value="$keyword" class="text" size="10" />\r
98                 </td>\r
99                 <td colspan="1"><input type="button" id="edit-submit-$id" name="edit-submit-$id" value="Save" title="Save new values" class="button" onclick="edit_save('$id');" />&nbsp;<input type="button" id="edit-close-$id" name="edit-close-$id" value="X" title="Cancel editing" class="button" onclick="hide_edit('$id');" /></td>\r
100                 </tr>\r
101 RETURN;\r
102         } else {\r
103                 $return = '<tr><td colspan="7">Invalid URL ID</td></tr>';\r
104         }\r
105         \r
106         return $return;\r
107 }\r
108 \r
109 // Add a link row\r
110 function yourls_table_add_row( $id, $keyword, $url, $ip, $clicks, $timestamp ) {\r
111         $date = date( 'M d, Y H:i', $timestamp+( yourls_HOURS_OFFSET * 3600) );\r
112         $clicks = number_format($clicks);\r
113         $www = YOURLS_SITE;\r
114         \r
115         return <<<ROW\r
116         <tr id="id-$id">\r
117                 <td id="keyword-$id">$keyword</td>\r
118                 <td id="url-$id"><a href="$url" title="$url">$url</a></td>\r
119                 <td id="shorturl-$id"><a href="$www/$keyword" title="$www/$keyword">$www/$keyword</a></td>\r
120                 <td id="timestamp-$id">$date</td>\r
121                 <td>$ip</td>\r
122                 <td>$clicks</td>\r
123                 <td class="actions">\r
124                 <input type="button" id="edit-button-$id" name="edit-button" value="Edit" class="button" onclick="edit('$id');" />&nbsp;<input type="button" id="delete-button-$id" name="delete-button" value="Del" class="button" onclick="remove('$id');" />\r
125                 </td>\r
126         </tr>\r
127 ROW;\r
128 }\r
129 \r
130 // Get next id a new link will have if no custom keyword provided\r
131 function yourls_get_next_decimal($db) {\r
132         $table = YOURLS_DB_TABLE_NEXTDEC;\r
133         return $db->get_var("SELECT `next_id` FROM `$table`");\r
134 }\r
135 \r
136 // Update id for next link with no custom keyword\r
137 function yourls_update_next_decimal($int = '', $db) {\r
138         $int = ( $int == '' ) ? 'next+1' : (int)$int ;\r
139         $table = YOURLS_DB_TABLE_NEXTDEC;\r
140         return $db->query("UPDATE `$table` set next_id=$int");\r
141 }\r
142 \r
143 // Delete a link in the DB\r
144 function yourls_delete_link_by_id($id, $db) {\r
145         $table = YOURLS_DB_TABLE_URL;\r
146         $id = yourls_intval($id);\r
147         return $db->query("DELETE FROM `$table` WHERE `id` = $id;");\r
148 }\r
149 \r
150 // SQL query to insert a new link in the DB. Needs sanitized data. Returns boolean for success or failure of the inserting\r
151 function yourls_insert_link_in_db($url, $id, $db) {\r
152         $table = YOURLS_DB_TABLE_URL;\r
153         $timestamp = date('Y-m-d H:i:s');\r
154         $ip = yourls_get_IP();\r
155         return $db->query("INSERT INTO `$table` VALUES($id, '$url', '$timestamp', '$ip', 0);");\r
156 }\r
157 \r
158 // Add a new link in the DB, either with custom keyword, or find one\r
159 function yourls_add_new_link($url, $keyword = '', $db) {\r
160         if ( !$url || $url == 'http://' || $url == 'https://' ) {\r
161                 $return['status'] = 'fail';\r
162                 $return['message'] = 'Missing URL input';\r
163                 return $return;\r
164         }\r
165 \r
166         $table = YOURLS_DB_TABLE_URL;\r
167         $url = mysql_real_escape_string(yourls_sanitize_url($url));\r
168         $strip_url = stripslashes($url);\r
169         $url_exists = $db->get_row("SELECT id,url FROM `$table` WHERE `url` = '".$strip_url."';");\r
170         $ip = yourls_get_IP();\r
171         $return = array();\r
172 \r
173         // New URL : store it\r
174         if( !$url_exists ) {\r
175 \r
176                 // Custom keyword provided\r
177                 if ($keyword) {\r
178                         $keyword = yourls_sanitize_string($keyword);\r
179                         if (!yourls_keyword_is_free($keyword, $db)) {\r
180                                 // This id either reserved or taken already\r
181                                 $return['status'] = 'fail';\r
182                                 $return['message'] = 'URL id '.$keyword.' already exists in database or is reserved';\r
183                         } else {\r
184                                 // all clear, store !\r
185                                 $id = yourls_string2int($keyword);\r
186                                 yourls_insert_link_in_db($url, $id, $db);\r
187                                 $return['url'] = array('id' => $id, 'keyword' => $keyword, 'url' => $strip_url, 'date' => date('Y-m-d H:i:s'), 'ip' => yourls_get_IP() );\r
188                                 $return['status'] = 'success';\r
189                                 $return['message'] = $strip_url.' (ID: '.$keyword.') added to database';\r
190                                 $return['html'] = yourls_table_add_row( $id, $keyword, $url, yourls_get_IP(), 0, time() );\r
191                                 $return['shorturl'] = YOURLS_SITE .'/'. $keyword;\r
192                         }\r
193 \r
194                 // Create random keyword        \r
195                 } else {\r
196                         $timestamp = date('Y-m-d H:i:s');\r
197                         $id = yourls_get_next_decimal($db);\r
198                         do {\r
199                                 $add_url = @yourls_insert_link_in_db($url, $id, $db);\r
200                                 $free = !yourls_is_reserved_id( $id );\r
201                                 $ok = ($free && $add_url);\r
202                                 if ( $ok === false && $add_url === 1 ) {\r
203                                         // we stored something, but shouldn't have (ie reserved id)\r
204                                         $delete = yourls_delete_link_by_id( $id, $db );\r
205                                         $return['extra_info'] .= '(deleted '.$id.')';\r
206                                 } else {\r
207                                         // everything ok, populate needed vars\r
208                                         $keyword = yourls_int2string($id);\r
209                                         $return['url'] = array('id' => $id, 'keyword' => $keyword, 'url' => $strip_url, 'date' => $timestamp, 'ip' => $ip);\r
210                                         $return['status'] = 'success';\r
211                                         $return['message'] = $strip_url.' (ID: '.$id.') added to database';\r
212                                         $return['html'] = yourls_table_add_row( $id, $keyword, $url, $ip, 0, time() );\r
213                                         $return['shorturl'] = YOURLS_SITE .'/'. $keyword;\r
214                                 }\r
215                                 $id++;\r
216                         } while (!$ok);\r
217                         @yourls_update_next_decimal($id, $db);\r
218                 }\r
219         } else {\r
220                 // URL was already stored\r
221                 $return['status'] = 'fail';\r
222                 $return['message'] = $strip_url.' already exists in database';\r
223                 $return['shorturl'] = YOURLS_SITE .'/'. yourls_int2string( $url_exists->id );\r
224         }\r
225 \r
226         return $return;\r
227 }\r
228 \r
229 \r
230 // Edit a link\r
231 function yourls_edit_link($url, $id, $keyword='', $db) {\r
232         $table = YOURLS_DB_TABLE_URL;\r
233         $url = mysql_real_escape_string(yourls_sanitize_url($url));\r
234         $id = yourls_intval($id);\r
235         $strip_url = stripslashes($url);\r
236         $old_url = $db->get_var("SELECT `url` FROM `$table` WHERE `id` = '".$id."';");\r
237         \r
238         \r
239         // Check if new URL is not here already\r
240         if ($old_url != $url) {\r
241                 $url_exists = intval($db->get_var("SELECT id FROM `$table` WHERE `url` = '".$strip_url."';"));\r
242         } else {\r
243                 $url_exists = false;\r
244         }\r
245         \r
246         // Check if the new keyword is not here already\r
247         $newid = ( $keyword ? yourls_string2int($keyword) : $id );\r
248         if ($newid != $id) {\r
249                 $id_exists = intval($db->get_var("SELECT id FROM `$table` WHERE `id` = '".$newid."';"));\r
250                 $id_free = yourls_keyword_is_free($keyword, $db);\r
251                 $id_is_ok = ($id_exists == 0) && $id_free;\r
252         } else {\r
253                 $id_is_ok = true;\r
254         }\r
255         \r
256         // All clear, update\r
257         if($url_exists == 0 && $id_is_ok ) {\r
258                 $timestamp4screen = date( 'Y M d H:i', time()+( yourls_HOURS_OFFSET * 3600) );\r
259                 $timestamp4db = date('Y-m-d H:i:s', time()+( yourls_HOURS_OFFSET * 3600) );\r
260                 $update_url = $db->query("UPDATE `$table` SET `url` = '$url', `timestamp` = '$timestamp4db', `id` = '$newid' WHERE `id` = $id;");\r
261                 if($update_url) {\r
262                         $return['url'] = array('id' => $newid, 'keyword' => $keyword, 'shorturl' => YOURLS_SITE.'/'.$keyword, 'url' => $strip_url, 'date' => $timestamp4screen);\r
263                         $return['status'] = 'success';\r
264                         $return['message'] = 'Link updated in database';\r
265                 } else {\r
266                         $return['status'] = 'fail';\r
267                         $return['message'] = 'Error updating '.$strip_url.' (ID: '.$id.') to database';\r
268                 }\r
269         \r
270         // Nope\r
271         } else {\r
272                 $return['status'] = 'fail';\r
273                 $return['message'] = 'URL or keyword already exists in database';\r
274         }\r
275         \r
276         return $return;\r
277 }\r
278 \r
279 \r
280 // Check if keyword id is free (ie not already taken, and not reserved)\r
281 function yourls_keyword_is_free($str, $db) {\r
282         $table = YOURLS_DB_TABLE_URL;\r
283         $id = yourls_string2int($str);\r
284         if ( yourls_is_reserved_id($id) )\r
285                 return false;\r
286                 \r
287         $already_exists = intval($db->get_var("SELECT `id` FROM `$table` WHERE `id` = '".$id."';"));\r
288         if ( $already_exists )\r
289                 return false;\r
290 \r
291         return true;\r
292 }\r
293 \r
294 \r
295 // Display a page\r
296 function yourls_page($page) {\r
297         $include = dirname(dirname(__FILE__))."/pages/$page.php";\r
298         if (!file_exists($include)) {\r
299                 die("Page '$page' not found");\r
300         }\r
301         include($include);\r
302         die();  \r
303 }\r
304 \r
305 // Connect to DB\r
306 function yourls_db_connect() {\r
307         if (!defined('YOURLS_DB_USER')\r
308                 or !defined('YOURLS_DB_PASS')\r
309                 or !defined('YOURLS_DB_NAME')\r
310                 or !defined('YOURLS_DB_HOST')\r
311                 or !class_exists('ezSQL_mysql')\r
312         ) die ('DB config/class missing');\r
313         \r
314         return new ezSQL_mysql(YOURLS_DB_USER, YOURLS_DB_PASS, YOURLS_DB_NAME, YOURLS_DB_HOST);\r
315 }\r
316 \r
317 // Return JSON output. Compatible with PHP prior to 5.2\r
318 function yourls_json_encode($array) {\r
319         if (function_exists('json_encode')) {\r
320                 return json_encode($array);\r
321         } else {\r
322                 require_once(dirname(__FILE__).'/functions-json.php');\r
323                 return yourls_array_to_json($array);\r
324         }\r
325 }\r
326 \r
327 // Return XML output.\r
328 function yourls_xml_encode($array) {\r
329         require_once(dirname(__FILE__).'/functions-xml.php');\r
330         $converter= new yourls_array2xml;\r
331         return $converter->array2xml($array);\r
332 }\r
333 \r
334 // Return array for API stat requests\r
335 function yourls_api_stats( $filter, $limit, $db ) {\r
336         switch( $filter ) {\r
337                 case 'bottom':\r
338                         $sort_by = 'clicks';\r
339                         $sort_order = 'asc';\r
340                         break;\r
341                 case 'last':\r
342                         $sort_by = 'timestamp';\r
343                         $sort_order = 'desc';\r
344                         break;\r
345                 case 'top':\r
346                 default:\r
347                         $sort_by = 'clicks';\r
348                         $sort_order = 'desc';\r
349                         break;\r
350         }\r
351         \r
352         $limit = intval( $limit );\r
353         $table_url = YOURLS_DB_TABLE_URL;\r
354         $results = $db->get_results("SELECT * FROM $table_url WHERE 1=1 ORDER BY $sort_by $sort_order LIMIT 0, $limit;");\r
355 \r
356         $return = array();\r
357         $i = 1;\r
358 \r
359         foreach ($results as $res) {\r
360                 $return['links']['link_'.$i++] = array(\r
361                         'shorturl' => YOURLS_SITE .'/'. yourls_int2string($res->id),\r
362                         'url' => $res->url,\r
363                         'timestamp' => $res->timestamp,\r
364                         'ip' => $res->ip,\r
365                         'clicks' => $res->clicks\r
366                 );\r
367         }\r
368 \r
369         $totals = $db->get_row("SELECT COUNT(id) as c, SUM(clicks) as s FROM $table_url WHERE 1=1");\r
370         $return['stats'] = array( 'total_links' => $totals->c, 'total_clicks' => $totals->s );\r
371 \r
372         return $return;\r
373 }\r
374 \r
375 // Return API result. Dies after this\r
376 function yourls_api_output( $mode, $return ) {\r
377         switch ( $mode ) {\r
378                 case 'json':\r
379                         header('Content-type: application/json');\r
380                         echo yourls_json_encode($return);\r
381                         break;\r
382                 \r
383                 case 'xml':\r
384                         header('Content-type: application/xml');\r
385                         echo yourls_xml_encode($return);\r
386                         break;\r
387                         \r
388                 case 'simple':\r
389                 default:\r
390                         echo $return['shorturl'];\r
391                         break;\r
392         }\r
393         die();\r
394 }