7 if (defined('YOURLS_DEBUG') && YOURLS_DEBUG == true) {
\r
8 error_reporting(E_ALL);
\r
10 error_reporting(E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING);
\r
13 // function to convert an integer (1337) to a string (3jk). Input integer processed as a string to beat PHP's int max value
\r
14 function yourls_int2string( $id ) {
\r
15 $str = yourls_base2base(trim(strval($id)), 10, YOURLS_URL_CONVERT);
\r
16 if (YOURLS_URL_CONVERT <= 37)
\r
17 $str = strtolower($str);
\r
21 // function to convert a string (3jk) to an integer (1337)
\r
22 function yourls_string2int( $str ) {
\r
23 if (YOURLS_URL_CONVERT <= 37)
\r
24 $str = strtolower($str);
\r
25 return yourls_base2base(trim($str), YOURLS_URL_CONVERT, 10);
\r
28 // Make sure a link keyword (ie "1fv" as in "site.com/1fv") is valid.
\r
29 function yourls_sanitize_string($in) {
\r
30 if (YOURLS_URL_CONVERT <= 37)
\r
31 $in = strtolower($in);
\r
32 return substr(preg_replace('/[^a-zA-Z0-9]/', '', $in), 0, 199);
\r
35 // A few sanity checks on the URL
\r
36 function yourls_sanitize_url($url) {
\r
37 // make sure there's only one 'http://' at the beginning (prevents pasting a URL right after the default 'http://')
\r
38 $url = str_replace('http://http://', 'http://', $url);
\r
40 // make sure there's a protocol, add http:// if not
\r
41 if ( !preg_match('!^([a-zA-Z]+://)!', $url ) )
\r
42 $url = 'http://'.$url;
\r
44 $url = yourls_clean_url($url);
\r
46 return substr( $url, 0, 199 );
\r
49 // Function to filter all invalid characters from a URL. Stolen from WP's clean_url()
\r
50 function yourls_clean_url( $url ) {
\r
51 $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);
\r
52 $strip = array('%0d', '%0a', '%0D', '%0A');
\r
53 $url = yourls_deep_replace($strip, $url);
\r
54 $url = str_replace(';//', '://', $url);
\r
59 // Perform a replacement while a string is found, eg $subject = '%0%0%0DDD', $search ='%0D' -> $result =''
\r
60 // Stolen from WP's _deep_replace
\r
61 function yourls_deep_replace($search, $subject){
\r
65 foreach( (array) $search as $val ) {
\r
66 while(strpos($subject, $val) !== false) {
\r
68 $subject = str_replace($val, '', $subject);
\r
77 // Make sure an integer is a valid integer (PHP's intval() limits to too small numbers)
\r
78 // TODO FIXME FFS: unused ?
\r
79 function yourls_sanitize_int($in) {
\r
80 return ( substr(preg_replace('/[^0-9]/', '', strval($in) ), 0, 20) );
\r
83 // Make sure a integer is safe
\r
84 // Note: this is not checking for integers, since integers on 32bits system are way too limited
\r
85 // TODO: find a way to validate as integer
\r
86 function yourls_intval($in) {
\r
87 return mysql_real_escape_string($in);
\r
91 function yourls_escape( $in ) {
\r
92 return mysql_real_escape_string($in);
\r
95 // Check to see if a given keyword is reserved (ie reserved URL or an existing page)
\r
97 function yourls_keyword_is_reserved( $keyword ) {
\r
98 global $yourls_reserved_URL;
\r
100 if ( in_array( $keyword, $yourls_reserved_URL)
\r
101 or file_exists(dirname(dirname(__FILE__))."/pages/$keyword.php")
\r
102 or is_dir(dirname(dirname(__FILE__))."$keyword")
\r
109 // Function: Get IP Address. Returns a DB safe string.
\r
110 function yourls_get_IP() {
\r
111 if(!empty($_SERVER['HTTP_CLIENT_IP'])) {
\r
112 $ip_address = $_SERVER['HTTP_CLIENT_IP'];
\r
113 } else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
\r
114 $ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
\r
115 } else if(!empty($_SERVER['REMOTE_ADDR'])) {
\r
116 $ip_address = $_SERVER['REMOTE_ADDR'];
\r
120 if(strpos($ip_address, ',') !== false) {
\r
121 $ip_address = explode(',', $ip_address);
\r
122 $ip_address = $ip_address[0];
\r
125 $ip_address = preg_replace( '/[^0-9a-fA-F:., ]/', '', $ip_address );
\r
127 return $ip_address;
\r
130 // Add the "Edit" row
\r
131 function yourls_table_edit_row( $keyword ) {
\r
134 $table = YOURLS_DB_TABLE_URL;
\r
135 $keyword = yourls_sanitize_string( $keyword );
\r
136 $id = yourls_string2int( $keyword ); // used as HTML #id
\r
137 $url = $ydb->get_row("SELECT `url` FROM `$table` WHERE `keyword` = '$keyword';");
\r
138 $safe_url = stripslashes( $url->url );
\r
139 $www = YOURLS_SITE;
\r
142 $return = <<<RETURN
\r
143 <tr id="edit-$id" class="edit-row"><td colspan="5"><strong>Original URL</strong>:<input type="text" id="edit-url-$id" name="edit-url-$id" value="$safe_url" class="text" size="100" /> <strong>Short URL</strong>: $www/<input type="text" id="edit-keyword-$id" name="edit-keyword-$id" value="$keyword" class="text" size="10" /></td><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');" /> <input type="button" id="edit-close-$id" name="edit-close-$id" value="X" title="Cancel editing" class="button" onclick="hide_edit('$id');" /><input type="hidden" id="old_keyword_$id" value="$keyword"/></td></tr>
\r
146 $return = '<tr><td colspan="6">Error, URL not found</td></tr>';
\r
153 function yourls_table_add_row( $keyword, $url, $ip, $clicks, $timestamp ) {
\r
154 $keyword = yourls_sanitize_string( $keyword );
\r
155 $id = yourls_string2int( $keyword ); // used as HTML #id
\r
156 $date = date( 'M d, Y H:i', $timestamp+( YOURLS_HOURS_OFFSET * 3600) );
\r
157 $clicks = number_format($clicks);
\r
158 $www = YOURLS_SITE;
\r
159 $shorturl = YOURLS_SITE.'/'.$keyword;
\r
162 <tr id="id-$id"><td id="keyword-$id"><a href="$shorturl">$shorturl</a></td><td id="url-$id"><a href="$url" title="$url">$url</a></td><td id="timestamp-$id">$date</td><td>$ip</td><td>$clicks</td><td class="actions"><input type="button" id="edit-button-$id" name="edit-button" value="Edit" class="button" onclick="edit('$id');" /> <input type="button" id="delete-button-$id" name="delete-button" value="Del" class="button" onclick="remove('$id');" /><input type="hidden" id="keyword_$id" value="$keyword"/></td></tr>
\r
166 // Get next id a new link will have if no custom keyword provided
\r
167 function yourls_get_next_decimal() {
\r
170 $table = YOURLS_DB_TABLE_NEXTDEC;
\r
171 return $ydb->get_var("SELECT `next_id` FROM `$table`");
\r
174 // Update id for next link with no custom keyword
\r
175 function yourls_update_next_decimal($int = '') {
\r
178 $int = ( $int == '' ) ? 'next_id+1' : (int)$int ;
\r
179 $table = YOURLS_DB_TABLE_NEXTDEC;
\r
180 return $ydb->query("UPDATE `$table` set next_id=$int");
\r
183 // Delete a link in the DB
\r
184 function yourls_delete_link_by_keyword( $keyword ) {
\r
187 $table = YOURLS_DB_TABLE_URL;
\r
188 $keyword = yourls_sanitize_string( $keyword );
\r
189 return $ydb->query("DELETE FROM `$table` WHERE `keyword` = '$keyword';");
\r
192 // SQL query to insert a new link in the DB. Needs sanitized data. Returns boolean for success or failure of the inserting
\r
193 function yourls_insert_link_in_db($url, $keyword) {
\r
196 $table = YOURLS_DB_TABLE_URL;
\r
197 $timestamp = date('Y-m-d H:i:s');
\r
198 $ip = yourls_get_IP();
\r
199 $insert = $ydb->query("INSERT INTO `$table` VALUES('$keyword', '$url', '$timestamp', '$ip', 0);");
\r
201 return (bool)$insert;
\r
204 // Add a new link in the DB, either with custom keyword, or find one
\r
205 function yourls_add_new_link( $url, $keyword = '' ) {
\r
208 if ( !$url || $url == 'http://' || $url == 'https://' ) {
\r
209 $return['status'] = 'fail';
\r
210 $return['code'] = 'error:nourl';
\r
211 $return['message'] = 'Missing URL input';
\r
215 $table = YOURLS_DB_TABLE_URL;
\r
216 $url = mysql_real_escape_string( yourls_sanitize_url($url) );
\r
217 $strip_url = stripslashes($url);
\r
218 $url_exists = $ydb->get_row("SELECT keyword,url FROM `$table` WHERE `url` = '".$strip_url."';");
\r
219 $ip = yourls_get_IP();
\r
222 // New URL : store it
\r
223 if( !$url_exists ) {
\r
225 // Custom keyword provided
\r
227 $keyword = mysql_real_escape_string(yourls_sanitize_string($keyword));
\r
228 if ( !yourls_keyword_is_free($keyword) ) {
\r
229 // This shorturl either reserved or taken already
\r
230 $return['status'] = 'fail';
\r
231 $return['code'] = 'error:keyword';
\r
232 $return['message'] = 'Short URL '.$keyword.' already exists in database or is reserved';
\r
234 // all clear, store !
\r
235 yourls_insert_link_in_db($url, $keyword);
\r
236 $return['url'] = array('keyword' => $keyword, 'url' => $strip_url, 'date' => date('Y-m-d H:i:s'), 'ip' => $ip );
\r
237 $return['status'] = 'success';
\r
238 $return['message'] = $strip_url.' added to database';
\r
239 $return['html'] = yourls_table_add_row( $keyword, $url, $ip, 0, time() );
\r
240 $return['shorturl'] = YOURLS_SITE .'/'. $keyword;
\r
243 // Create random keyword
\r
245 $timestamp = date('Y-m-d H:i:s');
\r
246 $id = yourls_get_next_decimal();
\r
249 $keyword = yourls_int2string( $id );
\r
250 $free = yourls_keyword_is_free($keyword);
\r
251 $add_url = @yourls_insert_link_in_db($url, $keyword);
\r
252 $ok = ($free && $add_url);
\r
253 if ( $ok === false && $add_url === 1 ) {
\r
254 // we stored something, but shouldn't have (ie reserved id)
\r
255 $delete = yourls_delete_link_by_keyword( $keyword );
\r
256 $return['extra_info'] .= '(deleted '.$keyword.')';
\r
258 // everything ok, populate needed vars
\r
259 $return['url'] = array('keyword' => $keyword, 'url' => $strip_url, 'date' => $timestamp, 'ip' => $ip );
\r
260 $return['status'] = 'success';
\r
261 $return['message'] = $strip_url.' added to database';
\r
262 $return['html'] = yourls_table_add_row( $keyword, $url, $ip, 0, time() );
\r
263 $return['shorturl'] = YOURLS_SITE .'/'. $keyword;
\r
267 @yourls_update_next_decimal($id);
\r
270 // URL was already stored
\r
271 $return['status'] = 'fail';
\r
272 $return['code'] = 'error:url';
\r
273 $return['message'] = $strip_url.' already exists in database';
\r
274 $return['shorturl'] = YOURLS_SITE .'/'. $url_exists->keyword;
\r
282 function yourls_edit_link($url, $keyword, $newkeyword='') {
\r
285 $table = YOURLS_DB_TABLE_URL;
\r
286 $url = mysql_real_escape_string(yourls_sanitize_url($url));
\r
287 $keyword = yourls_sanitize_string( $keyword );
\r
288 $newkeyword = yourls_sanitize_string( $newkeyword );
\r
289 $strip_url = stripslashes($url);
\r
290 $old_url = $ydb->get_var("SELECT `url` FROM `$table` WHERE `keyword` = '$keyword';");
\r
292 // Check if new URL is not here already
\r
293 if ($old_url != $url) {
\r
294 $new_url_already_there = intval($ydb->get_var("SELECT COUNT(keyword) FROM `$table` WHERE `url` = '$strip_url';"));
\r
296 $new_url_already_there = false;
\r
299 // Check if the new keyword is not here already
\r
300 if ( $newkeyword != $keyword ) {
\r
301 $keyword_is_ok = yourls_keyword_is_free( $newkeyword );
\r
303 $keyword_is_ok = true;
\r
306 // All clear, update
\r
307 if ( !$new_url_already_there && $keyword_is_ok ) {
\r
308 $timestamp4screen = date( 'Y M d H:i', time()+( yourls_HOURS_OFFSET * 3600) );
\r
309 $timestamp4db = date('Y-m-d H:i:s', time()+( yourls_HOURS_OFFSET * 3600) );
\r
310 $update_url = $ydb->query("UPDATE `$table` SET `url` = '$url', `timestamp` = '$timestamp4db', `keyword` = '$newkeyword' WHERE `keyword` = '$keyword';");
\r
311 if( $update_url ) {
\r
312 $return['url'] = array( 'keyword' => $newkeyword, 'shorturl' => YOURLS_SITE.'/'.$newkeyword, 'url' => $strip_url, 'date' => $timestamp4screen);
\r
313 $return['status'] = 'success';
\r
314 $return['message'] = 'Link updated in database';
\r
316 $return['status'] = 'fail';
\r
317 $return['message'] = 'Error updating '.$strip_url.' (Short URL: '.$keyword.') to database';
\r
322 $return['status'] = 'fail';
\r
323 $return['message'] = 'URL or keyword already exists in database';
\r
330 // Check if keyword id is free (ie not already taken, and not reserved)
\r
331 function yourls_keyword_is_free( $keyword ) {
\r
334 $table = YOURLS_DB_TABLE_URL;
\r
335 if ( yourls_keyword_is_reserved($keyword) )
\r
338 $already_exists = $ydb->get_var("SELECT COUNT(`keyword`) FROM `$table` WHERE `keyword` = '$keyword';");
\r
339 if ( $already_exists )
\r
347 function yourls_page( $page ) {
\r
348 $include = dirname(dirname(__FILE__))."/pages/$page.php";
\r
349 if (!file_exists($include)) {
\r
350 die("Page '$page' not found");
\r
357 function yourls_db_connect() {
\r
360 if (!defined('YOURLS_DB_USER')
\r
361 or !defined('YOURLS_DB_PASS')
\r
362 or !defined('YOURLS_DB_NAME')
\r
363 or !defined('YOURLS_DB_HOST')
\r
364 or !class_exists('ezSQL_mysql')
\r
365 ) die ('DB config/class missing');
\r
367 $ydb = new ezSQL_mysql(YOURLS_DB_USER, YOURLS_DB_PASS, YOURLS_DB_NAME, YOURLS_DB_HOST);
\r
368 if ( $ydb->last_error )
\r
369 die( $ydb->last_error );
\r
371 if ( defined('YOURLS_DEBUG') && YOURLS_DEBUG === true )
\r
372 $ydb->show_errors = true;
\r
377 // Return JSON output. Compatible with PHP prior to 5.2
\r
378 function yourls_json_encode($array) {
\r
379 if (function_exists('json_encode')) {
\r
380 return json_encode($array);
\r
382 require_once(dirname(__FILE__).'/functions-json.php');
\r
383 return yourls_array_to_json($array);
\r
387 // Return XML output.
\r
388 function yourls_xml_encode($array) {
\r
389 require_once(dirname(__FILE__).'/functions-xml.php');
\r
390 $converter= new yourls_array2xml;
\r
391 return $converter->array2xml($array);
\r
394 // Return long URL associated with keyword. Optional $notfound = string default message if nothing found
\r
395 function yourls_get_longurl( $keyword, $notfound = false ) {
\r
397 $keyword = yourls_sanitize_string( $keyword );
\r
398 $table = YOURLS_DB_TABLE_URL;
\r
399 $url = stripslashes($ydb->get_var("SELECT `url` FROM `$table` WHERE `keyword` = '$keyword'"));
\r
407 // Update click count on a short URL
\r
408 function yourls_update_clicks( $keyword ) {
\r
410 $keyword = yourls_sanitize_string( $keyword );
\r
411 $table = YOURLS_DB_TABLE_URL;
\r
412 return $ydb->query("UPDATE `$table` SET `clicks` = clicks + 1 WHERE `keyword` = '$keyword'");
\r
417 // Return array for API stat requests
\r
418 function yourls_api_stats( $filter, $limit ) {
\r
421 switch( $filter ) {
\r
423 $sort_by = 'clicks';
\r
424 $sort_order = 'asc';
\r
427 $sort_by = 'timestamp';
\r
428 $sort_order = 'desc';
\r
432 $sort_by = 'RAND()';
\r
437 $sort_by = 'clicks';
\r
438 $sort_order = 'desc';
\r
442 $limit = intval( $limit );
\r
443 $table_url = YOURLS_DB_TABLE_URL;
\r
444 $results = $ydb->get_results("SELECT * FROM $table_url WHERE 1=1 ORDER BY $sort_by $sort_order LIMIT 0, $limit;");
\r
449 foreach ($results as $res) {
\r
450 $return['links']['link_'.$i++] = array(
\r
451 'shorturl' => YOURLS_SITE .'/'. $res->keyword,
\r
452 'url' => $res->url,
\r
453 'timestamp' => $res->timestamp,
\r
455 'clicks' => $res->clicks
\r
459 $return['stats'] = yourls_get_db_stats();
\r
465 // Get total number of URLs and sum of clicks. Input: optional "AND WHERE" clause. Returns array
\r
466 function yourls_get_db_stats( $where = '' ) {
\r
468 $table_url = YOURLS_DB_TABLE_URL;
\r
470 $totals = $ydb->get_row("SELECT COUNT(keyword) as count, SUM(clicks) as sum FROM $table_url WHERE 1=1 $where");
\r
471 return array( 'total_links' => $totals->count, 'total_clicks' => $totals->sum );
\r
474 // Return API result. Dies after this
\r
475 function yourls_api_output( $mode, $return ) {
\r
478 header('Content-type: application/json');
\r
479 echo yourls_json_encode($return);
\r
483 header('Content-type: application/xml');
\r
484 echo yourls_xml_encode($return);
\r
489 echo $return['shorturl'];
\r
495 // Display HTML head and <body> tag
\r
496 function yourls_html_head( $context = 'index' ) {
\r
497 // Load components as needed
\r
498 switch ( $context ) {
\r
502 $tablesorter = true;
\r
508 $tablesorter = true;
\r
518 $tablesorter = false;
\r
523 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
\r
524 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
\r
526 <title>YOURLS » Your Own URL Shortener | <?php echo YOURLS_SITE; ?></title>
\r
527 <link rel="icon" type="image/gif" href="<?php echo YOURLS_SITE; ?>/images/favicon.gif" />
\r
528 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
\r
529 <meta name="copyright" content="Copyright © 2008-<?php echo date('Y'); ?> YOURS" />
\r
530 <meta name="author" content="Ozh Richard, Lester Chan" />
\r
531 <meta name="description" content="Insert URL « YOURLS » Your Own URL Shortener' | <?php echo YOURLS_SITE; ?>" />
\r
532 <script src="<?php echo YOURLS_SITE; ?>/js/jquery-1.3.2.min.js" type="text/javascript"></script>
\r
533 <link rel="stylesheet" href="<?php echo YOURLS_SITE; ?>/css/style.css" type="text/css" media="screen" />
\r
534 <?php if ($tablesorter) { ?>
\r
535 <link rel="stylesheet" href="<?php echo YOURLS_SITE; ?>/css/tablesorter.css" type="text/css" media="screen" />
\r
536 <script src="<?php echo YOURLS_SITE; ?>/js/jquery.tablesorter.min.js" type="text/javascript"></script>
\r
538 <?php if ($insert) { ?>
\r
539 <script src="<?php echo YOURLS_SITE; ?>/js/insert.js" type="text/javascript"></script>
\r
541 <?php if ($share) { ?>
\r
542 <script src="<?php echo YOURLS_SITE; ?>/js/share.js" type="text/javascript"></script>
\r
545 <body class="<?php echo $context; ?>">
\r
549 // Display HTML footer (including closing body & html tags)
\r
550 function yourls_html_footer() {
\r
553 $num_queries = ( $ydb && $ydb->num_queries ? ' – '.$ydb->num_queries.' queries' : '' );
\r
555 <div id="footer"><p>Powered by <a href="http://yourls.org/" title="YOURLS">YOURLS</a> v<?php echo YOURLS_VERSION; echo $num_queries; ?></p></div>
\r
561 // Display "Add new URL" box
\r
562 function yourls_html_addnew( $url = '', $keyword = '' ) {
\r
563 $url = $url ? $url : 'http://';
\r
567 <form id="new_url_form" action="" method="get">
\r
568 <div><strong>Enter the URL</strong>:<input type="text" id="add-url" name="url" value="<?php echo $url; ?>" class="text" size="90" />
\r
569 Optional: <strong>Custom short URL</strong>:<input type="text" id="add-keyword" name="keyword" value="<?php echo $keyword; ?>" maxlength="12" class="text" size="8" />
\r
570 <input type="button" id="add-button" name="add-button" value="Shorten The URL" class="button" onclick="add();" /></div>
\r
572 <div id="feedback" style="display:none"></div>
\r
578 // Display main table's footer
\r
579 function yourls_html_tfooter( $params = array() ) {
\r
580 extract( $params ); // extract $search_text, $page, $search_in_sql ...
\r
585 <th colspan="4" style="text-align: left;">
\r
586 <form action="" method="get">
\r
588 <div style="float:right;">
\r
589 <input type="submit" id="submit-sort" value="Filter" class="button primary" />
\r
591 <input type="button" id="submit-clear-filter" value="Clear Filter" class="button" onclick="window.parent.location.href = 'index.php'" />
\r
594 Search for
\r
595 <input type="text" name="s_search" class="text" size="20" value="<?php echo $search_text; ?>" />
\r
597 <select name="s_in" size="1">
\r
598 <!-- <option value="id"<?php if($search_in_sql == 'id') { echo ' selected="selected"'; } ?>>ID</option> -->
\r
599 <option value="url"<?php if($search_in_sql == 'url') { echo ' selected="selected"'; } ?>>URL</option>
\r
600 <option value="ip"<?php if($search_in_sql == 'ip') { echo ' selected="selected"'; } ?>>IP</option>
\r
602 – Order by
\r
603 <select name="s_by" size="1">
\r
604 <option value="id"<?php if($sort_by_sql == 'id') { echo ' selected="selected"'; } ?>>ID</option>
\r
605 <option value="url"<?php if($sort_by_sql == 'url') { echo ' selected="selected"'; } ?>>URL</option>
\r
606 <option value="timestamp"<?php if($sort_by_sql == 'timestamp') { echo ' selected="selected"'; } ?>>Date</option>
\r
607 <option value="ip"<?php if($sort_by_sql == 'ip') { echo ' selected="selected"'; } ?>>IP</option>
\r
608 <option value="clicks"<?php if($sort_by_sql == 'clicks') { echo ' selected="selected"'; } ?>>Clicks</option>
\r
610 <select name="s_order" size="1">
\r
611 <option value="asc"<?php if($sort_order_sql == 'asc') { echo ' selected="selected"'; } ?>>Ascending</option>
\r
612 <option value="desc"<?php if($sort_order_sql == 'desc') { echo ' selected="selected"'; } ?>>Descending</option>
\r
614 – Show
\r
615 <input type="text" name="perpage" class="text" size="2" value="<?php echo $perpage; ?>" /> rows<br/>
\r
618 <select name="link_filter" size="1">
\r
619 <option value="more"<?php if($link_filter === 'more') { echo ' selected="selected"'; } ?>>more</option>
\r
620 <option value="less"<?php if($link_filter === 'less') { echo ' selected="selected"'; } ?>>less</option>
\r
623 <input type="text" name="link_limit" class="text" size="4" value="<?php echo $link_limit; ?>" />clicks
\r
629 <th colspan="3" style="text-align: right;">
\r
630 Pages (<?php echo $total_pages; ?>):
\r
633 echo '<b><a href="'.$base_page.'?s_by='.$sort_by_sql.'&s_order='.$sort_order_sql.$search_url.'&perpage='.$perpage.'&page=1'.'" title="Go to First Page">« First</a></b> ... ';
\r
636 echo ' <b><a href="'.$base_page.'?s_by='.$sort_by_sql.'&s_order='.$sort_order_sql.$search_url.'&perpage='.$perpage.'&page='.($page-1).'" title="« Go to Page '.($page-1).'">«</a></b> ';
\r
638 for($i = $page - 2 ; $i <= $page +2; $i++) {
\r
639 if ($i >= 1 && $i <= $total_pages) {
\r
641 echo "<strong>[$i]</strong> ";
\r
643 echo '<a href="'.$base_page.'?s_by='.$sort_by_sql.'&s_order='.$sort_order_sql.$search_url.'&perpage='.$perpage.'&page='.($i).'" title="Page '.$i.'">'.$i.'</a> ';
\r
647 if($page < $total_pages) {
\r
648 echo ' <b><a href="'.$base_page.'?s_by='.$sort_by_sql.'&s_order='.$sort_order_sql.$search_url.'&perpage='.$perpage.'&page='.($page+1).'" title="Go to Page '.($page+1).' »">»</a></b> ';
\r
650 if (($page+2) < $total_pages) {
\r
651 echo ' ... <b><a href="'.$base_page.'?s_by='.$sort_by_sql.'&s_order='.$sort_order_sql.$search_url.'&perpage='.$perpage.'&page='.($total_pages).'" title="Go to Last Page">Last »</a></b>';
\r
660 // Display the Quick Share box of the tools.php page
\r
661 function yourls_share_box( $longurl, $shorturl, $title='', $text='' ) {
\r
662 $text = ( $text ? '"'.$text.'" ' : '' );
\r
663 $title = ( $title ? "$title " : '' );
\r
664 $share = htmlentities( $title.$text.$shorturl );
\r
665 $_share = rawurlencode( $share );
\r
666 $_url = rawurlencode( $shorturl );
\r
667 $count = 140 - strlen( $share );
\r
670 <div id="shareboxes">
\r
672 <div id="copybox" class="share">
\r
673 <h2>Your short link</h2>
\r
674 <p><input id="copylink" class="text" size="40" value="<?php echo $shorturl; ?>" /></p>
\r
675 <p><small>Original link: <a href="<?php echo $longurl; ?>"><?php echo $longurl; ?></a></small></p>
\r
678 <div id="sharebox" class="share">
\r
679 <h2>Quick Share</h2>
\r
681 <span id="charcount"><?php echo $count; ?></span>
\r
682 <textarea id="tweet_body"><?php echo $share; ?></textarea>
\r
684 <p id="share_links">Share with
\r
685 <a id="share_tw" href="http://twitter.com/home?status=<?php echo $_share; ?>" title="Tweet this!" onclick="share('tw');return false">Twitter</a>
\r
686 <a id="share_fb" href="http://www.facebook.com/share.php?u=<?php echo $_url; ?>" title="Share on Facebook" onclick="share('fb');return false;">Facebook</a>
\r
687 <a id="share_ff" href="http://friendfeed.com/share/bookmarklet/frame#title=<?php echo $_share; ?>" title="Share on Friendfeed" onclick="javascript:share('ff');return false;">FriendFeed</a>
\r
697 // Get number of SQL queries performed
\r
698 function yourls_get_num_queries() {
\r
701 return $ydb->num_queries;
\r
704 // Compat http_build_query for PHP4
\r
705 if (!function_exists('http_build_query')) {
\r
706 function http_build_query($data, $prefix=null, $sep=null) {
\r
707 return yourls_http_build_query($data, $prefix, $sep);
\r
711 // from php.net (modified by Mark Jaquith to behave like the native PHP5 function)
\r
712 function yourls_http_build_query($data, $prefix=null, $sep=null, $key='', $urlencode=true) {
\r
715 foreach ( (array) $data as $k => $v ) {
\r
717 $k = urlencode($k);
\r
718 if ( is_int($k) && $prefix != null )
\r
720 if ( !empty($key) )
\r
721 $k = $key . '%5B' . $k . '%5D';
\r
724 elseif ( $v === FALSE )
\r
727 if ( is_array($v) || is_object($v) )
\r
728 array_push($ret,yourls_http_build_query($v, '', $sep, $k, $urlencode));
\r
729 elseif ( $urlencode )
\r
730 array_push($ret, $k.'='.urlencode($v));
\r
732 array_push($ret, $k.'='.$v);
\r
735 if ( NULL === $sep )
\r
736 $sep = ini_get('arg_separator.output');
\r
738 return implode($sep, $ret);
\r
741 // Returns a sanitized a user agent string. Given what I found on http://www.user-agents.org/ it should be OK.
\r
742 function yourls_get_user_agent() {
\r
743 if ( !isset( $_SERVER['HTTP_USER_AGENT'] ) )
\r
746 $ua = strip_tags( html_entity_decode( $_SERVER['HTTP_USER_AGENT'] ));
\r
747 $ua = preg_replace('![^0-9a-zA-Z\':., /{}\(\)\[\]\+@&\!\?;_\-=~\*\#]!', '', $ua );
\r
749 return substr( $ua, 0, 254 );
\r
752 // Redirect to another page
\r
753 function yourls_redirect( $location, $code = 301 ) {
\r
754 // Anti fool check: cannot redirect to the URL we currently are on
\r
755 if( preg_replace('!^[^:]+://!', '', $location) != $_SERVER["SERVER_NAME"].$_SERVER['REQUEST_URI'] ) {
\r
756 $protocol = $_SERVER["SERVER_PROTOCOL"];
\r
757 if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
\r
758 $protocol = 'HTTP/1.0';
\r
760 $code = intval( $code );
\r
761 $desc = yourls_get_HTTP_status($code);
\r
763 if ( php_sapi_name() != 'cgi-fcgi' )
\r
764 header ("$protocol $code $desc"); // This causes problems on IIS and some FastCGI setups
\r
765 header("Location: $location");
\r
770 // Redirect to another page using Javascript
\r
771 function yourls_redirect_javascript( $location ) {
\r
773 <script type="text/javascript">
\r
774 //window.location="$location";
\r
776 <small>(if you are not redirected after 10 seconds, please <a href="$location">click here</a>)</small>
\r
780 // Return a HTTP status code
\r
781 function yourls_get_HTTP_status( $code ) {
\r
782 $code = intval( $code );
\r
783 $headers_desc = array(
\r
785 101 => 'Switching Protocols',
\r
786 102 => 'Processing',
\r
791 203 => 'Non-Authoritative Information',
\r
792 204 => 'No Content',
\r
793 205 => 'Reset Content',
\r
794 206 => 'Partial Content',
\r
795 207 => 'Multi-Status',
\r
798 300 => 'Multiple Choices',
\r
799 301 => 'Moved Permanently',
\r
801 303 => 'See Other',
\r
802 304 => 'Not Modified',
\r
803 305 => 'Use Proxy',
\r
805 307 => 'Temporary Redirect',
\r
807 400 => 'Bad Request',
\r
808 401 => 'Unauthorized',
\r
809 402 => 'Payment Required',
\r
810 403 => 'Forbidden',
\r
811 404 => 'Not Found',
\r
812 405 => 'Method Not Allowed',
\r
813 406 => 'Not Acceptable',
\r
814 407 => 'Proxy Authentication Required',
\r
815 408 => 'Request Timeout',
\r
818 411 => 'Length Required',
\r
819 412 => 'Precondition Failed',
\r
820 413 => 'Request Entity Too Large',
\r
821 414 => 'Request-URI Too Long',
\r
822 415 => 'Unsupported Media Type',
\r
823 416 => 'Requested Range Not Satisfiable',
\r
824 417 => 'Expectation Failed',
\r
825 422 => 'Unprocessable Entity',
\r
827 424 => 'Failed Dependency',
\r
828 426 => 'Upgrade Required',
\r
830 500 => 'Internal Server Error',
\r
831 501 => 'Not Implemented',
\r
832 502 => 'Bad Gateway',
\r
833 503 => 'Service Unavailable',
\r
834 504 => 'Gateway Timeout',
\r
835 505 => 'HTTP Version Not Supported',
\r
836 506 => 'Variant Also Negotiates',
\r
837 507 => 'Insufficient Storage',
\r
838 510 => 'Not Extended'
\r
841 if ( isset( $headers_desc[$code] ) )
\r
842 return $headers_desc[$code];
\r
848 // Log a redirect (for stats)
\r
849 function yourls_log_redirect( $keyword ) {
\r
851 $table = YOURLS_DB_TABLE_LOG;
\r
853 $keyword = yourls_sanitize_string( $keyword );
\r
854 $referrer = ( isset( $_SERVER['HTTP_REFERER'] ) ? yourls_sanitize_url( $_SERVER['HTTP_REFERER'] ) : 'direct' );
\r
855 $ua = yourls_get_user_agent();
\r
856 $ip = yourls_get_IP();
\r
857 $location = yourls_get_location( $ip );
\r
859 return $ydb->query( "INSERT INTO `$table` VALUES ('', NOW(), '$url', '$referrer', '$ua', '$ip', '$location')" );
\r
862 // Converts an IP to a 2 letter country code, using GeoIP database if available in includes/geo/
\r
863 function yourls_get_location( $ip = '', $default = '' ) {
\r
864 if ( !file_exists( dirname(__FILE__).'/geo/GeoIP.dat') || !file_exists( dirname(__FILE__).'/geo/geoip.inc') )
\r
868 $ip = yourls_get_IP();
\r
870 require_once( dirname(__FILE__).'/geo/geoip.inc') ;
\r
871 $gi = geoip_open( dirname(__FILE__).'/geo/GeoIP.dat', GEOIP_STANDARD);
\r
872 $location = geoip_country_code_by_addr($gi, $ip);
\r
878 // Check if an upgrade is needed
\r
879 function yourls_upgrade_is_needed() {
\r
880 // check YOURLS_VERSION && YOURLS_DB_VERSION exist && match values stored in YOURLS_DB_TABLE_OPTIONS
\r
881 list( $currentver, $currentsql ) = yourls_get_current_version_from_sql();
\r
883 // Using floatval() to get 1.4 from 1.4-alpha
\r
884 if( ( $currentver < floatval( YOURLS_VERSION ) ) || ( $currentsql < floatval( YOURLS_DB_VERSION ) ) )
\r
890 // Get current version & db version as stored in the options DB
\r
891 function yourls_get_current_version_from_sql() {
\r
892 if( !defined('YOURLS_DB_TABLE_OPTIONS') )
\r
893 die('<p>Your <tt>config.php</tt> does not contain all the required constant definitions. Please check <tt>config-sample.php</tt> and update your config accordingly, there are new stuffs!</p>');
\r
896 $table = YOURLS_DB_TABLE_OPTIONS;
\r
897 $currentver = @$ydb->get_var("SELECT `option_value` FROM $table WHERE `option_name` = 'version'");
\r
898 $currentsql = @$ydb->get_var("SELECT `option_value` FROM $table WHERE `option_name` = 'db_version'");
\r
900 $currentver = '1.3';
\r
902 $currentsql = '100';
\r
904 return array( $currentver, $currentsql);
\r
907 // Read an option from DB (or from cache if available). Return value or $default if not found
\r
908 function yourls_get_option( $option_name, $default = false ) {
\r
909 if ( !isset( $ydb->option[$option_name] ) ) {
\r
911 $table = YOURLS_DB_TABLE_OPTIONS;
\r
912 $option_name = yourls_escape( $option_name );
\r
913 $row = $ydb->get_row( "SELECT `option_value` FROM `$table` WHERE `option_name` = '$option_name' LIMIT 1" );
\r
914 if ( is_object( $row) ) { // Has to be get_row instead of get_var because of funkiness with 0, false, null values
\r
915 $value = $row->option_value;
\r
916 } else { // option does not exist, so we must cache its non-existence
\r
919 $ydb->option[$option_name] = yourls_maybe_unserialize( $value );
\r
922 return $ydb->option[$option_name];
\r
925 // Update (add if doesn't exist) an option to DB
\r
926 function yourls_update_option( $option_name, $newvalue ) {
\r
928 $table = YOURLS_DB_TABLE_OPTIONS;
\r
930 $safe_option_name = yourls_escape( $option_name );
\r
931 $newvalue = yourls_escape( $newvalue );
\r
933 $oldvalue = yourls_get_option( $safe_option_name );
\r
935 // If the new and old values are the same, no need to update.
\r
936 if ( $newvalue === $oldvalue )
\r
939 if ( false === $oldvalue ) {
\r
940 yourls_add_option( $option_name, $newvalue );
\r
944 $_newvalue = yourls_maybe_serialize( $newvalue );
\r
946 $ydb->query( "UPDATE `$table` SET `option_value` = '$_newvalue' WHERE `option_name` = '$option_name'");
\r
948 if ( $ydb->rows_affected == 1 ) {
\r
949 $ydb->option[$option_name] = $newvalue;
\r
955 // Add an option to the DB
\r
956 function yourls_add_option( $name, $value = '' ) {
\r
958 $table = YOURLS_DB_TABLE_OPTIONS;
\r
959 $safe_name = yourls_escape( $name );
\r
960 $value = yourls_escape( $value );
\r
962 // Make sure the option doesn't already exist. We can check the 'notoptions' cache before we ask for a db query
\r
963 if ( false !== yourls_get_option( $safe_name ) )
\r
966 $_value = yourls_maybe_serialize( $value );
\r
968 $ydb->query( "INSERT INTO `$table` (`option_name`, `option_value`) VALUES ('$name', '$_value')" );
\r
969 $ydb->option[$name] = $value;
\r
974 // Delete an option from the DB
\r
975 function yourls_delete_option( $name ) {
\r
977 $table = YOURLS_DB_TABLE_OPTIONS;
\r
978 $name = yourls_escape( $name );
\r
980 // Get the ID, if no ID then return
\r
981 $option = $ydb->get_row( "SELECT option_id FROM `$table` WHERE `option_name` = '$name'" );
\r
982 if ( is_null($option) || !$option->option_id )
\r
984 $ydb->query( "DELETE FROM `$table` WHERE `option_name` = '$name'" );
\r
990 // Serialize data if needed. Stolen from WordPress
\r
991 function yourls_maybe_serialize( $data ) {
\r
992 if ( is_array( $data ) || is_object( $data ) )
\r
993 return serialize( $data );
\r
995 if ( yourls_is_serialized( $data ) )
\r
996 return serialize( $data );
\r
1001 // Check value to find if it was serialized. Stolen from WordPress
\r
1002 function yourls_is_serialized( $data ) {
\r
1003 // if it isn't a string, it isn't serialized
\r
1004 if ( !is_string( $data ) )
\r
1006 $data = trim( $data );
\r
1007 if ( 'N;' == $data )
\r
1009 if ( !preg_match( '/^([adObis]):/', $data, $badions ) )
\r
1011 switch ( $badions[1] ) {
\r
1015 if ( preg_match( "/^{$badions[1]}:[0-9]+:.*[;}]\$/s", $data ) )
\r
1021 if ( preg_match( "/^{$badions[1]}:[0-9.E-]+;\$/", $data ) )
\r
1028 // Unserialize value only if it was serialized. Stolen from WP
\r
1029 function yourls_maybe_unserialize( $original ) {
\r
1030 if ( yourls_is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
\r
1031 return @unserialize( $original );
\r