diff --git a/.gitignore b/.gitignore index b7fd377..9656d79 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ user/plugins/*/vendor/* # frontend tooling frontend/node_modules frontend/package-lock.json +node_modules +package-lock.json + # backend tooling user/plugins/sleeky-backend/node_modules diff --git a/admin/admin-ajax.php b/admin/admin-ajax.php index 88de236..edfa16a 100644 --- a/admin/admin-ajax.php +++ b/admin/admin-ajax.php @@ -10,38 +10,38 @@ yourls_no_frame_header(); if( !isset( $_REQUEST['action'] ) ) - die(); + die(); // Pick action $action = $_REQUEST['action']; switch( $action ) { - case 'add': - yourls_verify_nonce( 'add_url', $_REQUEST['nonce'], false, 'omg error' ); - $return = yourls_add_new_link( $_REQUEST['url'], $_REQUEST['keyword'], '', $_REQUEST['rowid'] ); - echo json_encode($return); - break; - - case 'edit_display': - yourls_verify_nonce( 'edit-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); - $row = yourls_table_edit_row ( $_REQUEST['keyword'], $_REQUEST['id'] ); - echo json_encode( array('html' => $row) ); - break; - - case 'edit_save': - yourls_verify_nonce( 'edit-save_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); - $return = yourls_edit_link( $_REQUEST['url'], $_REQUEST['keyword'], $_REQUEST['newkeyword'], $_REQUEST['title'] ); - echo json_encode($return); - break; - - case 'delete': - yourls_verify_nonce( 'delete-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); - $query = yourls_delete_link_by_keyword( $_REQUEST['keyword'] ); - echo json_encode(array('success'=>$query)); - break; - - default: - yourls_do_action( 'yourls_ajax_'.$action ); + case 'add': + yourls_verify_nonce( 'add_url', $_REQUEST['nonce'], false, 'omg error' ); + $return = yourls_add_new_link( $_REQUEST['url'], $_REQUEST['keyword'], '', $_REQUEST['rowid'] ); + echo json_encode($return); + break; + + case 'edit_display': + yourls_verify_nonce( 'edit-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); + $row = yourls_table_edit_row ( $_REQUEST['keyword'], $_REQUEST['id'] ); + echo json_encode( array('html' => $row) ); + break; + + case 'edit_save': + yourls_verify_nonce( 'edit-save_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); + $return = yourls_edit_link( $_REQUEST['url'], $_REQUEST['keyword'], $_REQUEST['newkeyword'], $_REQUEST['title'] ); + echo json_encode($return); + break; + + case 'delete': + yourls_verify_nonce( 'delete-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); + $query = yourls_delete_link_by_keyword( $_REQUEST['keyword'] ); + echo json_encode(array('success'=>$query)); + break; + + default: + yourls_do_action( 'yourls_ajax_'.$action ); } diff --git a/admin/index.php b/admin/index.php index da52bca..1e60a56 100644 --- a/admin/index.php +++ b/admin/index.php @@ -30,17 +30,20 @@ $search_in = $view_params->get_search_in(); $search_in_text = $view_params->get_param_long_name($search_in); if( $search && $search_in && $search_in_text ) { - $search_sentence = yourls_s( 'Searching for %1$s in %2$s.', yourls_esc_html( $search ), yourls_esc_html( $search_in_text ) ); - $search_text = $search; - $search = str_replace( '*', '%', '*' . $search . '*' ); + $search_sentence = yourls_s( 'Searching for %1$s in %2$s.', yourls_esc_html( $search ), yourls_esc_html( $search_in_text ) ); + $search_text = $search; + $search = str_replace( '*', '%', '*' . $search . '*' ); if( $search_in == 'all' ) { - $where['sql'] .= " AND CONCAT_WS('',`keyword`,`url`,`title`,`ip`) LIKE (:search)"; - // Search across all fields. The resulting SQL will be something like: - // SELECT * FROM `yourls_url` WHERE CONCAT_WS('',`keyword`,`url`,`title`,`ip`) LIKE ("%ozh%") - // CONCAT_WS because CONCAT('foo', 'bar', NULL) = NULL. NULL wins. Not sure if values can be NULL now or in the future, so better safe. - // TODO: pay attention to this bit when the DB schema changes + $where['sql'] .= " AND `keyword` LIKE (:search) + OR `url` LIKE (:search) + OR `title` COLLATE utf8mb4_unicode_ci LIKE (:search) COLLATE utf8mb4_unicode_ci + OR `ip` LIKE (:search) "; } else { - $where['sql'] .= " AND `$search_in` LIKE (:search)"; + $collate = ''; + if( $search_in == 'title' ) { + $collate = ' COLLATE utf8mb4_unicode_ci'; + } + $where['sql'] .= " AND `$search_in` $collate LIKE (:search) $collate"; } $where['binds']['search'] = $search; } @@ -96,139 +99,139 @@ // Get URLs Count for current filter, total links in DB & total clicks list( $total_urls, $total_clicks ) = array_values( yourls_get_db_stats() ); if ( !empty($where['sql']) ) { - list( $total_items, $total_items_clicks ) = array_values( yourls_get_db_stats( $where ) ); + list( $total_items, $total_items_clicks ) = array_values( yourls_get_db_stats( $where ) ); } else { - $total_items = $total_urls; - $total_items_clicks = false; + $total_items = $total_urls; + $total_items_clicks = false; } // This is a bookmarklet if ( isset( $_GET['u'] ) or isset( $_GET['up'] ) ) { - $is_bookmark = true; - yourls_do_action( 'bookmarklet' ); - - // No sanitization needed here: everything happens in yourls_add_new_link() - if( isset( $_GET['u'] ) ) { - // Old school bookmarklet: ?u= - $url = $_GET['u']; - } else { - // New style bookmarklet: ?up=&us=&ur= - $url = $_GET['up'] . $_GET['us'] . $_GET['ur']; - } - $keyword = ( isset( $_GET['k'] ) ? ( $_GET['k'] ) : '' ); - $title = ( isset( $_GET['t'] ) ? ( $_GET['t'] ) : '' ); - $return = yourls_add_new_link( $url, $keyword, $title ); - - // If fails because keyword already exist, retry with no keyword - if ( isset( $return['status'] ) && $return['status'] == 'fail' && isset( $return['code'] ) && $return['code'] == 'error:keyword' ) { - $msg = $return['message']; - $return = yourls_add_new_link( $url, '' ); - $return['message'] .= ' ('.$msg.')'; - } - - // Stop here if bookmarklet with a JSON callback function - if( isset( $_GET['jsonp'] ) && $_GET['jsonp'] == 'yourls' ) { - $short = $return['shorturl'] ? $return['shorturl'] : ''; - $message = $return['message']; - yourls_content_type_header( 'application/javascript' ); - echo yourls_apply_filter( 'bookmarklet_jsonp', "yourls_callback({'short_url':'$short','message':'$message'});" ); - - die(); - } - - // Now use the URL that has been sanitized and returned by yourls_add_new_link() - $url = $return['url']['url']; - $where['sql'] .= ' AND `url` LIKE :url '; + $is_bookmark = true; + yourls_do_action( 'bookmarklet' ); + + // No sanitization needed here: everything happens in yourls_add_new_link() + if( isset( $_GET['u'] ) ) { + // Old school bookmarklet: ?u= + $url = $_GET['u']; + } else { + // New style bookmarklet: ?up=&us=&ur= + $url = $_GET['up'] . $_GET['us'] . $_GET['ur']; + } + $keyword = ( isset( $_GET['k'] ) ? ( $_GET['k'] ) : '' ); + $title = ( isset( $_GET['t'] ) ? ( $_GET['t'] ) : '' ); + $return = yourls_add_new_link( $url, $keyword, $title ); + + // If fails because keyword already exist, retry with no keyword + if ( isset( $return['status'] ) && $return['status'] == 'fail' && isset( $return['code'] ) && $return['code'] == 'error:keyword' ) { + $msg = $return['message']; + $return = yourls_add_new_link( $url, '' ); + $return['message'] .= ' ('.$msg.')'; + } + + // Stop here if bookmarklet with a JSON callback function + if( isset( $_GET['jsonp'] ) && $_GET['jsonp'] == 'yourls' ) { + $short = $return['shorturl'] ? $return['shorturl'] : ''; + $message = $return['message']; + yourls_content_type_header( 'application/javascript' ); + echo yourls_apply_filter( 'bookmarklet_jsonp', "yourls_callback({'short_url':'$short','message':'$message'});" ); + + die(); + } + + // Now use the URL that has been sanitized and returned by yourls_add_new_link() + $url = $return['url']['url']; + $where['sql'] .= ' AND `url` LIKE :url '; $where['binds']['url'] = $url; - $page = $total_pages = $perpage = 1; - $offset = 0; - - $text = ( isset( $_GET['s'] ) ? stripslashes( $_GET['s'] ) : '' ); - - // Sharing with social bookmarklets - if( !empty($_GET['share']) ) { - yourls_do_action( 'pre_share_redirect' ); - switch ( $_GET['share'] ) { - case 'twitter': - // share with Twitter - $destination = sprintf( "https://twitter.com/intent/tweet?url=%s&text=%s", urlencode( $return['shorturl'] ), urlencode( $title ) ); - yourls_redirect( $destination, 303 ); - - // Deal with the case when redirection failed: - $return['status'] = 'error'; - $return['errorCode'] = '400'; - $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Twitter' ); - break; - - case 'facebook': - // share with Facebook - $destination = sprintf( "https://www.facebook.com/sharer/sharer.php?u=%s&t=%s", urlencode( $return['shorturl'] ), urlencode( $title ) ); - yourls_redirect( $destination, 303 ); - - // Deal with the case when redirection failed: - $return['status'] = 'error'; - $return['errorCode'] = '400'; - $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Facebook' ); - break; - - case 'tumblr': - // share with Tumblr - $destination = sprintf( "https://www.tumblr.com/share?v=3&u=%s&t=%s&s=%s", urlencode( $return['shorturl'] ), urlencode( $title ), urlencode( $text ) ); - yourls_redirect( $destination, 303 ); - - // Deal with the case when redirection failed: - $return['status'] = 'error'; - $return['errorCode'] = '400'; - $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Tumblr' ); - break; - - default: - // Is there a custom registered social bookmark? - yourls_do_action( 'share_redirect_' . $_GET['share'], $return ); - - // Still here? That was an unknown 'share' method, then. - $return['status'] = 'error'; - $return['errorCode'] = '400'; - $return['message'] = yourls__( 'Unknown "Share" bookmarklet' ); - break; - } - } + $page = $total_pages = $perpage = 1; + $offset = 0; + + $text = ( isset( $_GET['s'] ) ? stripslashes( $_GET['s'] ) : '' ); + + // Sharing with social bookmarklets + if( !empty($_GET['share']) ) { + yourls_do_action( 'pre_share_redirect' ); + switch ( $_GET['share'] ) { + case 'twitter': + // share with Twitter + $destination = sprintf( "https://twitter.com/intent/tweet?url=%s&text=%s", urlencode( $return['shorturl'] ), urlencode( $title ) ); + yourls_redirect( $destination, 303 ); + + // Deal with the case when redirection failed: + $return['status'] = 'error'; + $return['errorCode'] = '400'; + $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Twitter' ); + break; + + case 'facebook': + // share with Facebook + $destination = sprintf( "https://www.facebook.com/sharer/sharer.php?u=%s&t=%s", urlencode( $return['shorturl'] ), urlencode( $title ) ); + yourls_redirect( $destination, 303 ); + + // Deal with the case when redirection failed: + $return['status'] = 'error'; + $return['errorCode'] = '400'; + $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Facebook' ); + break; + + case 'tumblr': + // share with Tumblr + $destination = sprintf( "https://www.tumblr.com/share?v=3&u=%s&t=%s&s=%s", urlencode( $return['shorturl'] ), urlencode( $title ), urlencode( $text ) ); + yourls_redirect( $destination, 303 ); + + // Deal with the case when redirection failed: + $return['status'] = 'error'; + $return['errorCode'] = '400'; + $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Tumblr' ); + break; + + default: + // Is there a custom registered social bookmark? + yourls_do_action( 'share_redirect_' . $_GET['share'], $return ); + + // Still here? That was an unknown 'share' method, then. + $return['status'] = 'error'; + $return['errorCode'] = '400'; + $return['message'] = yourls__( 'Unknown "Share" bookmarklet' ); + break; + } + } // This is not a bookmarklet } else { - $is_bookmark = false; - - // Checking $page, $offset, $perpage - if( empty($page) || $page == 0 ) { - $page = 1; - } - if( empty($offset) ) { - $offset = 0; - } - if( empty($perpage) || $perpage == 0) { - $perpage = 50; - } - - // Determine $offset - $offset = ( $page-1 ) * $perpage; - - // Determine Max Number Of Items To Display On Page - if( ( $offset + $perpage ) > $total_items ) { - $max_on_page = $total_items; - } else { - $max_on_page = ( $offset + $perpage ); - } - - // Determine Number Of Items To Display On Page - if ( ( $offset + 1 ) > $total_items ) { - $display_on_page = $total_items; - } else { - $display_on_page = ( $offset + 1 ); - } - - // Determine Total Amount Of Pages - $total_pages = ceil( $total_items / $perpage ); + $is_bookmark = false; + + // Checking $page, $offset, $perpage + if( empty($page) || $page == 0 ) { + $page = 1; + } + if( empty($offset) ) { + $offset = 0; + } + if( empty($perpage) || $perpage == 0) { + $perpage = 50; + } + + // Determine $offset + $offset = ( $page-1 ) * $perpage; + + // Determine Max Number Of Items To Display On Page + if( ( $offset + $perpage ) > $total_items ) { + $max_on_page = $total_items; + } else { + $max_on_page = ( $offset + $perpage ); + } + + // Determine Number Of Items To Display On Page + if ( ( $offset + 1 ) > $total_items ) { + $display_on_page = $total_items; + } else { + $display_on_page = ( $offset + 1 ); + } + + // Determine Total Amount Of Pages + $total_pages = ceil( $total_items / $perpage ); } @@ -241,18 +244,18 @@ yourls_do_action( 'admin_page_before_content' ); if ( !$is_bookmark ) { ?> -

-

%1$s to %2$s of %3$s URLs' ), $display_on_page, $max_on_page, $total_items ); - if( $total_items_clicks !== false ) - echo ", " . sprintf( yourls_n( 'counting 1 click', 'counting %s clicks', $total_items_clicks ), yourls_number_format_i18n( $total_items_clicks ) ); - } - ?>.

+

+

%1$s to %2$s of %3$s URLs' ), $display_on_page, $max_on_page, $total_items ); + if( $total_items_clicks !== false ) + echo ", " . sprintf( yourls_n( 'counting 1 click', 'counting %s clicks', $total_items_clicks ), yourls_number_format_i18n( $total_items_clicks ) ); + } + ?>.

%1$s links, %2$s clicks, and counting!' ), yourls_number_format_i18n( $total_urls ), yourls_number_format_i18n( $total_clicks ) ); ?>

$(document).ready(function(){ - feedback( "' . $return['message'] . '", "'. $return['status'] .'"); - init_clipboard(); - });'; + echo ''; } yourls_do_action( 'admin_page_before_table' ); @@ -276,42 +279,42 @@ yourls_table_head(); if ( !$is_bookmark ) { - $params = array( - 'search' => $search, - 'search_text' => $search_text, - 'search_in' => $search_in, - 'sort_by' => $sort_by, - 'sort_order' => $sort_order, - 'page' => $page, - 'perpage' => $perpage, - 'click_filter' => $click_filter, - 'click_limit' => $click_limit, - 'total_pages' => $total_pages, - 'date_filter' => $date_filter, - 'date_first' => $date_first, - 'date_second' => $date_second, - ); - yourls_html_tfooter( $params ); + $params = array( + 'search' => $search, + 'search_text' => $search_text, + 'search_in' => $search_in, + 'sort_by' => $sort_by, + 'sort_order' => $sort_order, + 'page' => $page, + 'perpage' => $perpage, + 'click_filter' => $click_filter, + 'click_limit' => $click_limit, + 'total_pages' => $total_pages, + 'date_filter' => $date_filter, + 'date_first' => $date_first, + 'date_second' => $date_second, + ); + yourls_html_tfooter( $params ); } yourls_table_tbody_start(); // Main Query $where = yourls_apply_filter( 'admin_list_where', $where ); -$url_results = yourls_get_db()->fetchObjects( "SELECT * FROM `$table_url` WHERE 1=1 {$where['sql']} ORDER BY `$sort_by` $sort_order LIMIT $offset, $perpage;", $where['binds'] ); +$url_results = yourls_get_db('read-admin_index')->fetchObjects( "SELECT * FROM `$table_url` WHERE 1=1 {$where['sql']} ORDER BY `$sort_by` $sort_order LIMIT $offset, $perpage;", $where['binds'] ); $found_rows = false; if( $url_results ) { - $found_rows = true; - foreach( $url_results as $url_result ) { - $keyword = yourls_sanitize_keyword($url_result->keyword); - $timestamp = strtotime( $url_result->timestamp ); - $url = stripslashes( $url_result->url ); - $ip = $url_result->ip; - $title = $url_result->title ? $url_result->title : ''; - $clicks = $url_result->clicks; - - echo yourls_table_add_row( $keyword, $url, $title, $ip, $clicks, $timestamp ); - } + $found_rows = true; + foreach( $url_results as $url_result ) { + $keyword = yourls_sanitize_keyword($url_result->keyword); + $timestamp = strtotime( $url_result->timestamp ); + $url = stripslashes( $url_result->url ); + $ip = $url_result->ip; + $title = $url_result->title ? $url_result->title : ''; + $clicks = $url_result->clicks; + + echo yourls_table_add_row( $keyword, $url, $title, $ip, $clicks, $timestamp ); + } } $display = $found_rows ? 'display:none' : ''; @@ -323,8 +326,10 @@ yourls_do_action( 'admin_page_after_table' ); +yourls_delete_link_modal(); + if ( $is_bookmark ) - yourls_share_box( $url, $return['shorturl'], $title, $text ); + yourls_share_box( $url, $return['shorturl'], $title, $text ); ?> diff --git a/admin/install.php b/admin/install.php index 3b00450..3d4b99a 100644 --- a/admin/install.php +++ b/admin/install.php @@ -9,44 +9,44 @@ // Check pre-requisites if ( !yourls_check_PDO() ) { - $error[] = yourls__( 'PHP extension for PDO not found' ); - yourls_debug_log( 'PHP PDO extension not found' ); + $error[] = yourls__( 'PHP extension for PDO not found' ); + yourls_debug_log( 'PHP PDO extension not found' ); } if ( !yourls_check_database_version() ) { - $error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'MySQL' ); - yourls_debug_log( 'MySQL version: ' . yourls_get_database_version() ); + $error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'MySQL' ); + yourls_debug_log( 'MySQL version: ' . yourls_get_database_version() ); } if ( !yourls_check_php_version() ) { - $error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'PHP' ); - yourls_debug_log( 'PHP version: ' . PHP_VERSION ); + $error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'PHP' ); + yourls_debug_log( 'PHP version: ' . PHP_VERSION ); } // Is YOURLS already installed ? if ( yourls_is_installed() ) { - $error[] = yourls__( 'YOURLS already installed.' ); - // check if .htaccess exists, recreate otherwise. No error checking. - if( !file_exists( YOURLS_ABSPATH.'/.htaccess' ) ) { - yourls_create_htaccess(); - } + $error[] = yourls__( 'YOURLS already installed.' ); + // check if .htaccess exists, recreate otherwise. No error checking. + if( !file_exists( YOURLS_ABSPATH.'/.htaccess' ) ) { + yourls_create_htaccess(); + } } // Start install if possible and needed if ( isset($_REQUEST['install']) && count( $error ) == 0 ) { - // Create/update .htaccess file - if ( yourls_create_htaccess() ) { - $success[] = yourls__( 'File .htaccess successfully created/updated.' ); - } else { - $warning[] = yourls__( 'Could not write file .htaccess in YOURLS root directory. You will have to do it manually. See how.' ); - } + // Create/update .htaccess file + if ( yourls_create_htaccess() ) { + $success[] = yourls__( 'File .htaccess successfully created/updated.' ); + } else { + $warning[] = yourls__( 'Could not write file .htaccess in YOURLS root directory. You will have to do it manually. See how.' ); + } - // Create SQL tables - $install = yourls_create_sql_tables(); - if ( isset( $install['error'] ) ) - $error = array_merge( $error, $install['error'] ); - if ( isset( $install['success'] ) ) - $success = array_merge( $success, $install['success'] ); + // Create SQL tables + $install = yourls_create_sql_tables(); + if ( isset( $install['error'] ) ) + $error = array_merge( $error, $install['error'] ); + if ( isset( $install['success'] ) ) + $success = array_merge( $success, $install['success'] ); } @@ -54,30 +54,30 @@ yourls_html_head( 'install', yourls__( 'Install YOURLS' ) ); ?>
-
-

- -

- 0 ) { - echo "
    "; - foreach( $$info as $msg ) { - echo '
  • '.$msg."
  • \n"; - } - echo '
'; - } - } + +

+ +

+ 0 ) { + echo "
    "; + foreach( $$info as $msg ) { + echo '
  • '.$msg."
  • \n"; + } + echo '
'; + } + } - // Display install button or link to admin area if applicable - if( !yourls_is_installed() && !isset($_REQUEST['install']) ) { - echo '

'; - } else { - if( count($error) == 0 ) - echo '

» ' . yourls__( 'YOURLS Administration Page') . '

'; - } - ?> -
+ // Display install button or link to admin area if applicable + if( !yourls_is_installed() && !isset($_REQUEST['install']) ) { + echo '

'; + } else { + if( count($error) == 0 ) + echo '

» ' . yourls__( 'YOURLS Administration Page') . '

'; + } + ?> +
diff --git a/admin/plugins.php b/admin/plugins.php index ad81339..8d02b96 100644 --- a/admin/plugins.php +++ b/admin/plugins.php @@ -5,56 +5,56 @@ // Handle plugin administration pages if( isset( $_GET['page'] ) && !empty( $_GET['page'] ) ) { - yourls_plugin_admin_page( $_GET['page'] ); + yourls_plugin_admin_page( $_GET['page'] ); die(); } // Handle activation/deactivation of plugins if( isset( $_GET['action'] ) ) { - // Check nonce - yourls_verify_nonce( 'manage_plugins', $_REQUEST['nonce'] ?? ''); + // Check nonce + yourls_verify_nonce( 'manage_plugins', $_REQUEST['nonce'] ?? ''); - // Check plugin file is valid - if(isset( $_GET['plugin'] ) && yourls_is_a_plugin_file(YOURLS_PLUGINDIR . '/' . $_GET['plugin'] . '/plugin.php') ) { + // Check plugin file is valid + if(isset( $_GET['plugin'] ) && yourls_is_a_plugin_file(YOURLS_PLUGINDIR . '/' . $_GET['plugin'] . '/plugin.php') ) { - // Activate / Deactive - switch( $_GET['action'] ) { - case 'activate': - $result = yourls_activate_plugin( $_GET['plugin'].'/plugin.php' ); - if( $result === true ) { + // Activate / Deactive + switch( $_GET['action'] ) { + case 'activate': + $result = yourls_activate_plugin( $_GET['plugin'].'/plugin.php' ); + if( $result === true ) { yourls_redirect(yourls_admin_url('plugins.php?success=activated'), 302); exit(); } - break; + break; - case 'deactivate': - $result = yourls_deactivate_plugin( $_GET['plugin'].'/plugin.php' ); - if( $result === true ) { + case 'deactivate': + $result = yourls_deactivate_plugin( $_GET['plugin'].'/plugin.php' ); + if( $result === true ) { yourls_redirect(yourls_admin_url('plugins.php?success=deactivated'), 302); exit(); } - break; + break; - default: - $result = yourls__( 'Unsupported action' ); - break; - } - } else { - $result = yourls__( 'No plugin specified, or not a valid plugin' ); - } + default: + $result = yourls__( 'Unsupported action' ); + break; + } + } else { + $result = yourls__( 'No plugin specified, or not a valid plugin' ); + } - yourls_add_notice( $result ); + yourls_add_notice( $result ); } // Handle message upon successful (de)activation if( isset( $_GET['success'] ) && ( ( $_GET['success'] == 'activated' ) OR ( $_GET['success'] == 'deactivated' ) ) ) { - if( $_GET['success'] == 'activated' ) { - $message = yourls__( 'Plugin has been activated' ); - } elseif ( $_GET['success'] == 'deactivated' ) { - $message = yourls__( 'Plugin has been deactivated' ); - } - yourls_add_notice( $message ); + if( $_GET['success'] == 'activated' ) { + $message = yourls__( 'Plugin has been activated' ); + } elseif ( $_GET['success'] == 'deactivated' ) { + $message = yourls__( 'Plugin has been deactivated' ); + } + yourls_add_notice( $message ); } yourls_html_head( 'plugins', yourls__( 'Manage Plugins' ) ); @@ -62,106 +62,110 @@ yourls_html_menu(); ?> -
-

- - - -

%1$s installed, and %2$s activated', $plugins_count, $count_active ); ?>

- - - - - - - - - - - - - $plugin ) { - - // default fields to read from the plugin header - $fields = array( - 'name' => 'Plugin Name', - 'uri' => 'Plugin URI', - 'desc' => 'Description', - 'version' => 'Version', - 'author' => 'Author', - 'author_uri' => 'Author URI' - ); - - // Loop through all default fields, get value if any and reset it - foreach( $fields as $field=>$value ) { - if( isset( $plugin[ $value ] ) ) { - $data[ $field ] = $plugin[ $value ]; - } else { - $data[ $field ] = yourls__('(no info)'); - } - unset( $plugin[$value] ); - } - - $plugindir = trim( dirname( $file ), '/' ); - - if( yourls_is_active_plugin( $file ) ) { - $class = 'active'; - $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'deactivate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) ); - $action_anchor = yourls__( 'Deactivate' ); - } else { - $class = 'inactive'; - $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'activate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) ); - $action_anchor = yourls__( 'Activate' ); - } - - // Other "Fields: Value" in the header? Get them too - if( $plugin ) { - foreach( $plugin as $extra_field=>$extra_value ) { - $data['desc'] .= "
\n$extra_field: $extra_value"; - unset( $plugin[$extra_value] ); - } - } - - $data['desc'] .= '
' . yourls_s( 'plugin file location: %s', $file) . ''; - - printf( "", - $class, $data['uri'], $data['name'], $data['version'], $data['desc'], $data['author_uri'], $data['author'], $action_url, $action_anchor - ); - - } - ?> - -
%s%s%s%s%s
- - - -

plugin.php.' ); ?>

- -

- -

Plugin list.' ); ?>

-
+
+

+ + + +

%1$s installed, and %2$s activated', $plugins_count, $count_active ); ?>

+ + + + + + + + + + + + + $plugin ) { + + // default fields to read from the plugin header + $fields = array( + 'name' => 'Plugin Name', + 'uri' => 'Plugin URI', + 'desc' => 'Description', + 'version' => 'Version', + 'author' => 'Author', + 'author_uri' => 'Author URI' + ); + + // Loop through all default fields, get value if any and reset it + foreach( $fields as $field=>$value ) { + if( isset( $plugin[ $value ] ) ) { + $data[ $field ] = $plugin[ $value ]; + } else { + $data[ $field ] = yourls__('(no info)'); + # If it's a URL, set to # + if( in_array( $field, array('uri', 'author_uri') ) ) { + $data[$field] = '#' . $data[$field]; + } + } + unset( $plugin[$value] ); + } + + $plugindir = trim( dirname( $file ), '/' ); + + if( yourls_is_active_plugin( $file ) ) { + $class = 'active'; + $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'deactivate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) ); + $action_anchor = yourls__( 'Deactivate' ); + } else { + $class = 'inactive'; + $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'activate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) ); + $action_anchor = yourls__( 'Activate' ); + } + + // Other "Fields: Value" in the header? Get them too + if( $plugin ) { + foreach( $plugin as $extra_field=>$extra_value ) { + $data['desc'] .= "
\n$extra_field: $extra_value"; + unset( $plugin[$extra_value] ); + } + } + + $data['desc'] .= '
' . yourls_s( 'plugin file location: %s', $file) . ''; + + printf( "", + $class, $data['uri'], $data['name'], $data['version'], $data['desc'], $data['author_uri'], $data['author'], $action_url, $action_anchor + ); + + } + ?> + +
%s%s%s%s%s
+ + + +

plugin.php.' ); ?>

+ +

+ +

Plugin list.' ); ?>

+
diff --git a/admin/tools.php b/admin/tools.php index b2aecf8..b772061 100644 --- a/admin/tools.php +++ b/admin/tools.php @@ -8,49 +8,49 @@ yourls_html_menu(); ?> -
+
-

+

-

bookmarklets for easier link shortening and sharing.' ); ?>

+

bookmarklets for easier link shortening and sharing.' ); ?>

-

+

-
    -
  • Standard Bookmarklets will take you to a page where you can easily edit or delete your brand new short URL.' ); ?>
  • +
      +
    • Standard Bookmarklets will take you to a page where you can easily edit or delete your brand new short URL.' ); ?>
    • -
    • Instant Bookmarklets will pop the short URL without leaving the page you are viewing (depending on the page and server configuration, they may silently fail)' ); ?>
    • +
    • Instant Bookmarklets will pop the short URL without leaving the page you are viewing (depending on the page and server configuration, they may silently fail)' ); ?>
    • -
    • Simple Bookmarklets will generate a short URL with a random or sequential keyword.' ); ?>
    • +
    • Simple Bookmarklets will generate a short URL with a random or sequential keyword.' ); ?>
    • -
    • Custom Keyword Bookmarklets will prompt you for a custom keyword first.' ); ?>
    • -
    +
  • Custom Keyword Bookmarklets will prompt you for a custom keyword first.' ); ?>
  • +
-

select text on the page you're viewing before clicking on your bookmarklet link" ); - ?>

+

select text on the page you're viewing before clicking on your bookmarklet link" ); + ?>

Important Note: bookmarklets may fail on websites with https, especially the "Instant" bookrmarklets. There is nothing you can do about this.'); ?>

-

+

-

+

- - - - - - - - - - - - + + + + + + + + + + + - - - + + - - - -
 
+
 
+
+
+ + + -

+

-

-

+

+

-

+

- + -

+

-

+

-

%s\" to the beginning of the current URL (right before its 'http://' part) and hit enter.", preg_replace('@https?://@', '', yourls_get_yourls_site()) . '/' ); ?>

+

%s\" to the beginning of the current URL (right before its 'http://' part) and hit enter.", preg_replace('@https?://@', '', yourls_get_yourls_site()) . '/' ); ?>

-

.

+

.

- + -

+

-

username and password parameters.' ); - echo "\n"; - yourls_e( "If you're worried about sending your credentials into the wild, you can also make API calls without using your login or your password, using a secret signature token." ); - ?>

+

username and password parameters.' ); + echo "\n"; + yourls_e( "If you're worried about sending your credentials into the wild, you can also make API calls without using your login or your password, using a secret signature token." ); + ?>

-

%s', yourls_auth_signature() ); ?> +

%s', yourls_auth_signature() ); ?>

-

+

-
    -
  • -

    signature in your API requests. Example:' ); ?>

    -

    /yourls-api.php?signature=&action=...

    -
  • +
      +
    • +

      signature in your API requests. Example:' ); ?>

      +

      /yourls-api.php?signature=&action=...

      +
    • -
    • +
    • <?php
       $timestamp = time();
       //  $time = 
      @@ -322,19 +322,19 @@
       //  $signature = ""
       ?>
       
      -

      signature and timestamp in your API requests. Example:' ); ?>

      -

      /yourls-api.php?timestamp=$timestamp&signature=$signature&action=...

      -


      - /yourls-api.php?timestamp=&signature=&action=...

      -

      -
    • -
    +

    signature and timestamp in your API requests. Example:' ); ?>

    +

    /yourls-api.php?timestamp=$timestamp&signature=$signature&action=...

    +


    + /yourls-api.php?timestamp=&signature=&action=...

    +

    + +
-

Passwordless API page on the wiki.', 'https://yourls.org/passwordlessapi' ); ?> - API documentation for more', yourls_get_yourls_site() . '/readme.html#API' ); ?>

+

Passwordless API page on the wiki.', 'https://yourls.org/passwordlessapi' ); ?> + API documentation for more', yourls_get_yourls_site() . '/readme.html#API' ); ?>

-
+
- + diff --git a/admin/upgrade.php b/admin/upgrade.php index 536a9f8..957870c 100644 --- a/admin/upgrade.php +++ b/admin/upgrade.php @@ -8,73 +8,73 @@ yourls_html_logo(); yourls_html_menu(); ?> -

+

' . yourls_s( 'Upgrade not required. Go back to play!', yourls_admin_url('index.php') ) . '

'; + echo '

' . yourls_s( 'Upgrade not required. Go back to play!', yourls_admin_url('index.php') ) . '

'; } else { - /* - step 1: create new tables and populate them, update old tables structure, - step 2: convert each row of outdated tables if needed - step 3: - if applicable finish updating outdated tables (indexes etc) - - update version & db_version in options, this is all done! - */ + /* + step 1: create new tables and populate them, update old tables structure, + step 2: convert each row of outdated tables if needed + step 3: - if applicable finish updating outdated tables (indexes etc) + - update version & db_version in options, this is all done! + */ - // From what are we upgrading? - if ( isset( $_GET['oldver'] ) && isset( $_GET['oldsql'] ) ) { - $oldver = yourls_sanitize_version($_GET['oldver']); - $oldsql = intval($_GET['oldsql']); - } else { - list( $oldver, $oldsql ) = yourls_get_current_version_from_sql(); - } + // From what are we upgrading? + if ( isset( $_GET['oldver'] ) && isset( $_GET['oldsql'] ) ) { + $oldver = yourls_sanitize_version($_GET['oldver']); + $oldsql = intval($_GET['oldsql']); + } else { + list( $oldver, $oldsql ) = yourls_get_current_version_from_sql(); + } - // To what are we upgrading ? - $newver = YOURLS_VERSION; - $newsql = YOURLS_DB_VERSION; + // To what are we upgrading ? + $newver = YOURLS_VERSION; + $newsql = YOURLS_DB_VERSION; - // Verbose & ugly details - yourls_debug_mode(true); + // Verbose & ugly details + yourls_debug_mode(true); - // Let's go - $step = ( isset( $_GET['step'] ) ? intval( $_GET['step'] ) : 0 ); - switch( $step ) { + // Let's go + $step = ( isset( $_GET['step'] ) ? intval( $_GET['step'] ) : 0 ); + switch( $step ) { - default: - case 0: - ?> -

-

backup your database
(you should do this regularly anyway)' ); ?>

-

should happen, but this doesn't mean it won't happen, right? ;)" ); ?>

-

something goes wrong, you'll see a message and hopefully a way to fix." ); ?>

-

good for you, let it go :)' ); ?>

-

- - - - - - - - "; + default: + case 0: + ?> +

+

backup your database
(you should do this regularly anyway)' ); ?>

+

should happen, but this doesn't mean it won't happen, right? ;)" ); ?>

+

something goes wrong, you'll see a message and hopefully a way to fix." ); ?>

+

good for you, let it go :)' ); ?>

+

+ + + + + + + + "; - break; + break; - case 1: - case 2: - $upgrade = yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ); - break; + case 1: + case 2: + $upgrade = yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ); + break; - case 3: - $upgrade = yourls_upgrade( 3, $oldver, $newver, $oldsql, $newsql ); - echo '

' . yourls__( 'Your installation is now up to date ! ' ) . '

'; - echo '

' . yourls_s( 'Go back to the admin interface', yourls_admin_url('index.php') ) . '

'; - } + case 3: + $upgrade = yourls_upgrade( 3, $oldver, $newver, $oldsql, $newsql ); + echo '

' . yourls__( 'Your installation is now up to date ! ' ) . '

'; + echo '

' . yourls_s( 'Go back to the admin interface', yourls_admin_url('index.php') ) . '

'; + } } diff --git a/composer.json b/composer.json index 53ac504..9dd04fe 100644 --- a/composer.json +++ b/composer.json @@ -29,12 +29,12 @@ "geoip2/geoip2" : "^2.10", "aura/sql": "^5.0 | ^6.0", "jakeasmith/http_build_url": "^1.0", - "platformsh/config-reader": "^3.0", "symfony/polyfill-mbstring": "^1.15", "symfony/polyfill-intl-idn": "^1.17", - "spatie/array-to-xml": "^2.14", + "spatie/array-to-xml": "^3.4", "yourls/seans-qrcode": "dev-develop as 1.x-dev", - "yourls/yourls-saml": "dev-develop as 1.x-dev" + "yourls/yourls-saml": "dev-develop as 1.x-dev", + "platformsh/laravel-bridge": "^1.1" }, "repositories": [ { diff --git a/composer.lock b/composer.lock index 336ed9f..988a797 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e5787f60ad536cc14e43fd0eb078833f", + "content-hash": "58d57b4c8cbf687a308bed29678dcc59", "packages": [ { "name": "aura/sql", @@ -456,16 +456,16 @@ }, { "name": "maxmind/web-service-common", - "version": "v0.11.0", + "version": "v0.11.1", "source": { "type": "git", "url": "https://github.com/maxmind/web-service-common-php.git", - "reference": "5b9e3d3472213361eebdb3ab8879e91b8952091b" + "reference": "c309236b5a5555b96cf560089ec3cead12d845d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/5b9e3d3472213361eebdb3ab8879e91b8952091b", - "reference": "5b9e3d3472213361eebdb3ab8879e91b8952091b", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/c309236b5a5555b96cf560089ec3cead12d845d2", + "reference": "c309236b5a5555b96cf560089ec3cead12d845d2", "shasum": "" }, "require": { @@ -477,7 +477,7 @@ "require-dev": { "friendsofphp/php-cs-fixer": "3.*", "phpstan/phpstan": "*", - "phpunit/phpunit": "^8.0 || ^9.0", + "phpunit/phpunit": "^10.0", "squizlabs/php_codesniffer": "4.*" }, "type": "library", @@ -501,9 +501,9 @@ "homepage": "https://github.com/maxmind/web-service-common-php", "support": { "issues": "https://github.com/maxmind/web-service-common-php/issues", - "source": "https://github.com/maxmind/web-service-common-php/tree/v0.11.0" + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.11.1" }, - "time": "2025-11-20T18:33:17+00:00" + "time": "2026-01-13T17:56:03+00:00" }, { "name": "onelogin/php-saml", @@ -657,6 +657,51 @@ }, "time": "2025-02-25T17:22:15+00:00" }, + { + "name": "platformsh/laravel-bridge", + "version": "1.1", + "source": { + "type": "git", + "url": "https://github.com/platformsh/laravel-bridge.git", + "reference": "9ae82479a36dfb68d2b41bd34f7d3912b929024c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/platformsh/laravel-bridge/zipball/9ae82479a36dfb68d2b41bd34f7d3912b929024c", + "reference": "9ae82479a36dfb68d2b41bd34f7d3912b929024c", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "files": [ + "platformsh-laravel-env.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Larry Garfield", + "email": "larry@platform.sh" + } + ], + "description": "Bridge library for running Symfony Flex on Platform.sh", + "support": { + "issues": "https://github.com/platformsh/laravel-bridge/issues", + "source": "https://github.com/platformsh/laravel-bridge/tree/master" + }, + "time": "2018-10-15T18:09:39+00:00" + }, { "name": "pomo/pomo", "version": "v1.5.0", @@ -905,29 +950,33 @@ }, { "name": "spatie/array-to-xml", - "version": "2.17.1", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "5cbec9c6ab17e320c58a259f0cebe88bde4a7c46" + "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/5cbec9c6ab17e320c58a259f0cebe88bde4a7c46", - "reference": "5cbec9c6ab17e320c58a259f0cebe88bde4a7c46", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/88b2f3852a922dd73177a68938f8eb2ec70c7224", + "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224", "shasum": "" }, "require": { "ext-dom": "*", - "php": "^7.4|^8.0" + "php": "^8.0" }, "require-dev": { "mockery/mockery": "^1.2", "pestphp/pest": "^1.21", - "phpunit/phpunit": "^9.0", "spatie/pest-plugin-snapshots": "^1.1" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, "autoload": { "psr-4": { "Spatie\\ArrayToXml\\": "src" @@ -953,7 +1002,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/2.17.1" + "source": "https://github.com/spatie/array-to-xml/tree/3.4.4" }, "funding": [ { @@ -965,7 +1014,7 @@ "type": "github" } ], - "time": "2022-12-26T08:22:07+00:00" + "time": "2025-12-15T09:00:41+00:00" }, { "name": "symfony/polyfill-intl-idn", diff --git a/css/style.css b/css/style.css index e1d350d..1f10841 100644 --- a/css/style.css +++ b/css/style.css @@ -18,8 +18,6 @@ body { border-right:3px solid #2a85b3; border-bottom:3px solid #2a85b3; border-top:3px solid #2a85b3; - -moz-border-radius:20px; - -webkit-border-radius:20px; border-radius:20px; } .hide-if-no-js {display: none;} @@ -68,8 +66,6 @@ tt { } input, textarea { - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; } Input.text, select, textarea { @@ -129,8 +125,11 @@ tr.edit-row td { td.url small a{ color:#bbc; } -body.desktop td.actions input,body.desktop td.actions a { - visibility:hidden; +/* Hide buttons visually but keep them accessible to screen readers */ +body.desktop td.actions input, body.desktop td.actions a { + opacity: 0; + pointer-events: none; + transition: opacity 0.2s ease; } td.timestamp span.timestamp { display:none; @@ -138,8 +137,20 @@ td.timestamp span.timestamp { td.actions input.disabled, td.actions input.loading { visibility:visible; } +/* Show buttons on row hover */ tr:hover td.actions input, tr:hover td.actions a { - visibility:visible; + opacity: 1; + pointer-events: auto; +} +/* Show buttons when any button in the actions cell receives focus */ +td.actions:focus-within input, td.actions:focus-within a { + opacity: 1; + pointer-events: auto; +} +/* Show all buttons when any element in the row receives focus (for keyboard nav through the entire row) */ +tr:focus-within td.actions input, tr:focus-within td.actions a { + opacity: 1; + pointer-events: auto; } td.actions .button { font-family: Verdana, Arial; @@ -148,8 +159,6 @@ td.actions .button { font-weight: bold; background-color: #FFFFFF; border: 1px solid #88c0eb; - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; cursor:pointer; height:22px; @@ -240,8 +249,6 @@ td.actions .button_stats { } a.bookmarklet { border:2px solid #2a85b3; - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; padding:5px 5px 5px 20px; background:#eef url(../images/favicon.svg) 2px center no-repeat; @@ -262,14 +269,8 @@ a.bookmarklet:hover { background:white; margin:0 auto; max-width:950px; - -moz-border-radius:10px; - -webkit-border-radius:10px; border-radius:10px; border:2px solid #2a85b3; - -moz-border-radius-bottomleft:30px; - -moz-border-radius-bottomright:30px; - -webkit-border-bottom-left-radius:25px; - -webkit-border-bottom-right-radius:25px; border-bottom-left-radius:25px; border-bottom-right-radius:25px; } @@ -281,8 +282,6 @@ a.bookmarklet:hover { .notice { border:1px solid #2a85b3; background: #F3FAFD; - -moz-border-radius:6px; - -webkit-border-radius:6px; border-radius:6px; width:70%; margin-left:15%; @@ -290,7 +289,6 @@ a.bookmarklet:hover { margin-bottom:5px; } - .jquery-notify-bar { width:100%; position:fixed; @@ -305,11 +303,7 @@ a.bookmarklet:hover { padding:20px 0px; border-bottom:1px solid #bbb; filter:alpha(opacity=95); - -moz-opacity:0.95; - -khtml-opacity:0.95; opacity:0.95; - -moz-box-shadow: 0 1px 5px rgba(0,0,0,0.5); - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5); text-shadow: 0 1px 1px rgba(0,0,0,0.1); } .jquery-notify-bar.error ,.jquery-notify-bar.fail { @@ -335,3 +329,59 @@ a.bookmarklet:hover { tr.plugin.active a{ font-weight:bolder;} body.desktop tr.plugin td.plugin_desc small{ visibility:hidden;} tr:hover.plugin td.plugin_desc small{ visibility:visible;} + +#delete-confirm-dialog { + background-color: #ffffff; + width: 50em; + height: 19em; + padding: 0px; + border: 3px solid #2a85b3; + border-radius: 20px; +} +#delete-confirm-dialog > div[name="dialog_title"] { + background-color: #c7e7ff; + font-size: 20px; + color: #026090; + text-align: center; + padding-top: 0.5em; + padding-bottom: 0.5em; + border-start-start-radius: 17px 17px; + border-start-end-radius: 17px 17px; +} +#delete-confirm-dialog div.confirm-message { + background-color: #ffffff; + width: calc(50em - 4em); + height: calc(20em - 50px - 5em - 2em + 6px); + float: none; + text-align: left; + padding: 1em 2em; + overflow: hidden; +} +#delete-confirm-dialog div.confirm-message ul { + border-left: 5px solid #026090; + list-style-type: none; + padding: 0 1em; +} +#delete-confirm-dialog div.confirm-message ul li { + margin-bottom: 0.5em; +} +#delete-confirm-dialog div.confirm-message ul li span { + border: 1px solid #c7e7ff; + border-radius: 3px; + padding: 1px 5px; + color:#333; +} +#delete-confirm-dialog div.button-group { + background-color: #e3f3ff; + width: calc(50em - 4em); + height: 2em; + float: none; + text-align: right; + padding: 1em 2em; + border-end-start-radius: 17px 17px; + border-end-end-radius: 17px 17px; +} +#delete-confirm-dialog::backdrop { + background-color: #666; + opacity: 80%; +} diff --git a/frontend/package.json b/frontend/package.json index 8760a39..72af22b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "sleeky-frontend", - "version": "2.5.0", + "version": "2.6.0", "description": "", "main": "index.js", "scripts": { diff --git a/includes/Database/Options.php b/includes/Database/Options.php index b35224d..f175f08 100644 --- a/includes/Database/Options.php +++ b/includes/Database/Options.php @@ -172,7 +172,7 @@ public function update($name, $newvalue) { // Cache option value to save a DB query if needed later $this->ydb->set_option($name, $newvalue); - yourls_do_action( 'update_option', $name, $oldvalue, $newvalue ); + yourls_do_action( 'update_option', $name, $oldvalue, $newvalue ); return true; } diff --git a/includes/Database/YDB.php b/includes/Database/YDB.php index c3313c3..803f345 100644 --- a/includes/Database/YDB.php +++ b/includes/Database/YDB.php @@ -1,12 +1,12 @@ option, or $ydb->set_option(), use yourls_*_options() functions instead). + * function wrappers (e.g. don't use $ydb->option, or $ydb->set_option(), use yourls_*_options() functions instead). * * @since 1.7.3 */ @@ -33,7 +33,7 @@ class YDB extends ExtendedPdo { protected $context = ''; /** - * Information related to a short URL keyword (eg timestamp, long URL, ...) + * Information related to a short URL keyword (e.g. timestamp, long URL, ...) * * @var array * @@ -53,13 +53,13 @@ class YDB extends ExtendedPdo { protected $option = []; /** - * Plugin admin pages informations + * Plugin admin pages information * @var array */ protected $plugin_pages = []; /** - * Plugin informations + * Plugin information * @var array */ protected $plugins = []; @@ -86,7 +86,7 @@ public function __construct($dsn, $user, $pass, $options) { * Init everything needed * * Everything we need to set up is done here in init(), not in the constructor, so even - * when the connection fails (eg config error or DB dead), the constructor has worked + * when the connection fails (e.g. config error or DB dead), the constructor has worked, * and we have a $ydb object properly instantiated (and for instance yourls_die() can * correctly die, even if using $ydb methods) * @@ -276,7 +276,20 @@ public function get_infos($keyword) { * @return void */ public function delete_infos($keyword) { - unset($this->infos[$keyword]); + if (isset($this->infos[$keyword])) { + unset($this->infos[$keyword]); + } + } + + /** + * @param string $keyword + * @param mixed $infos + * @return void + */ + public function update_infos_if_exists($keyword, $infos) { + if ($this->has_infos($keyword) && $this->infos[$keyword]) { + $this->infos[$keyword] = array_merge($this->infos[$keyword], $infos); + } } /** @@ -405,22 +418,13 @@ public function is_installed() { } /** - * Return standardized DB version - * - * The regex removes everything that's not a number at the start of the string, or remove anything that's not a number and what - * follows after that. - * 'omgmysql-5.5-ubuntu-4.20' => '5.5' - * 'mysql5.5-ubuntu-4.20' => '5.5' - * '5.5-ubuntu-4.20' => '5.5' - * '5.5-beta2' => '5.5' - * '5.5' => '5.5' + * Return MySQL version * * @since 1.7.3 * @return string */ public function mysql_version() { - $version = $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION); - return $version; + return $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION); } } diff --git a/includes/Views/AdminParams.php b/includes/Views/AdminParams.php index 9116fb5..892684d 100644 --- a/includes/Views/AdminParams.php +++ b/includes/Views/AdminParams.php @@ -222,8 +222,15 @@ public function get_click_filter() public function get_click_limit() { // @hook Default link click threshold (unset) - return (!empty($_GET['click_limit']) && intval($_GET['click_limit']) >= 0) ? - intval($_GET['click_limit']) : yourls_apply_filter('admin_view_click_limit', ''); + if ( + isset($_GET['click_limit']) // Exists in the query string + && ($_GET['click_limit'] !== '') // Not empty (&stuff=&click_limit=&otherstuff=) + && intval($_GET['click_limit']) >= 0 // A number >= 0 + ) { + return intval($_GET['click_limit']); + } else { + return yourls_apply_filter('admin_view_click_limit', ''); + } } diff --git a/includes/auth.php b/includes/auth.php index ad9f9a8..be98a87 100644 --- a/includes/auth.php +++ b/includes/auth.php @@ -6,23 +6,23 @@ if( $auth !== true ) { - // API mode, - if ( yourls_is_API() ) { - $format = ( isset($_REQUEST['format']) ? $_REQUEST['format'] : 'xml' ); - $callback = ( isset($_REQUEST['callback']) ? $_REQUEST['callback'] : '' ); - yourls_api_output( $format, array( - 'simple' => $auth, - 'message' => $auth, - 'errorCode' => '403', - 'callback' => $callback, - ) ); - - // Regular mode - } else { - yourls_login_screen( $auth ); - } - - die(); + // API mode, + if ( yourls_is_API() ) { + $format = ( isset($_REQUEST['format']) ? $_REQUEST['format'] : 'xml' ); + $callback = ( isset($_REQUEST['callback']) ? $_REQUEST['callback'] : '' ); + yourls_api_output( $format, array( + 'simple' => $auth, + 'message' => $auth, + 'errorCode' => '403', + 'callback' => $callback, + ) ); + + // Regular mode + } else { + yourls_login_screen( $auth ); + } + + die(); } yourls_do_action( 'auth_successful' ); @@ -36,12 +36,12 @@ // Did we just fail at encrypting passwords ? if ( isset( $_GET['dismiss'] ) && $_GET['dismiss'] == 'hasherror' ) { - yourls_update_option( 'defer_hashing_error', time() + 86400 * 7 ); // now + 1 week + yourls_update_option( 'defer_hashing_error', time() + 86400 * 7 ); // now + 1 week } else { - // Encrypt passwords that are clear text - if ( yourls_maybe_hash_passwords() ) { + // Encrypt passwords that are clear text + if ( yourls_maybe_hash_passwords() ) { $hash = yourls_hash_passwords_now( YOURLS_CONFIGFILE ); if ( $hash === true ) { // Hashing successful. Remove flag from DB if any. @@ -59,5 +59,5 @@ yourls_add_notice( $message ); } } - } + } } diff --git a/includes/class-mysql.php b/includes/class-mysql.php index c25c183..603c87c 100644 --- a/includes/class-mysql.php +++ b/includes/class-mysql.php @@ -4,9 +4,10 @@ * Connect to DB * * @since 1.0 + * @param string $context Optional context. Default: ''. * @return \YOURLS\Database\YDB */ -function yourls_db_connect() { +function yourls_db_connect($context = '') { global $ydb; if ( !defined( 'YOURLS_DB_USER' ) @@ -26,12 +27,12 @@ function yourls_db_connect() { yourls_do_action( 'set_DB_driver', 'deprecated' ); // Get custom port if any - if ( false !== strpos( $dbhost, ':' ) ) { + if (str_contains($dbhost, ':')) { list( $dbhost, $dbport ) = explode( ':', $dbhost ); $dbhost = sprintf( '%1$s;port=%2$d', $dbhost, $dbport ); } - $charset = yourls_apply_filter( 'db_connect_charset', 'utf8mb4' ); + $charset = yourls_apply_filter( 'db_connect_charset', 'utf8mb4', $context ); /** * Data Source Name (dsn) used to connect the DB @@ -42,7 +43,7 @@ function yourls_db_connect() { * 'pgsql:host=192.168.13.37;port=5432;dbname=omgwtf' */ $dsn = sprintf( 'mysql:host=%s;dbname=%s;charset=%s', $dbhost, $dbname, $charset ); - $dsn = yourls_apply_filter( 'db_connect_custom_dsn', $dsn ); + $dsn = yourls_apply_filter( 'db_connect_custom_dsn', $dsn, $context ); /** * PDO driver options and attributes @@ -52,14 +53,18 @@ function yourls_db_connect() { * The driver options are passed to the PDO constructor, eg array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) * The attribute options are then set in a foreach($attr as $k=>$v){$db->setAttribute($k, $v)} loop */ - $driver_options = yourls_apply_filter( 'db_connect_driver_option', [] ); // driver options as key-value pairs - $attributes = yourls_apply_filter( 'db_connect_attributes', [] ); // attributes as key-value pairs + $driver_options = yourls_apply_filter( 'db_connect_driver_option', [], $context ); // driver options as key-value pairs + $attributes = yourls_apply_filter( 'db_connect_attributes', [], $context ); // attributes as key-value pairs $ydb = new \YOURLS\Database\YDB( $dsn, $user, $pass, $driver_options, $attributes ); $ydb->init(); // Past this point, we're connected - yourls_debug_log( sprintf( 'Connected to database %s on %s ', $dbname, $dbhost ) ); + $msg = 'Connected to ' . $dsn; + if ($context !== '') { + $msg .= ', context: ' . $context; + } + yourls_debug_log( $msg ); yourls_debug_mode( YOURLS_DEBUG ); @@ -67,7 +72,7 @@ function yourls_db_connect() { } /** - * Helper function : return instance of the DB + * Helper function: return instance of the DB * * Instead of: * global $ydb; @@ -76,18 +81,46 @@ function yourls_db_connect() { * yourls_get_db()->do_stuff() * * @since 1.7.10 + * @param string $context Optional context. Default: ''. + * If not provided, the function will trigger a notice to encourage developers to provide a context while not + * breaking existing code. A context is a string describing the operation for which the DB is requested. + * Use a naming schema starting with a prefix describing the operation, followed by a short description: + * - Prefix should be either "read-" or "write-", as follows: + * * "read-" for operations that only read from the DB (eg get_keyword_infos) + * * "write-" for operations that write to the DB (eg insert_link_in_db) + * - The description should be lowercase, words separated with underscores, eg "insert_link_in_db". + * Examples: + * - read-fetch_keyword + * - write-insert_link_in_db * @return \YOURLS\Database\YDB */ -function yourls_get_db() { +function yourls_get_db($context = '') { // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_get_db', false ); + $pre = yourls_apply_filter( 'shunt_get_db', false, $context ); if ( false !== $pre ) { return $pre; } + // Validate context and raise notice if missing or malformed + if ($context == '' || !preg_match('/^(read|write)-[a-z0-9_]+$/', $context)) { + $db = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $file = $db[0]['file']; + $line = $db[0]['line']; + + if ($context == '') { + $msg = 'Undefined yourls_get_db() context'; + } else { + $msg = 'Improperly formatted yourls_get_db() context ("' . $context . '")'; + } + + trigger_error( $msg . ' at ' . $file . ':' . $line .'', E_USER_NOTICE ); + } + + yourls_do_action( 'get_db_action', $context ); + global $ydb; - $ydb = ( isset( $ydb ) ) ? $ydb : yourls_db_connect(); - return yourls_apply_filter('get_db', $ydb); + $ydb = ( isset( $ydb ) ) ? $ydb : yourls_db_connect($context); + return yourls_apply_filter('get_db', $ydb, $context); } /** diff --git a/includes/functions-api.php b/includes/functions-api.php index b32f1cc..bd97237 100644 --- a/includes/functions-api.php +++ b/includes/functions-api.php @@ -15,13 +15,13 @@ * @return array Result of API call */ function yourls_api_action_shorturl() { - $url = ( isset( $_REQUEST['url'] ) ? $_REQUEST['url'] : '' ); - $keyword = ( isset( $_REQUEST['keyword'] ) ? $_REQUEST['keyword'] : '' ); - $title = ( isset( $_REQUEST['title'] ) ? $_REQUEST['title'] : '' ); - $return = yourls_add_new_link( $url, $keyword, $title ); - $return['simple'] = ( isset( $return['shorturl'] ) ? $return['shorturl'] : '' ); // This one will be used in case output mode is 'simple' - unset( $return['html'] ); // in API mode, no need for our internal HTML output - return yourls_apply_filter( 'api_result_shorturl', $return ); + $url = ( isset( $_REQUEST['url'] ) ? $_REQUEST['url'] : '' ); + $keyword = ( isset( $_REQUEST['keyword'] ) ? $_REQUEST['keyword'] : '' ); + $title = ( isset( $_REQUEST['title'] ) ? $_REQUEST['title'] : '' ); + $return = yourls_add_new_link( $url, $keyword, $title ); + $return['simple'] = ( isset( $return['shorturl'] ) ? $return['shorturl'] : '' ); // This one will be used in case output mode is 'simple' + unset( $return['html'] ); // in API mode, no need for our internal HTML output + return yourls_apply_filter( 'api_result_shorturl', $return ); } /** @@ -31,10 +31,10 @@ function yourls_api_action_shorturl() { * @return array Result of API call */ function yourls_api_action_stats() { - $filter = ( isset( $_REQUEST['filter'] ) ? $_REQUEST['filter'] : '' ); - $limit = ( isset( $_REQUEST['limit'] ) ? $_REQUEST['limit'] : '' ); - $start = ( isset( $_REQUEST['start'] ) ? $_REQUEST['start'] : '' ); - return yourls_apply_filter( 'api_result_stats', yourls_api_stats( $filter, $limit, $start ) ); + $filter = ( isset( $_REQUEST['filter'] ) ? $_REQUEST['filter'] : '' ); + $limit = ( isset( $_REQUEST['limit'] ) ? $_REQUEST['limit'] : '' ); + $start = ( isset( $_REQUEST['start'] ) ? $_REQUEST['start'] : '' ); + return yourls_apply_filter( 'api_result_stats', yourls_api_stats( $filter, $limit, $start ) ); } /** @@ -44,7 +44,7 @@ function yourls_api_action_stats() { * @return array Result of API call */ function yourls_api_action_db_stats() { - return yourls_apply_filter( 'api_result_db_stats', yourls_api_db_stats() ); + return yourls_apply_filter( 'api_result_db_stats', yourls_api_db_stats() ); } /** @@ -54,8 +54,8 @@ function yourls_api_action_db_stats() { * @return array Result of API call */ function yourls_api_action_url_stats() { - $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); - return yourls_apply_filter( 'api_result_url_stats', yourls_api_url_stats( $shorturl ) ); + $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); + return yourls_apply_filter( 'api_result_url_stats', yourls_api_url_stats( $shorturl ) ); } /** @@ -65,8 +65,8 @@ function yourls_api_action_url_stats() { * @return array Result of API call */ function yourls_api_action_expand() { - $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); - return yourls_apply_filter( 'api_result_expand', yourls_api_expand( $shorturl ) ); + $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); + return yourls_apply_filter( 'api_result_expand', yourls_api_expand( $shorturl ) ); } /** @@ -76,10 +76,10 @@ function yourls_api_action_expand() { * @return array Result of API call */ function yourls_api_action_version() { - $return['version'] = $return['simple'] = YOURLS_VERSION; - if( isset( $_REQUEST['db'] ) && $_REQUEST['db'] == 1 ) - $return['db_version'] = YOURLS_DB_VERSION; - return yourls_apply_filter( 'api_result_version', $return ); + $return['version'] = $return['simple'] = YOURLS_VERSION; + if( isset( $_REQUEST['db'] ) && $_REQUEST['db'] == 1 ) + $return['db_version'] = YOURLS_DB_VERSION; + return yourls_apply_filter( 'api_result_version', $return ); } /** @@ -99,12 +99,12 @@ function yourls_api_action_version() { * @return string API output, as an XML / JSON / JSONP / raw text string */ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) { - if( isset( $output['simple'] ) ) { - $simple = $output['simple']; - unset( $output['simple'] ); - } + if( isset( $output['simple'] ) ) { + $simple = $output['simple']; + unset( $output['simple'] ); + } - yourls_do_action( 'pre_api_output', $mode, $output, $send_headers, $echo ); + yourls_do_action( 'pre_api_output', $mode, $output, $send_headers, $echo ); if( $send_headers ) { if( isset( $output['statusCode'] ) ) { @@ -119,43 +119,49 @@ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) $result = ''; - switch ( $mode ) { - case 'jsonp': + switch ( $mode ) { + case 'jsonp': if( $send_headers ) yourls_content_type_header( 'application/javascript' ); - $callback = isset( $output['callback'] ) ? $output['callback'] : ''; - $result = $callback . '(' . json_encode( $output ) . ')'; - break; + $callback = isset( $output['callback'] ) ? yourls_validate_jsonp_callback($output['callback'] ) : ''; + if( $callback === false ) { + yourls_status_header( 400 ); + $result = json_encode( ['errorCode' => '400', 'error' => 'Invalid callback parameter'] ); + } else { + $result = $callback . '(' . json_encode( $output ) . ')'; + } + + break; - case 'json': + case 'json': if( $send_headers ) yourls_content_type_header( 'application/json' ); - $result = json_encode( $output ); - break; + $result = json_encode( $output ); + break; - case 'xml': + case 'xml': if( $send_headers ) yourls_content_type_header( 'application/xml' ); - $result = yourls_xml_encode( $output ); - break; + $result = yourls_xml_encode( $output ); + break; - case 'simple': - default: + case 'simple': + default: if( $send_headers ) yourls_content_type_header( 'text/plain' ); - $result = isset( $simple ) ? $simple : ''; - break; - } + $result = isset( $simple ) ? $simple : ''; + break; + } if( $echo ) { echo $result; } - yourls_do_action( 'api_output', $mode, $output, $send_headers, $echo ); + yourls_do_action( 'api_output', $mode, $output, $send_headers, $echo ); return $result; } @@ -169,10 +175,10 @@ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) * @return array */ function yourls_api_stats($filter = 'top', $limit = 10, $start = 0 ) { - $return = yourls_get_stats( $filter, $limit, $start ); - $return['simple'] = 'Need either XML or JSON format for stats'; - $return['message'] = 'success'; - return yourls_apply_filter( 'api_stats', $return, $filter, $limit, $start ); + $return = yourls_get_stats( $filter, $limit, $start ); + $return['simple'] = 'Need either XML or JSON format for stats'; + $return['message'] = 'success'; + return yourls_apply_filter( 'api_stats', $return, $filter, $limit, $start ); } /** @@ -181,14 +187,14 @@ function yourls_api_stats($filter = 'top', $limit = 10, $start = 0 ) { * @return array */ function yourls_api_db_stats() { - $return = array( - 'db-stats' => yourls_get_db_stats(), - 'statusCode' => '200', - 'simple' => 'Need either XML or JSON format for stats', - 'message' => 'success', - ); - - return yourls_apply_filter( 'api_db_stats', $return ); + $return = array( + 'db-stats' => yourls_get_db_stats(), + 'statusCode' => '200', + 'simple' => 'Need either XML or JSON format for stats', + 'message' => 'success', + ); + + return yourls_apply_filter( 'api_db_stats', $return ); } /** @@ -198,12 +204,12 @@ function yourls_api_db_stats() { * @return array */ function yourls_api_url_stats( $shorturl ) { - $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' - $keyword = yourls_sanitize_keyword( $keyword ); + $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' + $keyword = yourls_sanitize_keyword( $keyword ); - $return = yourls_get_keyword_stats( $keyword ); - $return['simple'] = 'Need either XML or JSON format for stats'; - return yourls_apply_filter( 'api_url_stats', $return, $shorturl ); + $return = yourls_get_keyword_stats( $keyword ); + $return['simple'] = 'Need either XML or JSON format for stats'; + return yourls_apply_filter( 'api_url_stats', $return, $shorturl ); } /** @@ -213,29 +219,29 @@ function yourls_api_url_stats( $shorturl ) { * @return array */ function yourls_api_expand( $shorturl ) { - $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' - $keyword = yourls_sanitize_keyword( $keyword ); + $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' + $keyword = yourls_sanitize_keyword( $keyword ); - $longurl = yourls_get_keyword_longurl( $keyword ); + $longurl = yourls_get_keyword_longurl( $keyword ); - if( $longurl ) { - $return = array( - 'keyword' => $keyword, - 'shorturl' => yourls_link($keyword), - 'longurl' => $longurl, + if( $longurl ) { + $return = array( + 'keyword' => $keyword, + 'shorturl' => yourls_link($keyword), + 'longurl' => $longurl, 'title' => yourls_get_keyword_title( $keyword ), - 'simple' => $longurl, - 'message' => 'success', - 'statusCode' => '200', - ); - } else { - $return = array( - 'keyword' => $keyword, - 'simple' => 'not found', - 'message' => 'Error: short URL not found', - 'errorCode' => '404', - ); - } - - return yourls_apply_filter( 'api_expand', $return, $shorturl ); + 'simple' => $longurl, + 'message' => 'success', + 'statusCode' => '200', + ); + } else { + $return = array( + 'keyword' => $keyword, + 'simple' => 'not found', + 'message' => 'Error: short URL not found', + 'errorCode' => '404', + ); + } + + return yourls_apply_filter( 'api_expand', $return, $shorturl ); } diff --git a/includes/functions-auth.php b/includes/functions-auth.php index f074c21..cadf538 100644 --- a/includes/functions-auth.php +++ b/includes/functions-auth.php @@ -10,12 +10,12 @@ * @return void */ function yourls_maybe_require_auth() { - if( yourls_is_private() ) { - yourls_do_action( 'require_auth' ); - require_once( YOURLS_INC.'/auth.php' ); - } else { - yourls_do_action( 'require_no_auth' ); - } + if( yourls_is_private() ) { + yourls_do_action( 'require_auth' ); + require_once( YOURLS_INC.'/auth.php' ); + } else { + yourls_do_action( 'require_no_auth' ); + } } /** @@ -24,102 +24,102 @@ function yourls_maybe_require_auth() { * @return bool|string|mixed true if valid user, error message otherwise. Can also call yourls_die() or redirect to login page. Oh my. */ function yourls_is_valid_user() { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_is_valid_user', null ); - if ( null !== $pre ) { - return $pre; - } + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_is_valid_user', null ); + if ( null !== $pre ) { + return $pre; + } - // $unfiltered_valid : are credentials valid? Boolean value. It's "unfiltered" to allow plugins to eventually filter it. - $unfiltered_valid = false; + // $unfiltered_valid : are credentials valid? Boolean value. It's "unfiltered" to allow plugins to eventually filter it. + $unfiltered_valid = false; - // Logout request - if( isset( $_GET['action'] ) && $_GET['action'] == 'logout' && isset( $_REQUEST['nonce'] ) ) { + // Logout request + if( isset( $_GET['action'] ) && $_GET['action'] == 'logout' && isset( $_REQUEST['nonce'] ) ) { // The logout nonce is associated to fake user 'logout' since at this point we don't know the real user yourls_verify_nonce('admin_logout', $_REQUEST['nonce'], 'logout'); - yourls_do_action( 'logout' ); - yourls_store_cookie( '' ); - return yourls__( 'Logged out successfully' ); - } - - // Check cookies or login request. Login form has precedence. - - yourls_do_action( 'pre_login' ); - - // Determine auth method and check credentials - if - // API only: Secure (no login or pwd) and time limited token - // ?timestamp=12345678&signature=md5(totoblah12345678) - ( yourls_is_API() && - isset( $_REQUEST['timestamp'] ) && !empty($_REQUEST['timestamp'] ) && - isset( $_REQUEST['signature'] ) && !empty($_REQUEST['signature'] ) - ) - { - yourls_do_action( 'pre_login_signature_timestamp' ); - $unfiltered_valid = yourls_check_signature_timestamp(); - } - - elseif - // API only: Secure (no login or pwd) - // ?signature=md5(totoblah) - ( yourls_is_API() && - !isset( $_REQUEST['timestamp'] ) && - isset( $_REQUEST['signature'] ) && !empty( $_REQUEST['signature'] ) - ) - { - yourls_do_action( 'pre_login_signature' ); - $unfiltered_valid = yourls_check_signature(); - } - - elseif - // API or normal: login with username & pwd - ( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) - && !empty( $_REQUEST['username'] ) && !empty( $_REQUEST['password'] ) ) - { - yourls_do_action( 'pre_login_username_password' ); - $unfiltered_valid = yourls_check_username_password(); - } - - elseif - // Normal only: cookies - ( !yourls_is_API() && - isset( $_COOKIE[ yourls_cookie_name() ] ) ) - { - yourls_do_action( 'pre_login_cookie' ); - $unfiltered_valid = yourls_check_auth_cookie(); - } - - // Regardless of validity, allow plugins to filter the boolean and have final word - $valid = yourls_apply_filter( 'is_valid_user', $unfiltered_valid ); - - // Login for the win! - if ( $valid ) { - yourls_do_action( 'login' ); - - // (Re)store encrypted cookie if needed - if ( !yourls_is_API() ) { - yourls_store_cookie( YOURLS_USER ); - - // Login form : redirect to requested URL to avoid re-submitting the login form on page reload - if( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) && isset( $_SERVER['REQUEST_URI'] ) ) { - // The return makes sure we exit this function before waiting for redirection. + yourls_do_action( 'logout' ); + yourls_store_cookie( '' ); + return yourls__( 'Logged out successfully' ); + } + + // Check cookies or login request. Login form has precedence. + + yourls_do_action( 'pre_login' ); + + // Determine auth method and check credentials + if + // API only: Secure (no login or pwd) and time limited token + // ?timestamp=12345678&signature=md5(totoblah12345678) + ( yourls_is_API() && + isset( $_REQUEST['timestamp'] ) && !empty($_REQUEST['timestamp'] ) && + isset( $_REQUEST['signature'] ) && !empty($_REQUEST['signature'] ) + ) + { + yourls_do_action( 'pre_login_signature_timestamp' ); + $unfiltered_valid = yourls_check_signature_timestamp(); + } + + elseif + // API only: Secure (no login or pwd) + // ?signature=md5(totoblah) + ( yourls_is_API() && + !isset( $_REQUEST['timestamp'] ) && + isset( $_REQUEST['signature'] ) && !empty( $_REQUEST['signature'] ) + ) + { + yourls_do_action( 'pre_login_signature' ); + $unfiltered_valid = yourls_check_signature(); + } + + elseif + // API or normal: login with username & pwd + ( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) + && !empty( $_REQUEST['username'] ) && !empty( $_REQUEST['password'] ) ) + { + yourls_do_action( 'pre_login_username_password' ); + $unfiltered_valid = yourls_check_username_password(); + } + + elseif + // Normal only: cookies + ( !yourls_is_API() && + isset( $_COOKIE[ yourls_cookie_name() ] ) ) + { + yourls_do_action( 'pre_login_cookie' ); + $unfiltered_valid = yourls_check_auth_cookie(); + } + + // Regardless of validity, allow plugins to filter the boolean and have final word + $valid = yourls_apply_filter( 'is_valid_user', $unfiltered_valid ); + + // Login for the win! + if ( $valid ) { + yourls_do_action( 'login' ); + + // (Re)store encrypted cookie if needed + if ( !yourls_is_API() ) { + yourls_store_cookie( YOURLS_USER ); + + // Login form : redirect to requested URL to avoid re-submitting the login form on page reload + if( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) && isset( $_SERVER['REQUEST_URI'] ) ) { + // The return makes sure we exit this function before waiting for redirection. // See #3189 and note in yourls_redirect() - return yourls_redirect( yourls_sanitize_url_safe($_SERVER['REQUEST_URI']) ); - } - } + return yourls_redirect( yourls_sanitize_url_safe($_SERVER['REQUEST_URI']) ); + } + } - // Login successful - return true; - } + // Login successful + return true; + } - // Login failed - yourls_do_action( 'login_failed' ); + // Login failed + yourls_do_action( 'login_failed' ); - if ( isset( $_REQUEST['username'] ) || isset( $_REQUEST['password'] ) ) { - return yourls__( 'Invalid username or password' ); - } else { - return yourls__( 'Please log in' ); - } + if ( isset( $_REQUEST['username'] ) || isset( $_REQUEST['password'] ) ) { + return yourls__( 'Invalid username or password' ); + } else { + return yourls__( 'Please log in' ); + } } /** @@ -128,18 +128,18 @@ function yourls_is_valid_user() { * @return bool true if login/pwd pair is valid (and sets user if applicable), false otherwise */ function yourls_check_username_password() { - global $yourls_user_passwords; + global $yourls_user_passwords; - // If login form (not API), check for nonce + // If login form (not API), check for nonce if(!yourls_is_API()) { yourls_verify_nonce('admin_login'); } - if( isset( $yourls_user_passwords[ $_REQUEST['username'] ] ) && yourls_check_password_hash( $_REQUEST['username'], $_REQUEST['password'] ) ) { - yourls_set_user( $_REQUEST['username'] ); - return true; - } - return false; + if( isset( $yourls_user_passwords[ $_REQUEST['username'] ] ) && yourls_check_password_hash( $_REQUEST['username'], $_REQUEST['password'] ) ) { + yourls_set_user( $_REQUEST['username'] ); + return true; + } + return false; } /** @@ -150,24 +150,24 @@ function yourls_check_username_password() { * @return bool */ function yourls_check_password_hash($user, $submitted_password ) { - global $yourls_user_passwords; + global $yourls_user_passwords; - if( !isset( $yourls_user_passwords[ $user ] ) ) - return false; + if( !isset( $yourls_user_passwords[ $user ] ) ) + return false; - if ( yourls_has_phpass_password( $user ) ) { - // Stored password is hashed - list( , $hash ) = explode( ':', $yourls_user_passwords[ $user ] ); - $hash = str_replace( '!', '$', $hash ); - return ( yourls_phpass_check( $submitted_password, $hash ) ); - } else if( yourls_has_md5_password( $user ) ) { - // Stored password is a salted md5 hash: "md5:<$r = rand(10000,99999)>:" - list( , $salt, ) = explode( ':', $yourls_user_passwords[ $user ] ); - return( $yourls_user_passwords[ $user ] == 'md5:'.$salt.':'.md5( $salt . $submitted_password ) ); - } else { - // Password stored in clear text - return( $yourls_user_passwords[ $user ] === $submitted_password ); - } + if ( yourls_has_phpass_password( $user ) ) { + // Stored password is hashed + list( , $hash ) = explode( ':', $yourls_user_passwords[ $user ] ); + $hash = str_replace( '!', '$', $hash ); + return ( yourls_phpass_check( $submitted_password, $hash ) ); + } else if( yourls_has_md5_password( $user ) ) { + // Stored password is a salted md5 hash: "md5:<$r = rand(10000,99999)>:" + list( , $salt, ) = explode( ':', $yourls_user_passwords[ $user ] ); + return( $yourls_user_passwords[ $user ] == 'md5:'.$salt.':'.md5( $salt . $submitted_password ) ); + } else { + // Password stored in clear text + return( $yourls_user_passwords[ $user ] === $submitted_password ); + } } /** @@ -178,66 +178,66 @@ function yourls_check_password_hash($user, $submitted_password ) { * @return true|string if overwrite was successful, an error message otherwise */ function yourls_hash_passwords_now( $config_file ) { - if( !is_readable( $config_file ) ) { + if( !is_readable( $config_file ) ) { yourls_debug_log( 'Cannot hash passwords: cannot read file ' . $config_file ); return 'cannot read file'; // not sure that can actually happen... } - if( !is_writable( $config_file ) ) { + if( !is_writable( $config_file ) ) { yourls_debug_log( 'Cannot hash passwords: cannot write file ' . $config_file ); - return 'cannot write file'; + return 'cannot write file'; } $yourls_user_passwords = []; - // Include file to read value of $yourls_user_passwords - // Temporary suppress error reporting to avoid notices about redeclared constants - $errlevel = error_reporting(); - error_reporting( 0 ); - require $config_file; - error_reporting( $errlevel ); + // Include file to read value of $yourls_user_passwords + // Temporary suppress error reporting to avoid notices about redeclared constants + $errlevel = error_reporting(); + error_reporting( 0 ); + require $config_file; + error_reporting( $errlevel ); - $configdata = file_get_contents( $config_file ); + $configdata = file_get_contents( $config_file ); if( $configdata == false ) { yourls_debug_log('Cannot hash passwords: file_get_contents() false with ' . $config_file); return 'could not read file'; } - $to_hash = 0; // keep track of number of passwords that need hashing - foreach ( $yourls_user_passwords as $user => $password ) { + $to_hash = 0; // keep track of number of passwords that need hashing + foreach ( $yourls_user_passwords as $user => $password ) { // avoid "deprecated" warning when password is null -- see test case in tests/data/auth/preg_replace_problem.php $password ??= ''; - if ( !yourls_has_phpass_password( $user ) && !yourls_has_md5_password( $user ) ) { - $to_hash++; - $hash = yourls_phpass_hash( $password ); - // PHP would interpret $ as a variable, so replace it in storage. - $hash = str_replace( '$', '!', $hash ); - $quotes = "'" . '"'; - $pattern = "/[$quotes]" . preg_quote( $user, '/' ) . "[$quotes]\s*=>\s*[$quotes]" . preg_quote( $password, '/' ) . "[$quotes]/"; - $replace = "'$user' => 'phpass:$hash' /* Password encrypted by YOURLS */ "; - $count = 0; - $configdata = preg_replace( $pattern, $replace, $configdata, -1, $count ); - // There should be exactly one replacement. Otherwise, fast fail. - if ( $count != 1 ) { - yourls_debug_log( "Problem with preg_replace for password hash of user $user" ); - return 'preg_replace problem'; - } - } - } - - if( $to_hash == 0 ) { + if ( !yourls_has_phpass_password( $user ) && !yourls_has_md5_password( $user ) ) { + $to_hash++; + $hash = yourls_phpass_hash( $password ); + // PHP would interpret $ as a variable, so replace it in storage. + $hash = str_replace( '$', '!', $hash ); + $quotes = "'" . '"'; + $pattern = "/[$quotes]" . preg_quote( $user, '/' ) . "[$quotes]\s*=>\s*[$quotes]" . preg_quote( $password, '/' ) . "[$quotes]/"; + $replace = "'$user' => 'phpass:$hash' /* Password encrypted by YOURLS */ "; + $count = 0; + $configdata = preg_replace( $pattern, $replace, $configdata, -1, $count ); + // There should be exactly one replacement. Otherwise, fast fail. + if ( $count != 1 ) { + yourls_debug_log( "Problem with preg_replace for password hash of user $user" ); + return 'preg_replace problem'; + } + } + } + + if( $to_hash == 0 ) { yourls_debug_log('Cannot hash passwords: no password found in ' . $config_file); return 'no password found'; } - $success = file_put_contents( $config_file, $configdata ); - if ( $success === FALSE ) { - yourls_debug_log( 'Failed writing to ' . $config_file ); - return 'could not write file'; - } + $success = file_put_contents( $config_file, $configdata ); + if ( $success === FALSE ) { + yourls_debug_log( 'Failed writing to ' . $config_file ); + return 'could not write file'; + } yourls_debug_log('Successfully encrypted passwords in ' . basename($config_file)); - return true; + return true; } /** @@ -277,7 +277,7 @@ function yourls_phpass_hash( $password ) { * @return bool true if the hash matches the password, false otherwise */ function yourls_phpass_check( $password, $hash ) { - return password_verify($password, $hash); + return password_verify($password, $hash); } @@ -288,13 +288,13 @@ function yourls_phpass_check( $password, $hash ) { * @return bool true if any passwords are cleartext */ function yourls_has_cleartext_passwords() { - global $yourls_user_passwords; - foreach ( $yourls_user_passwords as $user => $pwdata ) { - if ( !yourls_has_md5_password( $user ) && !yourls_has_phpass_password( $user ) ) { - return true; - } - } - return false; + global $yourls_user_passwords; + foreach ( $yourls_user_passwords as $user => $pwdata ) { + if ( !yourls_has_md5_password( $user ) && !yourls_has_phpass_password( $user ) ) { + return true; + } + } + return false; } /** @@ -308,11 +308,11 @@ function yourls_has_cleartext_passwords() { * @return bool true if password hashed, false otherwise */ function yourls_has_md5_password( $user ) { - global $yourls_user_passwords; - return( isset( $yourls_user_passwords[ $user ] ) - && substr( $yourls_user_passwords[ $user ], 0, 4 ) == 'md5:' - && strlen( $yourls_user_passwords[ $user ] ) == 42 // http://www.google.com/search?q=the+answer+to+life+the+universe+and+everything - ); + global $yourls_user_passwords; + return( isset( $yourls_user_passwords[ $user ] ) + && substr( $yourls_user_passwords[ $user ], 0, 4 ) == 'md5:' + && strlen( $yourls_user_passwords[ $user ] ) == 42 // http://www.google.com/search?q=the+answer+to+life+the+universe+and+everything + ); } /** @@ -327,10 +327,10 @@ function yourls_has_md5_password( $user ) { * @return bool true if password hashed with password_hash, otherwise false */ function yourls_has_phpass_password( $user ) { - global $yourls_user_passwords; - return( isset( $yourls_user_passwords[ $user ] ) - && substr( $yourls_user_passwords[ $user ], 0, 7 ) == 'phpass:' - ); + global $yourls_user_passwords; + return( isset( $yourls_user_passwords[ $user ] ) + && substr( $yourls_user_passwords[ $user ], 0, 7 ) == 'phpass:' + ); } /** @@ -339,14 +339,14 @@ function yourls_has_phpass_password( $user ) { * @return bool true if authenticated, false otherwise */ function yourls_check_auth_cookie() { - global $yourls_user_passwords; - foreach( $yourls_user_passwords as $valid_user => $valid_password ) { - if ( yourls_cookie_value( $valid_user ) === $_COOKIE[ yourls_cookie_name() ] ) { - yourls_set_user( $valid_user ); - return true; - } - } - return false; + global $yourls_user_passwords; + foreach( $yourls_user_passwords as $valid_user => $valid_password ) { + if ( yourls_cookie_value( $valid_user ) === $_COOKIE[ yourls_cookie_name() ] ) { + yourls_set_user( $valid_user ); + return true; + } + } + return false; } /** @@ -380,21 +380,21 @@ function yourls_check_signature_timestamp() { return false; } - // Check signature & timestamp against all possible users - global $yourls_user_passwords; - foreach( $yourls_user_passwords as $valid_user => $valid_password ) { - if ( + // Check signature & timestamp against all possible users + global $yourls_user_passwords; + foreach( $yourls_user_passwords as $valid_user => $valid_password ) { + if ( hash( $hash_function, $_REQUEST['timestamp'].yourls_auth_signature( $valid_user ) ) === $_REQUEST['signature'] or hash( $hash_function, yourls_auth_signature( $valid_user ).$_REQUEST['timestamp'] ) === $_REQUEST['signature'] - ) { - yourls_set_user( $valid_user ); - return true; - } - } + ) { + yourls_set_user( $valid_user ); + return true; + } + } // Signature doesn't match known user - return false; + return false; } /** @@ -407,17 +407,17 @@ function yourls_check_signature() { if( !isset( $_REQUEST['signature'] ) OR empty( $_REQUEST['signature'] ) ) return false; - // Check signature against all possible users + // Check signature against all possible users global $yourls_user_passwords; - foreach( $yourls_user_passwords as $valid_user => $valid_password ) { - if ( yourls_auth_signature( $valid_user ) === $_REQUEST['signature'] ) { - yourls_set_user( $valid_user ); - return true; - } - } + foreach( $yourls_user_passwords as $valid_user => $valid_password ) { + if ( yourls_auth_signature( $valid_user ) === $_REQUEST['signature'] ) { + yourls_set_user( $valid_user ); + return true; + } + } // Signature doesn't match known user - return false; + return false; } /** @@ -427,10 +427,10 @@ function yourls_check_signature() { * @return string Signature */ function yourls_auth_signature( $username = false ) { - if( !$username && defined('YOURLS_USER') ) { - $username = YOURLS_USER; - } - return ( $username ? substr( yourls_salt( $username ), 0, 10 ) : 'Cannot generate auth signature: no username' ); + if( !$username && defined('YOURLS_USER') ) { + $username = YOURLS_USER; + } + return ( $username ? substr( yourls_salt( $username ), 0, 10 ) : 'Cannot generate auth signature: no username' ); } /** @@ -440,9 +440,9 @@ function yourls_auth_signature( $username = false ) { * @return bool True if timestamp is valid */ function yourls_check_timestamp( $time ) { - $now = time(); - // Allow timestamp to be a little in the future or the past -- see Issue 766 - return yourls_apply_filter( 'check_timestamp', abs( $now - (int)$time ) < yourls_get_nonce_life(), $time ); + $now = time(); + // Allow timestamp to be a little in the future or the past -- see Issue 766 + return yourls_apply_filter( 'check_timestamp', abs( $now - (int)$time ) < yourls_get_nonce_life(), $time ); } /** @@ -454,30 +454,30 @@ function yourls_check_timestamp( $time ) { function yourls_store_cookie( $user = '' ) { // No user will delete the cookie with a cookie time from the past - if( !$user ) { - $time = time() - 3600; - } else { - $time = time() + yourls_get_cookie_life(); - } + if( !$user ) { + $time = time() - 3600; + } else { + $time = time() + yourls_get_cookie_life(); + } $path = yourls_apply_filter( 'setcookie_path', '/' ); - $domain = yourls_apply_filter( 'setcookie_domain', parse_url( yourls_get_yourls_site(), PHP_URL_HOST ) ); - $secure = yourls_apply_filter( 'setcookie_secure', yourls_is_ssl() ); - $httponly = yourls_apply_filter( 'setcookie_httponly', true ); + $domain = yourls_apply_filter( 'setcookie_domain', parse_url( yourls_get_yourls_site(), PHP_URL_HOST ) ); + $secure = yourls_apply_filter( 'setcookie_secure', yourls_is_ssl() ); + $httponly = yourls_apply_filter( 'setcookie_httponly', true ); - // Some browsers refuse to store localhost cookie - if ( $domain == 'localhost' ) - $domain = ''; + // Some browsers refuse to store localhost cookie + if ( $domain == 'localhost' ) + $domain = ''; - yourls_do_action( 'pre_setcookie', $user, $time, $path, $domain, $secure, $httponly ); + yourls_do_action( 'pre_setcookie', $user, $time, $path, $domain, $secure, $httponly ); if ( !headers_sent( $filename, $linenum ) ) { yourls_setcookie( yourls_cookie_name(), yourls_cookie_value( $user ), $time, $path, $domain, $secure, $httponly ); - } else { - // For some reason cookies were not stored: action to be able to debug that - yourls_do_action( 'setcookie_failed', $user ); + } else { + // For some reason cookies were not stored: action to be able to debug that + yourls_do_action( 'setcookie_failed', $user ); yourls_debug_log( "Could not store cookie: headers already sent in $filename on line $linenum" ); - } + } } /** @@ -517,8 +517,8 @@ function yourls_setcookie($name, $value, $expire, $path, $domain, $secure, $http * @return void */ function yourls_set_user( $user ) { - if( !defined( 'YOURLS_USER' ) ) - define( 'YOURLS_USER', $user ); + if( !defined( 'YOURLS_USER' ) ) + define( 'YOURLS_USER', $user ); } /** @@ -532,7 +532,7 @@ function yourls_set_user( $user ) { * @return integer cookie life span, in seconds */ function yourls_get_cookie_life() { - return yourls_apply_filter( 'get_cookie_life', YOURLS_COOKIE_LIFE ); + return yourls_apply_filter( 'get_cookie_life', YOURLS_COOKIE_LIFE ); } /** @@ -547,7 +547,7 @@ function yourls_get_cookie_life() { * @return integer nonce life span, in seconds */ function yourls_get_nonce_life() { - return yourls_apply_filter( 'get_nonce_life', YOURLS_NONCE_LIFE ); + return yourls_apply_filter( 'get_nonce_life', YOURLS_NONCE_LIFE ); } /** @@ -572,7 +572,7 @@ function yourls_cookie_name() { * @return string cookie value */ function yourls_cookie_value( $user ) { - return yourls_apply_filter( 'set_cookie_value', yourls_salt( $user ?? '' ), $user ); + return yourls_apply_filter( 'set_cookie_value', yourls_salt( $user ?? '' ), $user ); } /** @@ -583,7 +583,7 @@ function yourls_cookie_value( $user ) { * @return float */ function yourls_tick() { - return ceil( time() / yourls_get_nonce_life() ); + return ceil( time() / yourls_get_nonce_life() ); } /** @@ -596,8 +596,8 @@ function yourls_tick() { * @return string hashed string */ function yourls_salt( $string ) { - $salt = defined('YOURLS_COOKIEKEY') ? YOURLS_COOKIEKEY : md5(__FILE__) ; - return yourls_apply_filter( 'yourls_salt', hash_hmac( yourls_hmac_algo(), $string, $salt), $string ); + $salt = defined('YOURLS_COOKIEKEY') ? YOURLS_COOKIEKEY : md5(__FILE__) ; + return yourls_apply_filter( 'yourls_salt', hash_hmac( yourls_hmac_algo(), $string, $salt), $string ); } /** @@ -622,13 +622,13 @@ function yourls_hmac_algo() { * @return string Nonce token */ function yourls_create_nonce($action, $user = false ) { - if( false === $user ) { + if( false === $user ) { $user = defined('YOURLS_USER') ? YOURLS_USER : '-1'; } - $tick = yourls_tick(); - $nonce = substr( yourls_salt($tick . $action . $user), 0, 10 ); - // Allow plugins to alter the nonce - return yourls_apply_filter( 'create_nonce', $nonce, $action, $user ); + $tick = yourls_tick(); + $nonce = substr( yourls_salt($tick . $action . $user), 0, 10 ); + // Allow plugins to alter the nonce + return yourls_apply_filter( 'create_nonce', $nonce, $action, $user ); } /** @@ -641,10 +641,10 @@ function yourls_create_nonce($action, $user = false ) { * @return string Nonce field */ function yourls_nonce_field($action, $name = 'nonce', $user = false, $echo = true ) { - $field = ''; - if( $echo ) - echo $field."\n"; - return $field; + $field = ''; + if( $echo ) + echo $field."\n"; + return $field; } /** @@ -657,8 +657,8 @@ function yourls_nonce_field($action, $name = 'nonce', $user = false, $echo = tru * @return string URL with nonce added */ function yourls_nonce_url($action, $url = false, $name = 'nonce', $user = false ) { - $nonce = yourls_create_nonce( $action, $user ); - return yourls_add_query_arg( $name, $nonce, $url ); + $nonce = yourls_create_nonce( $action, $user ); + return yourls_add_query_arg( $name, $nonce, $url ); } /** @@ -674,31 +674,31 @@ function yourls_nonce_url($action, $url = false, $name = 'nonce', $user = false * @return bool|void True if valid, dies otherwise */ function yourls_verify_nonce($action, $nonce = false, $user = false, $return = '' ) { - // Get user - if( false === $user ) { + // Get user + if( false === $user ) { $user = defined('YOURLS_USER') ? YOURLS_USER : '-1'; } - // Get nonce value from $_REQUEST if not specified - if( false === $nonce && isset( $_REQUEST['nonce'] ) ) { + // Get nonce value from $_REQUEST if not specified + if( false === $nonce && isset( $_REQUEST['nonce'] ) ) { $nonce = $_REQUEST['nonce']; } - // Allow plugins to short-circuit the rest of the function - if (yourls_apply_filter( 'verify_nonce', false, $action, $nonce, $user, $return ) === true) { - return true; - } + // Allow plugins to short-circuit the rest of the function + if (yourls_apply_filter( 'verify_nonce', false, $action, $nonce, $user, $return ) === true) { + return true; + } - // What nonce should be - $valid = yourls_create_nonce( $action, $user ); + // What nonce should be + $valid = yourls_create_nonce( $action, $user ); - if( $nonce === $valid ) { - return true; - } else { - if( $return ) - die( $return ); - yourls_die( yourls__( 'Unauthorized action or expired link' ), yourls__( 'Error' ), 403 ); - } + if( $nonce === $valid ) { + return true; + } else { + if( $return ) + die( $return ); + yourls_die( yourls__( 'Unauthorized action or expired link' ), yourls__( 'Error' ), 403 ); + } } /** @@ -708,7 +708,7 @@ function yourls_verify_nonce($action, $nonce = false, $user = false, $return = ' * @return bool true if YOURLS_USER and YOURLS_PASSWORD are defined as environment variables */ function yourls_is_user_from_env() { - return yourls_apply_filter('is_user_from_env', getenv('YOURLS_USER') && getenv('YOURLS_PASSWORD')); + return yourls_apply_filter('is_user_from_env', getenv('YOURLS_USER') && getenv('YOURLS_PASSWORD')); } diff --git a/includes/functions-compat.php b/includes/functions-compat.php index 4bc1330..2dc17d3 100644 --- a/includes/functions-compat.php +++ b/includes/functions-compat.php @@ -11,9 +11,9 @@ * */ if( !function_exists( 'json_encode' ) ) { - function json_encode( $array ) { - return yourls_array_to_json( $array ); - } + function json_encode( $array ) { + return yourls_array_to_json( $array ); + } } /** @@ -26,60 +26,60 @@ function json_encode( $array ) { */ function yourls_array_to_json( $array ){ - if( !is_array( $array ) ){ - return false; - } + if( !is_array( $array ) ){ + return false; + } - $associative = count( array_diff( array_keys($array), array_keys( array_keys( $array )) )); - if( $associative ){ + $associative = count( array_diff( array_keys($array), array_keys( array_keys( $array )) )); + if( $associative ){ - $construct = array(); - foreach( $array as $key => $value ){ + $construct = array(); + foreach( $array as $key => $value ){ - // We first copy each key/value pair into a staging array, - // formatting each key and value properly as we go. + // We first copy each key/value pair into a staging array, + // formatting each key and value properly as we go. - // Format the key: - if( is_numeric( $key ) ){ - $key = "key_$key"; - } - $key = '"'.addslashes( $key ).'"'; + // Format the key: + if( is_numeric( $key ) ){ + $key = "key_$key"; + } + $key = '"'.addslashes( $key ).'"'; - // Format the value: - if( is_array( $value )){ - $value = yourls_array_to_json( $value ); - } else if( !is_numeric( $value ) || is_string( $value ) ){ - $value = '"'.addslashes( $value ).'"'; - } + // Format the value: + if( is_array( $value )){ + $value = yourls_array_to_json( $value ); + } else if( !is_numeric( $value ) || is_string( $value ) ){ + $value = '"'.addslashes( $value ).'"'; + } - // Add to staging array: - $construct[] = "$key: $value"; - } + // Add to staging array: + $construct[] = "$key: $value"; + } - // Then we collapse the staging array into the JSON form: - $result = "{ " . implode( ", ", $construct ) . " }"; + // Then we collapse the staging array into the JSON form: + $result = "{ " . implode( ", ", $construct ) . " }"; - } else { // If the array is a vector (not associative): + } else { // If the array is a vector (not associative): - $construct = array(); - foreach( $array as $value ){ + $construct = array(); + foreach( $array as $value ){ - // Format the value: - if( is_array( $value )){ - $value = yourls_array_to_json( $value ); - } else if( !is_numeric( $value ) || is_string( $value ) ){ - $value = '"'.addslashes($value).'"'; - } + // Format the value: + if( is_array( $value )){ + $value = yourls_array_to_json( $value ); + } else if( !is_numeric( $value ) || is_string( $value ) ){ + $value = '"'.addslashes($value).'"'; + } - // Add to staging array: - $construct[] = $value; - } + // Add to staging array: + $construct[] = $value; + } - // Then we collapse the staging array into the JSON form: - $result = "[ " . implode( ", ", $construct ) . " ]"; - } + // Then we collapse the staging array into the JSON form: + $result = "[ " . implode( ", ", $construct ) . " ]"; + } - return $result; + return $result; } @@ -88,23 +88,23 @@ function yourls_array_to_json( $array ){ * */ if ( !function_exists( 'bcdiv' ) ) { - function bcdiv( $dividend, $divisor ) { - $quotient = floor( $dividend/$divisor ); - return $quotient; - } - function bcmod( $dividend, $modulo ) { - $remainder = $dividend%$modulo; - return $remainder; - } - function bcmul( $left, $right ) { - return $left * $right; - } - function bcadd( $left, $right ) { - return $left + $right; - } - function bcpow( $base, $power ) { - return pow( $base, $power ); - } + function bcdiv( $dividend, $divisor ) { + $quotient = floor( $dividend/$divisor ); + return $quotient; + } + function bcmod( $dividend, $modulo ) { + $remainder = $dividend%$modulo; + return $remainder; + } + function bcmul( $left, $right ) { + return $left * $right; + } + function bcadd( $left, $right ) { + return $left + $right; + } + function bcpow( $base, $power ) { + return pow( $base, $power ); + } } // @codeCoverageIgnoreEnd diff --git a/includes/functions-debug.php b/includes/functions-debug.php index 4e5a557..cac4f2d 100644 --- a/includes/functions-debug.php +++ b/includes/functions-debug.php @@ -6,8 +6,8 @@ /** * Add a message to the debug log * - * When in debug mode ( YOURLS_DEBUG == true ) the debug log is echoed in yourls_html_footer() - * Log messages are appended to $ydb->debug_log array, which is instanciated within class Database\YDB + * When in debug mode (YOURLS_DEBUG == true) the debug log is echoed in yourls_html_footer() + * Log messages are appended to $ydb->debug_log array, which is instantiated within class Database\YDB * * @since 1.7 * @param string $msg Message to add to the debug log @@ -15,12 +15,7 @@ */ function yourls_debug_log( $msg ) { yourls_do_action( 'debug_log', $msg ); - // Get the DB object ($ydb), get its profiler (\Aura\Sql\Profiler\Profiler), its logger (\Aura\Sql\Profiler\MemoryLogger) and - // pass it a unused argument (loglevel) and the message - // Check if function exists to allow usage of the function in very early stages - if(function_exists('yourls_debug_log')) { - yourls_get_db()->getProfiler()->getLogger()->log( 'debug', $msg); - } + yourls_get_db('read-debug_log')->getProfiler()->getLogger()->log('debug', $msg); return $msg; } @@ -31,7 +26,7 @@ function yourls_debug_log( $msg ) { * @return array */ function yourls_get_debug_log() { - return yourls_get_db()->getProfiler()->getLogger()->getMessages(); + return yourls_get_db('read-get_debug_log')->getProfiler()->getLogger()->getMessages(); } /** @@ -40,7 +35,7 @@ function yourls_get_debug_log() { * @return int */ function yourls_get_num_queries() { - return yourls_apply_filter( 'get_num_queries', yourls_get_db()->get_num_queries() ); + return yourls_apply_filter( 'get_num_queries', yourls_get_db('read-get_num_queries')->get_num_queries() ); } /** @@ -52,7 +47,7 @@ function yourls_get_num_queries() { */ function yourls_debug_mode( $bool ) { // log queries if true - yourls_get_db()->getProfiler()->setActive( (bool)$bool ); + yourls_get_db('read-debug_mode')->getProfiler()->setActive( (bool)$bool ); // report notices if true $level = $bool ? -1 : ( E_ERROR | E_PARSE ); diff --git a/includes/functions-deprecated.php b/includes/functions-deprecated.php index 3154c17..662ffb2 100644 --- a/includes/functions-deprecated.php +++ b/includes/functions-deprecated.php @@ -129,12 +129,12 @@ function yourls_get_search_text() { */ function yourls_current_time( $type, $gmt = 0 ) { yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_timestamp' ); - switch ( $type ) { - case 'mysql': - return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', yourls_get_timestamp( time() )); - case 'timestamp': - return ( $gmt ) ? time() : yourls_get_timestamp( time() ); - } + switch ( $type ) { + case 'mysql': + return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', yourls_get_timestamp( time() )); + case 'timestamp': + return ( $gmt ) ? time() : yourls_get_timestamp( time() ); + } } /** @@ -169,8 +169,8 @@ function yourls_sanitize_string( $string, $restrict_to_shorturl_charset = false * */ function yourls_favicon( $echo = true ) { - yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_yourls_favicon_url' ); - return yourls_get_yourls_favicon_url( $echo ); + yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_yourls_favicon_url' ); + return yourls_get_yourls_favicon_url( $echo ); } /** @@ -180,8 +180,8 @@ function yourls_favicon( $echo = true ) { * */ function yourls_get_link_stats( $url ) { - yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_keyword_stats' ); - return yourls_get_keyword_stats( $url ); + yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_keyword_stats' ); + return yourls_get_keyword_stats( $url ); } /** @@ -192,8 +192,8 @@ function yourls_get_link_stats( $url ) { * */ function yourls_url_exists( $url ) { - yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_long_url_exists' ); - return yourls_long_url_exists( $url ); + yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_long_url_exists' ); + return yourls_long_url_exists( $url ); } /** @@ -201,8 +201,8 @@ function yourls_url_exists( $url ) { * */ function yourls_plural( $word, $count=1 ) { - yourls_deprecated_function( __FUNCTION__, '1.6', 'yourls_n' ); - return $word . ($count > 1 ? 's' : ''); + yourls_deprecated_function( __FUNCTION__, '1.6', 'yourls_n' ); + return $word . ($count > 1 ? 's' : ''); } /** @@ -210,10 +210,10 @@ function yourls_plural( $word, $count=1 ) { * */ function yourls_get_duplicate_keywords( $longurl ) { - yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_get_longurl_keywords' ); - if( !yourls_allow_duplicate_longurls() ) - return NULL; - return yourls_apply_filter( 'get_duplicate_keywords', yourls_get_longurl_keywords ( $longurl ), $longurl ); + yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_get_longurl_keywords' ); + if( !yourls_allow_duplicate_longurls() ) + return NULL; + return yourls_apply_filter( 'get_duplicate_keywords', yourls_get_longurl_keywords ( $longurl ), $longurl ); } /** @@ -223,8 +223,8 @@ function yourls_get_duplicate_keywords( $longurl ) { * */ function yourls_intval( $int ) { - yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_sanitize_int' ); - return yourls_escape( $int ); + yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_sanitize_int' ); + return yourls_escape( $int ); } /** @@ -232,8 +232,8 @@ function yourls_intval( $int ) { * */ function yourls_get_remote_content( $url, $maxlen = 4096, $timeout = 5 ) { - yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_http_get_body' ); - return yourls_http_get_body( $url ); + yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_http_get_body' ); + return yourls_http_get_body( $url ); } /** @@ -250,8 +250,8 @@ function yourls_get_remote_content( $url, $maxlen = 4096, $timeout = 5 ) { * @return mixed */ function yourls_apply_filters( $hook, $value = '' ) { - yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_apply_filter' ); - return yourls_apply_filter( $hook, $value ); + yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_apply_filter' ); + return yourls_apply_filter( $hook, $value ); } /** @@ -259,23 +259,22 @@ function yourls_apply_filters( $hook, $value = '' ) { * */ function yourls_has_interface() { - yourls_deprecated_function( __FUNCTION__, '1.7.1' ); - if( yourls_is_API() or yourls_is_GO() ) - return false; - return true; + yourls_deprecated_function( __FUNCTION__, '1.7.1' ); + if( yourls_is_API() or yourls_is_GO() ) + return false; + return true; } /** * Check if a proxy is defined for HTTP requests * - * @uses YOURLS_PROXY * @since 1.7 * @deprecated 1.7.1 * @return bool true if a proxy is defined, false otherwise */ function yourls_http_proxy_is_defined() { - yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_http_get_proxy' ); - return yourls_apply_filter( 'http_proxy_is_defined', defined( 'YOURLS_PROXY' ) ); + yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_http_get_proxy' ); + return yourls_apply_filter( 'http_proxy_is_defined', defined( 'YOURLS_PROXY' ) ); } /** @@ -293,8 +292,8 @@ function yourls_http_proxy_is_defined() { * @return string Translated context string without pipe */ function yourls_ex( $text, $context, $domain = 'default' ) { - yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_xe' ); - echo yourls_xe( $text, $context, $domain ); + yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_xe' ); + echo yourls_xe( $text, $context, $domain ); } /** @@ -308,20 +307,20 @@ function yourls_ex( $text, $context, $domain = 'default' ) { * @return string|array escaped data */ function yourls_escape( $data ) { - yourls_deprecated_function( __FUNCTION__, '1.7.3', 'PDO' ); - if( is_array( $data ) ) { - foreach( $data as $k => $v ) { - if( is_array( $v ) ) { - $data[ $k ] = yourls_escape( $v ); - } else { - $data[ $k ] = yourls_escape_real( $v ); - } - } - } else { - $data = yourls_escape_real( $data ); - } + yourls_deprecated_function( __FUNCTION__, '1.7.3', 'PDO' ); + if( is_array( $data ) ) { + foreach( $data as $k => $v ) { + if( is_array( $v ) ) { + $data[ $k ] = yourls_escape( $v ); + } else { + $data[ $k ] = yourls_escape_real( $v ); + } + } + } else { + $data = yourls_escape_real( $data ); + } - return $data; + return $data; } /** @@ -338,13 +337,13 @@ function yourls_escape( $data ) { * @return string escaped string */ function yourls_escape_real( $string ) { - yourls_deprecated_function( __FUNCTION__, '1.7.3', 'PDO' ); - global $ydb; - if( isset( $ydb ) && ( $ydb instanceof \YOURLS\Database\YDB ) ) - return $ydb->escape( $string ); + yourls_deprecated_function( __FUNCTION__, '1.7.3', 'PDO' ); + global $ydb; + if( isset( $ydb ) && ( $ydb instanceof \YOURLS\Database\YDB ) ) + return $ydb->escape( $string ); - // YOURLS DB classes have been bypassed by a custom DB engine or a custom cache layer - return yourls_apply_filter( 'custom_escape_real', addslashes( $string ), $string ); + // YOURLS DB classes have been bypassed by a custom DB engine or a custom cache layer + return yourls_apply_filter( 'custom_escape_real', addslashes( $string ), $string ); } // @codeCoverageIgnoreEnd diff --git a/includes/functions-formatting.php b/includes/functions-formatting.php index f7b034f..e0c7f49 100644 --- a/includes/functions-formatting.php +++ b/includes/functions-formatting.php @@ -12,18 +12,18 @@ * @return string Converted number */ function yourls_int2string($num, $chars = null) { - if( $chars == null ) - $chars = yourls_get_shorturl_charset(); - $string = ''; - $len = strlen( $chars ); - while( $num >= $len ) { - $mod = bcmod( (string)$num, (string)$len ); - $num = bcdiv( (string)$num, (string)$len ); - $string = $chars[ $mod ] . $string; - } - $string = $chars[ intval( $num ) ] . $string; + if( $chars == null ) + $chars = yourls_get_shorturl_charset(); + $string = ''; + $len = strlen( $chars ); + while( $num >= $len ) { + $mod = bcmod( (string)$num, (string)$len ); + $num = bcdiv( (string)$num, (string)$len ); + $string = $chars[ $mod ] . $string; + } + $string = $chars[ intval( $num ) ] . $string; - return yourls_apply_filter( 'int2string', $string, $num, $chars ); + return yourls_apply_filter( 'int2string', $string, $num, $chars ); } /** @@ -34,18 +34,18 @@ function yourls_int2string($num, $chars = null) { * @return string Number (as a string) */ function yourls_string2int($string, $chars = null) { - if( $chars == null ) - $chars = yourls_get_shorturl_charset(); - $integer = 0; - $string = strrev( $string ); - $baselen = strlen( $chars ); - $inputlen = strlen( $string ); - for ($i = 0; $i < $inputlen; $i++) { - $index = strpos( $chars, $string[$i] ); - $integer = bcadd( (string)$integer, bcmul( (string)$index, bcpow( (string)$baselen, (string)$i ) ) ); - } + if( $chars == null ) + $chars = yourls_get_shorturl_charset(); + $integer = 0; + $string = strrev( $string ); + $baselen = strlen( $chars ); + $inputlen = strlen( $string ); + for ($i = 0; $i < $inputlen; $i++) { + $index = strpos( $chars, $string[$i] ); + $integer = bcadd( (string)$integer, bcmul( (string)$index, bcpow( (string)$baselen, (string)$i ) ) ); + } - return yourls_apply_filter( 'string2int', $integer, $string, $chars ); + return yourls_apply_filter( 'string2int', $integer, $string, $chars ); } /** @@ -58,10 +58,10 @@ function yourls_string2int($string, $chars = null) { */ function yourls_unique_element_id($prefix = 'yid', $initial_val = 1) { static $id_counter = 1; - if ($initial_val > 1) { - $id_counter = (int) $initial_val; - } - return yourls_apply_filter( 'unique_element_id', $prefix . (string) $id_counter++ ); + if ($initial_val > 1) { + $id_counter = (int) $initial_val; + } + return yourls_apply_filter( 'unique_element_id', $prefix . (string) $id_counter++ ); } /** @@ -86,7 +86,7 @@ function yourls_sanitize_keyword( $keyword, $restrict_to_shorturl_charset = fals $valid = yourls_sanitize_url( $keyword ); } - return yourls_apply_filter( 'sanitize_string', $valid, $keyword, $restrict_to_shorturl_charset ); + return yourls_apply_filter( 'sanitize_string', $valid, $keyword, $restrict_to_shorturl_charset ); } /** @@ -99,15 +99,15 @@ function yourls_sanitize_keyword( $keyword, $restrict_to_shorturl_charset = fals * @return string Safe title */ function yourls_sanitize_title( $unsafe_title, $fallback = '' ) { - $title = $unsafe_title; - $title = strip_tags( $title ); - $title = preg_replace( "/\s+/", ' ', trim( $title ) ); + $title = $unsafe_title; + $title = strip_tags( $title ); + $title = preg_replace( "/\s+/", ' ', trim( $title ) ); if ( '' === $title || false === $title ) { $title = $fallback; } - return yourls_apply_filter( 'sanitize_title', $title, $unsafe_title, $fallback ); + return yourls_apply_filter( 'sanitize_title', $title, $unsafe_title, $fallback ); } /** @@ -120,8 +120,8 @@ function yourls_sanitize_title( $unsafe_title, $fallback = '' ) { * @return string Safe URL */ function yourls_sanitize_url( $unsafe_url, $protocols = array() ) { - $url = yourls_esc_url( $unsafe_url, 'redirection', $protocols ); - return yourls_apply_filter( 'sanitize_url', $url, $unsafe_url ); + $url = yourls_esc_url( $unsafe_url, 'redirection', $protocols ); + return yourls_apply_filter( 'sanitize_url', $url, $unsafe_url ); } /** @@ -139,8 +139,8 @@ function yourls_sanitize_url( $unsafe_url, $protocols = array() ) { * @return string Safe URL */ function yourls_sanitize_url_safe( $unsafe_url, $protocols = array() ) { - $url = yourls_esc_url( $unsafe_url, 'safe', $protocols ); - return yourls_apply_filter( 'sanitize_url_safe', $url, $unsafe_url ); + $url = yourls_esc_url( $unsafe_url, 'safe', $protocols ); + return yourls_apply_filter( 'sanitize_url_safe', $url, $unsafe_url ); } /** @@ -153,18 +153,18 @@ function yourls_sanitize_url_safe( $unsafe_url, $protocols = array() ) { * @return string The string with the replaced values. */ function yourls_deep_replace($search, $subject ){ - $found = true; - while($found) { - $found = false; - foreach( (array) $search as $val ) { - while( strpos( $subject, $val ) !== false ) { - $found = true; - $subject = str_replace( $val, '', $subject ); - } - } - } + $found = true; + while($found) { + $found = false; + foreach( (array) $search as $val ) { + while( strpos( $subject, $val ) !== false ) { + $found = true; + $subject = str_replace( $val, '', $subject ); + } + } + } - return $subject; + return $subject; } /** @@ -174,7 +174,7 @@ function yourls_deep_replace($search, $subject ){ * @return string Integer as a string */ function yourls_sanitize_int($int ) { - return ( substr( preg_replace( '/[^0-9]/', '', strval( $int ) ), 0, 20 ) ); + return ( substr( preg_replace( '/[^0-9]/', '', strval( $int ) ), 0, 20 ) ); } /** @@ -185,7 +185,7 @@ function yourls_sanitize_int($int ) { * @return string IP address */ function yourls_sanitize_ip($ip ) { - return preg_replace( '/[^0-9a-fA-F:., ]/', '', $ip ); + return preg_replace( '/[^0-9a-fA-F:., ]/', '', $ip ); } /** @@ -195,10 +195,10 @@ function yourls_sanitize_ip($ip ) { * @return false|mixed Date in format m(m)/d(d)/yyyy or false if invalid */ function yourls_sanitize_date($date ) { - if( !preg_match( '!^\d{1,2}/\d{1,2}/\d{4}$!' , $date ) ) { - return false; - } - return $date; + if( !preg_match( '!^\d{1,2}/\d{1,2}/\d{4}$!' , $date ) ) { + return false; + } + return $date; } /** @@ -208,9 +208,9 @@ function yourls_sanitize_date($date ) { * @return false|string String in Y-m-d format for SQL search or false if malformed input */ function yourls_sanitize_date_for_sql($date) { - if( !yourls_sanitize_date( $date ) ) - return false; - return date( 'Y-m-d', strtotime( $date ) ); + if( !yourls_sanitize_date( $date ) ) + return false; + return date( 'Y-m-d', strtotime( $date ) ); } /** @@ -222,11 +222,11 @@ function yourls_sanitize_date_for_sql($date) { * @return string Trimmed string */ function yourls_trim_long_string($string, $length = 60, $append = '[...]') { - $newstring = $string; + $newstring = $string; if ( mb_strlen( $newstring ) > $length ) { $newstring = mb_substr( $newstring, 0, $length - mb_strlen( $append ), 'UTF-8' ) . $append; } - return yourls_apply_filter( 'trim_long_string', $newstring, $string, $length, $append ); + return yourls_apply_filter( 'trim_long_string', $newstring, $string, $length, $append ); } /** @@ -234,7 +234,12 @@ function yourls_trim_long_string($string, $length = 60, $append = '[...]') { * * The regexp searches for the first digits, then a period, then more digits and periods, and discards * all the rest. - * For instance, 'mysql-5.5-beta' and '5.5-RC1' return '5.5' + * Examples: + * 'omgmysql-5.5-ubuntu-4.20' => '5.5' + * 'mysql5.5-ubuntu-4.20' => '5.5' + * '5.5-ubuntu-4.20' => '5.5' + * '5.5-beta2' => '5.5' + * '5.5' => '5.5' * * @since 1.4.1 * @param string $version Version number @@ -254,9 +259,42 @@ function yourls_sanitize_version( $version ) { * @return string|null Sanitized file name (or null if it's just backslashes, ok...) */ function yourls_sanitize_filename($file) { - $file = str_replace( '\\', '/', $file ); // sanitize for Win32 installs - $file = preg_replace( '|/+|' ,'/', $file ); // remove any duplicate slash - return $file; + $file = str_replace( '\\', '/', $file ); // sanitize for Win32 installs + $file = preg_replace( '|/+|' ,'/', $file ); // remove any duplicate slash + return $file; +} + +/** + * Validate a JSONP callback name + * + * Check if the callback contains only safe characters: [a-zA-Z0-9_$.] + * Returns the original callback if valid, or false if invalid. + * + * Examples: + * - 'myCallback' => 'myCallback' + * - 'alert(1)' => false + * See tests/tests/format/JsonpCallbackTest.php for various cases covered + * + * @since 1.10.3 + * @param string $callback Raw callback value + * @return string|false Original callback if valid, false otherwise + */ +function yourls_validate_jsonp_callback($callback ) { + $callback = (string) $callback; + + // First, check for JavaScript unicode escape sequences like \u2028 or u2028 + // They are sometimes used to smuggle line/paragraph separators. + if ( preg_match( '/\\\\?u[0-9a-fA-F]{4}/', $callback ) ) { + return yourls_apply_filter( 'validate_jsonp_callback_error', false, $callback ); + } + + // Check if callback contains only safe characters [a-zA-Z0-9_$.] + if ( !preg_match( '/^[a-zA-Z0-9_$.]+$/', $callback ) ) { + return yourls_apply_filter( 'validate_jsonp_callback_error', false, $callback ); + } + + // Callback is valid, return original value + return yourls_apply_filter( 'validate_jsonp_callback', $callback ); } /** @@ -266,22 +304,22 @@ function yourls_sanitize_filename($file) { * @return bool Whether string seems valid UTF-8 */ function yourls_seems_utf8($str) { - $length = strlen( $str ); - for ( $i=0; $i < $length; $i++ ) { - $c = ord( $str[ $i ] ); - if ( $c < 0x80 ) $n = 0; # 0bbbbbbb - elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb - elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb - elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb - elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb - elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b - else return false; # Does not match any model - for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? - if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) - return false; - } - } - return true; + $length = strlen( $str ); + for ( $i=0; $i < $length; $i++ ) { + $c = ord( $str[ $i ] ); + if ( $c < 0x80 ) $n = 0; # 0bbbbbbb + elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb + elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb + elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb + elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb + elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b + else return false; # Does not match any model + for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? + if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) + return false; + } + } + return true; } @@ -313,28 +351,28 @@ function yourls_supports_pcre_u() { * @return string The checked text. */ function yourls_check_invalid_utf8( $string, $strip = false ) { - $string = (string) $string; + $string = (string) $string; - if ( 0 === strlen( $string ) ) { - return ''; - } + if ( 0 === strlen( $string ) ) { + return ''; + } - // We can't demand utf8 in the PCRE installation, so just return the string in those cases - if ( ! yourls_supports_pcre_u() ) { - return $string; - } + // We can't demand utf8 in the PCRE installation, so just return the string in those cases + if ( ! yourls_supports_pcre_u() ) { + return $string; + } - // preg_match fails when it encounters invalid UTF8 in $string - if ( 1 === @preg_match( '/^./us', $string ) ) { - return $string; - } + // preg_match fails when it encounters invalid UTF8 in $string + if ( 1 === @preg_match( '/^./us', $string ) ) { + return $string; + } - // Attempt to strip the bad chars if requested (not recommended) - if ( $strip && function_exists( 'iconv' ) ) { - return iconv( 'utf-8', 'utf-8', $string ); - } + // Attempt to strip the bad chars if requested (not recommended) + if ( $strip && function_exists( 'iconv' ) ) { + return iconv( 'utf-8', 'utf-8', $string ); + } - return ''; + return ''; } /** @@ -353,56 +391,56 @@ function yourls_check_invalid_utf8( $string, $strip = false ) { * @return string The encoded text with HTML entities. */ function yourls_specialchars( $string, $quote_style = ENT_NOQUOTES, $double_encode = false ) { - $string = (string) $string; + $string = (string) $string; - if ( 0 === strlen( $string ) ) - return ''; + if ( 0 === strlen( $string ) ) + return ''; - // Don't bother if there are no specialchars - saves some processing - if ( ! preg_match( '/[&<>"\']/', $string ) ) - return $string; + // Don't bother if there are no specialchars - saves some processing + if ( ! preg_match( '/[&<>"\']/', $string ) ) + return $string; - // Account for the previous behaviour of the function when the $quote_style is not an accepted value - if ( empty( $quote_style ) ) - $quote_style = ENT_NOQUOTES; - elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) - $quote_style = ENT_QUOTES; + // Account for the previous behaviour of the function when the $quote_style is not an accepted value + if ( empty( $quote_style ) ) + $quote_style = ENT_NOQUOTES; + elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) + $quote_style = ENT_QUOTES; - $charset = 'UTF-8'; + $charset = 'UTF-8'; - $_quote_style = $quote_style; + $_quote_style = $quote_style; - if ( $quote_style === 'double' ) { - $quote_style = ENT_COMPAT; - $_quote_style = ENT_COMPAT; - } elseif ( $quote_style === 'single' ) { - $quote_style = ENT_NOQUOTES; - } + if ( $quote_style === 'double' ) { + $quote_style = ENT_COMPAT; + $_quote_style = ENT_COMPAT; + } elseif ( $quote_style === 'single' ) { + $quote_style = ENT_NOQUOTES; + } - // Handle double encoding ourselves - if ( $double_encode ) { - $string = @htmlspecialchars( $string, $quote_style, $charset ); - } else { - // Decode & into & - $string = yourls_specialchars_decode( $string, $_quote_style ); + // Handle double encoding ourselves + if ( $double_encode ) { + $string = @htmlspecialchars( $string, $quote_style, $charset ); + } else { + // Decode & into & + $string = yourls_specialchars_decode( $string, $_quote_style ); - // Guarantee every &entity; is valid or re-encode the & - $string = yourls_kses_normalize_entities( $string ); + // Guarantee every &entity; is valid or re-encode the & + $string = yourls_kses_normalize_entities( $string ); - // Now re-encode everything except &entity; - $string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE ); + // Now re-encode everything except &entity; + $string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE ); - for ( $i = 0; $i < count( $string ); $i += 2 ) - $string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset ); + for ( $i = 0; $i < count( $string ); $i += 2 ) + $string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset ); - $string = implode( '', $string ); - } + $string = implode( '', $string ); + } - // Backwards compatibility - if ( 'single' === $_quote_style ) - $string = str_replace( "'", ''', $string ); + // Backwards compatibility + if ( 'single' === $_quote_style ) + $string = str_replace( "'", ''', $string ); - return $string; + return $string; } /** @@ -420,53 +458,53 @@ function yourls_specialchars( $string, $quote_style = ENT_NOQUOTES, $double_enco * @return string The decoded text without HTML entities. */ function yourls_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) { - $string = (string) $string; - - if ( 0 === strlen( $string ) ) { - return ''; - } - - // Don't bother if there are no entities - saves a lot of processing - if ( strpos( $string, '&' ) === false ) { - return $string; - } - - // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value - if ( empty( $quote_style ) ) { - $quote_style = ENT_NOQUOTES; - } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) { - $quote_style = ENT_QUOTES; - } - - // More complete than get_html_translation_table( HTML_SPECIALCHARS ) - $single = array( ''' => '\'', ''' => '\'' ); - $single_preg = array( '/�*39;/' => ''', '/�*27;/i' => ''' ); - $double = array( '"' => '"', '"' => '"', '"' => '"' ); - $double_preg = array( '/�*34;/' => '"', '/�*22;/i' => '"' ); - $others = array( '<' => '<', '<' => '<', '>' => '>', '>' => '>', '&' => '&', '&' => '&', '&' => '&' ); - $others_preg = array( '/�*60;/' => '<', '/�*62;/' => '>', '/�*38;/' => '&', '/�*26;/i' => '&' ); + $string = (string) $string; + + if ( 0 === strlen( $string ) ) { + return ''; + } + + // Don't bother if there are no entities - saves a lot of processing + if ( strpos( $string, '&' ) === false ) { + return $string; + } + + // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value + if ( empty( $quote_style ) ) { + $quote_style = ENT_NOQUOTES; + } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) { + $quote_style = ENT_QUOTES; + } + + // More complete than get_html_translation_table( HTML_SPECIALCHARS ) + $single = array( ''' => '\'', ''' => '\'' ); + $single_preg = array( '/�*39;/' => ''', '/�*27;/i' => ''' ); + $double = array( '"' => '"', '"' => '"', '"' => '"' ); + $double_preg = array( '/�*34;/' => '"', '/�*22;/i' => '"' ); + $others = array( '<' => '<', '<' => '<', '>' => '>', '>' => '>', '&' => '&', '&' => '&', '&' => '&' ); + $others_preg = array( '/�*60;/' => '<', '/�*62;/' => '>', '/�*38;/' => '&', '/�*26;/i' => '&' ); $translation = $translation_preg = []; - if ( $quote_style === ENT_QUOTES ) { - $translation = array_merge( $single, $double, $others ); - $translation_preg = array_merge( $single_preg, $double_preg, $others_preg ); - } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) { - $translation = array_merge( $double, $others ); - $translation_preg = array_merge( $double_preg, $others_preg ); - } elseif ( $quote_style === 'single' ) { - $translation = array_merge( $single, $others ); - $translation_preg = array_merge( $single_preg, $others_preg ); - } elseif ( $quote_style === ENT_NOQUOTES ) { - $translation = $others; - $translation_preg = $others_preg; - } + if ( $quote_style === ENT_QUOTES ) { + $translation = array_merge( $single, $double, $others ); + $translation_preg = array_merge( $single_preg, $double_preg, $others_preg ); + } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) { + $translation = array_merge( $double, $others ); + $translation_preg = array_merge( $double_preg, $others_preg ); + } elseif ( $quote_style === 'single' ) { + $translation = array_merge( $single, $others ); + $translation_preg = array_merge( $single_preg, $others_preg ); + } elseif ( $quote_style === ENT_NOQUOTES ) { + $translation = $others; + $translation_preg = $others_preg; + } - // Remove zero padding on numeric entities - $string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string ); + // Remove zero padding on numeric entities + $string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string ); - // Replace characters according to translation table - return strtr( $string, $translation ); + // Replace characters according to translation table + return strtr( $string, $translation ); } @@ -479,9 +517,9 @@ function yourls_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) { * @return string */ function yourls_esc_html( $text ) { - $safe_text = yourls_check_invalid_utf8( $text ); - $safe_text = yourls_specialchars( $safe_text, ENT_QUOTES ); - return yourls_apply_filter( 'esc_html', $safe_text, $text ); + $safe_text = yourls_check_invalid_utf8( $text ); + $safe_text = yourls_specialchars( $safe_text, ENT_QUOTES ); + return yourls_apply_filter( 'esc_html', $safe_text, $text ); } /** @@ -493,9 +531,9 @@ function yourls_esc_html( $text ) { * @return string */ function yourls_esc_attr( $text ) { - $safe_text = yourls_check_invalid_utf8( $text ); - $safe_text = yourls_specialchars( $safe_text, ENT_QUOTES ); - return yourls_apply_filter( 'esc_attr', $safe_text, $text ); + $safe_text = yourls_check_invalid_utf8( $text ); + $safe_text = yourls_specialchars( $safe_text, ENT_QUOTES ); + return yourls_apply_filter( 'esc_attr', $safe_text, $text ); } /** @@ -518,38 +556,41 @@ function yourls_esc_url( $url, $context = 'display', $protocols = array() ) { // trim first -- see #1931 $url = trim( $url ); - // make sure there's only one 'http://' at the beginning (prevents pasting a URL right after the default 'http://') - $url = str_replace( - array( 'http://http://', 'http://https://' ), - array( 'http://', 'https://' ), - $url - ); + // make sure there's only one 'http://' at the beginning (prevents pasting a URL right after the default 'http://') + $url = str_replace( + array( 'http://http://', 'http://https://' ), + array( 'http://', 'https://' ), + $url + ); - if ( '' == $url ) - return $url; + if ( '' == $url ) + return $url; - $original_url = $url; + $original_url = $url; - // force scheme and domain to lowercase - see issues 591 and 1630 + // force scheme and domain to lowercase - see issues 591 and 1630 $url = yourls_normalize_uri( $url ); - $url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url ); - // Previous regexp in YOURLS was '|[^a-z0-9-~+_.?\[\]\^#=!&;,/:%@$\|*`\'<>"()\\x80-\\xff\{\}]|i' - // TODO: check if that was it too destructive + $url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\\\\x80-\\xff]|i', '', $url ); + // The replace above allows backslashes now, but we only should only allow them after a query string or a fragment identifier + $url = yourls_remove_backslashes_before_query_fragment($url); + + // Previous regexp in YOURLS was '|[^a-z0-9-~+_.?\[\]\^#=!&;,/:%@$\|*`\'<>"()\\x80-\\xff\{\}]|i' + // TODO: check if that was it too destructive // If $context is 'safe', an extra step is taken to make sure no CRLF injection is possible. // To be used when $url can be forged by evil user (eg it's from a $_SERVER variable, a query string, etc..) - if ( 'safe' == $context ) { + if ( 'safe' == $context ) { $strip = array( '%0d', '%0a', '%0D', '%0A' ); $url = yourls_deep_replace( $strip, $url ); } - // Replace ampersands and single quotes only when displaying. - if ( 'display' == $context ) { - $url = yourls_kses_normalize_entities( $url ); - $url = str_replace( '&', '&', $url ); - $url = str_replace( "'", ''', $url ); - } + // Replace ampersands and single quotes only when displaying. + if ( 'display' == $context ) { + $url = yourls_kses_normalize_entities( $url ); + $url = str_replace( '&', '&', $url ); + $url = str_replace( "'", ''', $url ); + } // If there's a protocol, make sure it's OK if( yourls_get_protocol($url) !== '' ) { @@ -565,9 +606,45 @@ function yourls_esc_url( $url, $context = 'display', $protocols = array() ) { // I didn't use KSES function kses_bad_protocol() because it doesn't work the way I liked (returns //blah from illegal://blah) } - return yourls_apply_filter( 'esc_url', $url, $original_url, $context ); + return yourls_apply_filter( 'esc_url', $url, $original_url, $context ); } +/** + * Remove backslashes before query string or fragment identifier + * + * This function removes backslashes before the first ? or #, if any. + * If there's no ? or #, all backslashes are removed. + * See issue #3802 and PR #3998 + * + * @since 1.10.3 + * @param string $url URL + * @return string URL without backslashes before query string or fragment identifier + */ +function yourls_remove_backslashes_before_query_fragment(string $url): string { + $posQ = strpos($url, '?'); + $posH = strpos($url, '#'); + + if ($posQ === false && $posH === false) { + // no ? or # -> remove all backslashes + return str_replace('\\', '', $url); + } + + // chose the first of ? or # + if ($posQ === false) { + $pos = $posH; + } elseif ($posH === false) { + $pos = $posQ; + } else { + $pos = min($posQ, $posH); + } + + $before = substr($url, 0, $pos); + $after = substr($url, $pos); + + $before = str_replace('\\', '', $before); + + return $before . $after; +} /** * Normalize a URI : lowercase scheme and domain, convert IDN to UTF8 @@ -664,12 +741,12 @@ function yourls_normalize_uri( $url ) { * @return string Escaped text. */ function yourls_esc_js( $text ) { - $safe_text = yourls_check_invalid_utf8( $text ); - $safe_text = yourls_specialchars( $safe_text, ENT_COMPAT ); - $safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) ); - $safe_text = str_replace( "\r", '', $safe_text ); - $safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) ); - return yourls_apply_filter( 'esc_js', $safe_text, $text ); + $safe_text = yourls_check_invalid_utf8( $text ); + $safe_text = yourls_specialchars( $safe_text, ENT_COMPAT ); + $safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) ); + $safe_text = str_replace( "\r", '', $safe_text ); + $safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) ); + return yourls_apply_filter( 'esc_js', $safe_text, $text ); } /** @@ -681,8 +758,8 @@ function yourls_esc_js( $text ) { * @return string */ function yourls_esc_textarea( $text ) { - $safe_text = htmlspecialchars( $text, ENT_QUOTES ); - return yourls_apply_filter( 'esc_textarea', $safe_text, $text ); + $safe_text = htmlspecialchars( $text, ENT_QUOTES ); + return yourls_apply_filter( 'esc_textarea', $safe_text, $text ); } /** @@ -708,7 +785,7 @@ function yourls_backslashit($string) { * @return bool */ function yourls_is_rawurlencoded( $string ) { - return rawurldecode( $string ) != $string; + return rawurldecode( $string ) != $string; } /** @@ -722,11 +799,11 @@ function yourls_is_rawurlencoded( $string ) { * @return string */ function yourls_rawurldecode_while_encoded( $string ) { - $string = rawurldecode( $string ); - if( yourls_is_rawurlencoded( $string ) ) { - $string = yourls_rawurldecode_while_encoded( $string ); - } - return $string; + $string = rawurldecode( $string ); + if( yourls_is_rawurlencoded( $string ) ) { + $string = yourls_rawurldecode_while_encoded( $string ); + } + return $string; } /** diff --git a/includes/functions-html.php b/includes/functions-html.php index e8b5bbd..aadf6f6 100644 --- a/includes/functions-html.php +++ b/includes/functions-html.php @@ -6,16 +6,16 @@ * @return void */ function yourls_html_logo() { - yourls_do_action( 'pre_html_logo' ); - ?> -
-

- YOURLS: Your Own URL Shortener
-
-

-
- +
+

+ YOURLS: Your Own URL Shortener
+
+

+
+ + ?> > - <?php echo $title ?> - - - - + <?php echo $title ?> + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- -
-

- YOURLS v ' . YOURLS_VERSION ); - $footer .= $num_queries; - echo yourls_apply_filter( 'html_footer_text', $footer ); - ?> -

-
';
-		echo join( "\n", yourls_get_debug_log() );
-		echo '
'; - } ?> - - - - + +

+ YOURLS v ' . YOURLS_VERSION ); + $footer .= $num_queries; + echo yourls_apply_filter( 'html_footer_text', $footer ); + ?> +

+
';
+        echo join( "\n", yourls_get_debug_log() );
+        echo '
'; + } ?> + + + + -
-
-
-
-
+ ?> +
+
+
+ +
: : @@ -198,11 +198,39 @@ function yourls_html_addnew( $url = '', $keyword = '' ) {
- - -
- -
+ + +
+ +
+ + +
+
+

+
    +
  • :
  • +
  • :
  • +
  • :
  • +
+
+
+ + + +
+
- - - -
-
-
- '; - $_options = array( + ?> + + + +
+ +
+ '; + $_options = array( 'all' => yourls__( 'All fields' ), - 'keyword' => yourls__( 'Short URL' ), - 'url' => yourls__( 'URL' ), - 'title' => yourls__( 'Title' ), - 'ip' => yourls__( 'IP' ), - ); - $_select = yourls_html_select( 'search_in', $_options, $search_in, false, yourls__( 'Search in' ) ); - /* //translators: "Search for in in '; - yourls_se( 'Show %s rows', $_input ); - echo "
\n"; - - // Fourth search control: Show links with more than XX clicks - $_options = array( - 'more' => yourls__( 'more' ), - 'less' => yourls__( 'less' ), - ); - $_select = yourls_html_select( 'click_filter', $_options, $click_filter, false, yourls__( 'Show links with' ) ); - $_input = ' '; - /* //translators: "Show links with than clicks" */ - yourls_se( 'Show links with %1$s than %2$s clicks', $_select, $_input ); - echo "
\n"; - - // Fifth search control: Show links created before/after/between ... - $_options = array( - 'before' => yourls__('before'), - 'after' => yourls__('after'), - 'between' => yourls__('between'), - ); - $_select = yourls_html_select( 'date_filter', $_options, $date_filter, false, yourls__('Show links created') ); - $_input = ''; - $_and = ' & '; - $_input2 = ''; - /* //translators: "Show links created <"and" if applicable> " */ - yourls_se( 'Show links created %1$s %2$s %3$s %4$s', $_select, $_input, $_and, $_input2 ); - ?> - -
- -   - -
- -
- -
- - - - - - - - - \n"; + + // Fourth search control: Show links with more than XX clicks + $_options = array( + 'more' => yourls__( 'more' ), + 'less' => yourls__( 'less' ), + ); + $_select = yourls_html_select( 'click_filter', $_options, $click_filter, false, yourls__( 'Show links with' ) ); + $_input = ' '; + /* //translators: "Show links with than clicks" */ + yourls_se( 'Show links with %1$s than %2$s clicks', $_select, $_input ); + echo "
\n"; + + // Fifth search control: Show links created before/after/between ... + $_options = array( + 'before' => yourls__('before'), + 'after' => yourls__('after'), + 'between' => yourls__('between'), + ); + $_select = yourls_html_select( 'date_filter', $_options, $date_filter, false, yourls__('Show links created') ); + $_input = ''; + $_and = ' & '; + $_input2 = ''; + /* //translators: "Show links created <"and" if applicable> " */ + yourls_se( 'Show links created %1$s %2$s %3$s %4$s', $_select, $_input, $_and, $_input2 ); + ?> + +
+ +   + +
+ +
+ +
+ + + + + + + + + \n"; - foreach( $options as $value => $text ) { - $html .= "
' ); + echo yourls_apply_filter( 'table_end', '' ); } @@ -729,12 +757,12 @@ function yourls_table_end() { * @return void */ function yourls_html_link( $href, $anchor = '', $element = '' ) { - if( !$anchor ) - $anchor = $href; - if( $element ) - $element = sprintf( 'id="%s"', yourls_esc_attr( $element ) ); - $link = sprintf( '%s', yourls_esc_url( $href ), $element, yourls_esc_html( $anchor ) ); - echo yourls_apply_filter( 'html_link', $link ); + if( !$anchor ) + $anchor = $href; + if( $element ) + $element = sprintf( 'id="%s"', yourls_esc_attr( $element ) ); + $link = sprintf( '%s', yourls_esc_url( $href ), $element, yourls_esc_html( $anchor ) ); + echo yourls_apply_filter( 'html_link', $link ); } /** @@ -744,46 +772,46 @@ function yourls_html_link( $href, $anchor = '', $element = '' ) { * @return void */ function yourls_login_screen( $error_msg = '' ) { - yourls_html_head( 'login' ); - - $action = ( isset( $_GET['action'] ) && $_GET['action'] == 'logout' ? '?' : '' ); - - yourls_html_logo(); - ?> -
-
-
- '.$error_msg.'

'; - } - yourls_do_action( 'login_form_top' ); - ?> -

-
- -

-

-
- -

- -

- - -

- -
- -
-
- +
+
+
+ '.$error_msg.'

'; + } + yourls_do_action( 'login_form_top' ); + ?> +

+
+ +

+

+
+ +

+ +

+ + +

+ +
+ +
+
+ 'logout'], yourls_admin_url('index.php')), 'nonce', 'logout'); - $logout_link = yourls_apply_filter('logout_link', sprintf( yourls__('Hello %s'), YOURLS_USER ) . ' (' . yourls__( 'Logout' ) . ')' ); - } else { - $logout_link = yourls_apply_filter( 'logout_link', '' ); - } - $help_link = yourls_apply_filter( 'help_link', '' . yourls__( 'Help' ) . '' ); - - $admin_links = array(); - $admin_sublinks = array(); - - $admin_links['admin'] = array( - 'url' => yourls_admin_url( 'index.php' ), - 'title' => yourls__( 'Go to the admin interface' ), - 'anchor' => yourls__( 'Admin interface' ) - ); - - if( yourls_is_admin() ) { - $admin_links['tools'] = array( - 'url' => yourls_admin_url( 'tools.php' ), - 'anchor' => yourls__( 'Tools' ) - ); - $admin_links['plugins'] = array( - 'url' => yourls_admin_url( 'plugins.php' ), - 'anchor' => yourls__( 'Manage Plugins' ) - ); - $admin_sublinks['plugins'] = yourls_list_plugin_admin_pages(); - } - - $admin_links = yourls_apply_filter( 'admin_links', $admin_links ); - $admin_sublinks = yourls_apply_filter( 'admin_sublinks', $admin_sublinks ); - - // Now output menu - echo '\n"; - yourls_do_action( 'admin_notices' ); - yourls_do_action( 'admin_notice' ); // because I never remember if it's 'notices' or 'notice' - /* - To display a notice: - $message = "
OMG, dude, I mean!
" ); - yourls_add_action( 'admin_notices', function() use ( $message ) { echo (string) $message; } ); - */ + // Build menu links + if( defined( 'YOURLS_USER' ) ) { + // Create a logout link with a nonce associated to fake user 'logout' : the user is not yet defined + // when the logout check is done -- see yourls_is_valid_user() + $logout_url = yourls_nonce_url( 'admin_logout', + yourls_add_query_arg(['action' => 'logout'], yourls_admin_url('index.php')), 'nonce', 'logout'); + $logout_link = yourls_apply_filter('logout_link', sprintf( yourls__('Hello %s'), YOURLS_USER ) . ' (' . yourls__( 'Logout' ) . ')' ); + } else { + $logout_link = yourls_apply_filter( 'logout_link', '' ); + } + $help_link = yourls_apply_filter( 'help_link', '' . yourls__( 'Help' ) . '' ); + + $admin_links = array(); + $admin_sublinks = array(); + + $admin_links['admin'] = array( + 'url' => yourls_admin_url( 'index.php' ), + 'title' => yourls__( 'Go to the admin interface' ), + 'anchor' => yourls__( 'Admin interface' ) + ); + + if( yourls_is_admin() ) { + $admin_links['tools'] = array( + 'url' => yourls_admin_url( 'tools.php' ), + 'anchor' => yourls__( 'Tools' ) + ); + $admin_links['plugins'] = array( + 'url' => yourls_admin_url( 'plugins.php' ), + 'anchor' => yourls__( 'Manage Plugins' ) + ); + $admin_sublinks['plugins'] = yourls_list_plugin_admin_pages(); + } + + $admin_links = yourls_apply_filter( 'admin_links', $admin_links ); + $admin_sublinks = yourls_apply_filter( 'admin_sublinks', $admin_sublinks ); + + // Now output menu + echo '\n"; + yourls_do_action( 'admin_notices' ); + yourls_do_action( 'admin_notice' ); // because I never remember if it's 'notices' or 'notice' + /* + To display a notice: + $message = "
OMG, dude, I mean!
" ); + yourls_add_action( 'admin_notices', function() use ( $message ) { echo (string) $message; } ); + */ } /** @@ -876,9 +904,9 @@ function yourls_html_menu() { * @return void */ function yourls_add_notice( $message, $style = 'notice' ) { - // Escape single quotes in $message to avoid breaking the anonymous function - $message = yourls_notice_box( strtr( $message, array( "'" => "\'" ) ), $style ); - yourls_add_action( 'admin_notices', function() use ( $message ) { echo (string) $message; } ); + // Escape single quotes in $message to avoid breaking the anonymous function + $message = yourls_notice_box( strtr( $message, array( "'" => "\'" ) ), $style ); + yourls_add_action( 'admin_notices', function() use ( $message ) { echo (string) $message; } ); } /** @@ -889,10 +917,10 @@ function yourls_add_notice( $message, $style = 'notice' ) { * @return string HTML of the notice */ function yourls_notice_box( $message, $style = 'notice' ) { - return << -

$message

- + return << +

$message

+ HTML; } @@ -908,15 +936,15 @@ function yourls_notice_box( $message, $style = 'notice' ) { */ function yourls_page( $page ) { if( !yourls_is_page($page)) { - yourls_die( yourls_s('Page "%1$s" not found', $page), yourls__('Not found'), 404 ); + yourls_die( yourls_s('Page "%1$s" not found', $page), yourls__('Not found'), 404 ); } - yourls_do_action( 'pre_page', $page ); + yourls_do_action( 'pre_page', $page ); $load = yourls_include_file_sandbox(YOURLS_PAGEDIR . "/$page.php"); - if (is_string($load)) { + if (is_string($load)) { yourls_die( $load, yourls__('Not found'), 404 ); - } - yourls_do_action( 'post_page', $page ); + } + yourls_do_action( 'post_page', $page ); } /** @@ -929,24 +957,24 @@ function yourls_page( $page ) { * @return void */ function yourls_html_language_attributes() { - $attributes = array(); - $output = ''; - - $attributes[] = ( yourls_is_rtl() ? 'dir="rtl"' : 'dir="ltr"' ); - - $doctype = yourls_apply_filter( 'html_language_attributes_doctype', 'html' ); - // Experimental: get HTML lang from locale. Should work. Convert fr_FR -> fr-FR - if ( $lang = str_replace( '_', '-', yourls_get_locale() ) ) { - if( $doctype == 'xhtml' ) { - $attributes[] = "xml:lang=\"$lang\""; - } else { - $attributes[] = "lang=\"$lang\""; - } - } - - $output = implode( ' ', $attributes ); - $output = yourls_apply_filter( 'html_language_attributes', $output ); - echo $output; + $attributes = array(); + $output = ''; + + $attributes[] = ( yourls_is_rtl() ? 'dir="rtl"' : 'dir="ltr"' ); + + $doctype = yourls_apply_filter( 'html_language_attributes_doctype', 'html' ); + // Experimental: get HTML lang from locale. Should work. Convert fr_FR -> fr-FR + if ( $lang = str_replace( '_', '-', yourls_get_locale() ) ) { + if( $doctype == 'xhtml' ) { + $attributes[] = "xml:lang=\"$lang\""; + } else { + $attributes[] = "lang=\"$lang\""; + } + } + + $output = implode( ' ', $attributes ); + $output = yourls_apply_filter( 'html_language_attributes', $output ); + echo $output; } /** @@ -956,16 +984,16 @@ function yourls_html_language_attributes() { * @return void */ function yourls_l10n_calendar_strings() { - echo "\n\n"; - - // Dummy returns, to initialize l10n strings used in the calendar - yourls__( 'Today' ); - yourls__( 'Close' ); + echo "\n\n"; + + // Dummy returns, to initialize l10n strings used in the calendar + yourls__( 'Today' ); + yourls__( 'Close' ); } @@ -979,14 +1007,14 @@ function yourls_l10n_calendar_strings() { function yourls_new_core_version_notice($compare_with = null) { $compare_with = $compare_with ?: YOURLS_VERSION; - $checks = yourls_get_option( 'core_version_checks' ); + $checks = yourls_get_option( 'core_version_checks' ); $latest = isset($checks->last_result->latest) ? yourls_sanitize_version($checks->last_result->latest) : false; - if( $latest AND version_compare( $latest, $compare_with, '>' ) ) { + if( $latest AND version_compare( $latest, $compare_with, '>' ) ) { yourls_do_action('new_core_version_notice', $latest); - $msg = yourls_s( 'YOURLS version %s is available. Please update!', 'http://yourls.org/download', $latest ); - yourls_add_notice( $msg ); - } + $msg = yourls_s( 'YOURLS version %s is available. Please update!', 'http://yourls.org/download', $latest ); + yourls_add_notice( $msg ); + } } /** @@ -1017,7 +1045,7 @@ function yourls_bookmarklet_link( $href, $anchor, $echo = true ) { * @return void */ function yourls_set_html_context($context) { - yourls_get_db()->set_html_context($context); + yourls_get_db('read-set_html_context')->set_html_context($context); } /** @@ -1027,7 +1055,7 @@ function yourls_set_html_context($context) { * @return string */ function yourls_get_html_context() { - return yourls_get_db()->get_html_context(); + return yourls_get_db('read-get_html_context')->get_html_context(); } /** diff --git a/includes/functions-http.php b/includes/functions-http.php index db60abc..b1bb208 100644 --- a/includes/functions-http.php +++ b/includes/functions-http.php @@ -31,7 +31,7 @@ * @return mixed Response object, or error string */ function yourls_http_get( $url, $headers = array(), $data = array(), $options = array() ) { - return yourls_http_request( 'GET', $url, $headers, $data, $options ); + return yourls_http_request( 'GET', $url, $headers, $data, $options ); } /** @@ -46,8 +46,8 @@ function yourls_http_get( $url, $headers = array(), $data = array(), $options = * @return mixed String (page body) or null if error */ function yourls_http_get_body( $url, $headers = array(), $data = array(), $options = array() ) { - $return = yourls_http_get( $url, $headers, $data, $options ); - return isset( $return->body ) ? $return->body : null; + $return = yourls_http_get( $url, $headers, $data, $options ); + return isset( $return->body ) ? $return->body : null; } /** @@ -64,7 +64,7 @@ function yourls_http_get_body( $url, $headers = array(), $data = array(), $optio * @return mixed Response object, or error string */ function yourls_http_post( $url, $headers = array(), $data = array(), $options = array() ) { - return yourls_http_request( 'POST', $url, $headers, $data, $options ); + return yourls_http_request( 'POST', $url, $headers, $data, $options ); } /** @@ -81,14 +81,13 @@ function yourls_http_post( $url, $headers = array(), $data = array(), $options = * @return mixed String (page body) or null if error */ function yourls_http_post_body( $url, $headers = array(), $data = array(), $options = array() ) { - $return = yourls_http_post( $url, $headers, $data, $options ); - return isset( $return->body ) ? $return->body : null; + $return = yourls_http_post( $url, $headers, $data, $options ); + return isset( $return->body ) ? $return->body : null; } /** * Get proxy information * - * @uses YOURLS_PROXY YOURLS_PROXY_USERNAME YOURLS_PROXY_PASSWORD * @since 1.7.1 * @return mixed false if no proxy is defined, or string like '10.0.0.201:3128' or array like ('10.0.0.201:3128', 'username', 'password') */ @@ -108,7 +107,6 @@ function yourls_http_get_proxy() { /** * Get list of hosts that should bypass the proxy * - * @uses YOURLS_PROXY_BYPASS_HOSTS * @since 1.7.1 * @return mixed false if no host defined, or string like "example.com, *.mycorp.com" */ @@ -127,18 +125,18 @@ function yourls_http_get_proxy_bypass_host() { * @return array Options */ function yourls_http_default_options() { - $options = array( - 'timeout' => yourls_apply_filter( 'http_default_options_timeout', 3 ), - 'useragent' => yourls_http_user_agent(), - 'follow_redirects' => true, - 'redirects' => 3, - ); - - if( yourls_http_get_proxy() ) { + $options = array( + 'timeout' => yourls_apply_filter( 'http_default_options_timeout', 3 ), + 'useragent' => yourls_http_user_agent(), + 'follow_redirects' => true, + 'redirects' => 3, + ); + + if( yourls_http_get_proxy() ) { $options['proxy'] = yourls_http_get_proxy(); - } + } - return yourls_apply_filter( 'http_default_options', $options ); + return yourls_apply_filter( 'http_default_options', $options ); } /** @@ -147,35 +145,33 @@ function yourls_http_default_options() { * Concept stolen from WordPress. The idea is to allow some URLs, including localhost and the YOURLS install itself, * to be requested directly and bypassing any defined proxy. * - * @uses YOURLS_PROXY - * @uses YOURLS_PROXY_BYPASS_HOSTS * @since 1.7 * @param string $url URL to check * @return bool true to request through proxy, false to request directly */ function yourls_send_through_proxy( $url ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_send_through_proxy', null, $url ); - if ( null !== $pre ) - return $pre; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_send_through_proxy', null, $url ); + if ( null !== $pre ) + return $pre; - $check = @parse_url( $url ); + $check = @parse_url( $url ); if( !isset( $check['host'] ) ) { return false; } - // Malformed URL, can not process, but this could mean ssl, so let through anyway. - if ( $check === false ) - return true; + // Malformed URL, can not process, but this could mean ssl, so let through anyway. + if ( $check === false ) + return true; - // Self and loopback URLs are considered local (':' is parse_url() host on '::1') - $home = parse_url( yourls_get_yourls_site() ); - $local = array( 'localhost', '127.0.0.1', '127.1', '[::1]', ':', $home['host'] ); + // Self and loopback URLs are considered local (':' is parse_url() host on '::1') + $home = parse_url( yourls_get_yourls_site() ); + $local = array( 'localhost', '127.0.0.1', '127.1', '[::1]', ':', $home['host'] ); - if( in_array( $check['host'], $local ) ) - return false; + if( in_array( $check['host'], $local ) ) + return false; $bypass = yourls_http_get_proxy_bypass_host(); @@ -183,10 +179,10 @@ function yourls_send_through_proxy( $url ) { return true; } - // Build array of hosts to bypass - static $bypass_hosts; - static $wildcard_regex = false; - if ( null == $bypass_hosts ) { + // Build array of hosts to bypass + static $bypass_hosts; + static $wildcard_regex = false; + if ( null == $bypass_hosts ) { $bypass_hosts = preg_split( '|\s*,\s*|', $bypass ); if ( false !== strpos( $bypass, '*' ) ) { @@ -199,12 +195,12 @@ function yourls_send_through_proxy( $url ) { } $wildcard_regex = '/^(' . implode( '|', $wildcard_regex ) . ')$/i'; } - } + } - if ( !empty( $wildcard_regex ) ) - return !preg_match( $wildcard_regex, $check['host'] ); - else - return !in_array( $check['host'], $bypass_hosts ); + if ( !empty( $wildcard_regex ) ) + return !preg_match( $wildcard_regex, $check['host'] ); + else + return !in_array( $check['host'], $bypass_hosts ); } /** @@ -220,16 +216,16 @@ function yourls_send_through_proxy( $url ) { */ function yourls_http_request( $type, $url, $headers, $data, $options ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_yourls_http_request', null, $type, $url, $headers, $data, $options ); - if ( null !== $pre ) - return $pre; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_yourls_http_request', null, $type, $url, $headers, $data, $options ); + if ( null !== $pre ) + return $pre; - $options = array_merge( yourls_http_default_options(), $options ); + $options = array_merge( yourls_http_default_options(), $options ); - if( yourls_http_get_proxy() && !yourls_send_through_proxy( $url ) ) { - unset( $options['proxy'] ); - } + if( yourls_http_get_proxy() && !yourls_send_through_proxy( $url ) ) { + unset( $options['proxy'] ); + } // filter everything $type = yourls_apply_filter('http_request_type', $type); @@ -238,13 +234,13 @@ function yourls_http_request( $type, $url, $headers, $data, $options ) { $data = yourls_apply_filter('http_request_data', $data); $options = yourls_apply_filter('http_request_options', $options); - try { - $result = Requests::request( $url, $headers, $data, $type, $options ); - } catch( \WpOrg\Requests\Exception $e ) { - $result = yourls_debug_log( $e->getMessage() . ' (' . $type . ' on ' . $url . ')' ); - }; + try { + $result = Requests::request( $url, $headers, $data, $type, $options ); + } catch( \WpOrg\Requests\Exception $e ) { + $result = yourls_debug_log( $e->getMessage() . ' (' . $type . ' on ' . $url . ')' ); + }; - return $result; + return $result; } /** @@ -254,7 +250,7 @@ function yourls_http_request( $type, $url, $headers, $data, $options ) { * @return string UA string */ function yourls_http_user_agent() { - return yourls_apply_filter( 'http_user_agent', 'YOURLS v'.YOURLS_VERSION.' +http://yourls.org/ (running on '.yourls_get_yourls_site().')' ); + return yourls_apply_filter( 'http_user_agent', 'YOURLS v'.YOURLS_VERSION.' +http://yourls.org/ (running on '.yourls_get_yourls_site().')' ); } /** @@ -274,51 +270,51 @@ function yourls_http_user_agent() { */ function yourls_check_core_version() { - global $yourls_user_passwords; + global $yourls_user_passwords; - $checks = yourls_get_option( 'core_version_checks' ); + $checks = yourls_get_option( 'core_version_checks' ); - // Invalidate check data when YOURLS version changes - if ( is_object( $checks ) && YOURLS_VERSION != $checks->version_checked ) { - $checks = false; - } + // Invalidate check data when YOURLS version changes + if ( is_object( $checks ) && YOURLS_VERSION != $checks->version_checked ) { + $checks = false; + } - if( !is_object( $checks ) ) { - $checks = new stdClass; - $checks->failed_attempts = 0; - $checks->last_attempt = 0; - $checks->last_result = ''; - $checks->version_checked = YOURLS_VERSION; - } + if( !is_object( $checks ) ) { + $checks = new stdClass; + $checks->failed_attempts = 0; + $checks->last_attempt = 0; + $checks->last_result = ''; + $checks->version_checked = YOURLS_VERSION; + } - // Total number of links and clicks + // Total number of links and clicks list( $total_urls, $total_clicks ) = array_values(yourls_get_db_stats()); - // The collection of stuff to report - $stuff = array( - // Globally uniquish site identifier + // The collection of stuff to report + $stuff = array( + // Globally uniquish site identifier // This uses const YOURLS_SITE and not yourls_get_yourls_site() to prevent creating another id for an already known install - 'md5' => md5( YOURLS_SITE . YOURLS_ABSPATH ), - - // Install information - 'failed_attempts' => $checks->failed_attempts, - 'yourls_site' => defined( 'YOURLS_SITE' ) ? yourls_get_yourls_site() : 'unknown', - 'yourls_version' => defined( 'YOURLS_VERSION' ) ? YOURLS_VERSION : 'unknown', - 'php_version' => PHP_VERSION, - 'mysql_version' => yourls_get_db()->mysql_version(), - 'locale' => yourls_get_locale(), - - // custom DB driver if any, and useful common PHP extensions - 'db_driver' => defined( 'YOURLS_DB_DRIVER' ) ? YOURLS_DB_DRIVER : 'unset', - 'db_ext_pdo' => extension_loaded( 'PDO' ) ? 1 : 0, - 'db_ext_mysql' => extension_loaded( 'mysql' ) ? 1 : 0, - 'db_ext_mysqli' => extension_loaded( 'mysqli' ) ? 1 : 0, - 'ext_curl' => extension_loaded( 'curl' ) ? 1 : 0, - - // Config information - 'yourls_private' => defined( 'YOURLS_PRIVATE' ) && YOURLS_PRIVATE ? 1 : 0, - 'yourls_unique' => defined( 'YOURLS_UNIQUE_URLS' ) && YOURLS_UNIQUE_URLS ? 1 : 0, - 'yourls_url_convert' => defined( 'YOURLS_URL_CONVERT' ) ? YOURLS_URL_CONVERT : 'unknown', + 'md5' => md5( YOURLS_SITE . YOURLS_ABSPATH ), + + // Install information + 'failed_attempts' => $checks->failed_attempts, + 'yourls_site' => defined( 'YOURLS_SITE' ) ? yourls_get_yourls_site() : 'unknown', + 'yourls_version' => defined( 'YOURLS_VERSION' ) ? YOURLS_VERSION : 'unknown', + 'php_version' => PHP_VERSION, + 'mysql_version' => yourls_get_db('read-check_core_version')->mysql_version(), + 'locale' => yourls_get_locale(), + + // custom DB driver if any, and useful common PHP extensions + 'db_driver' => defined( 'YOURLS_DB_DRIVER' ) ? YOURLS_DB_DRIVER : 'unset', + 'db_ext_pdo' => extension_loaded( 'PDO' ) ? 1 : 0, + 'db_ext_mysql' => extension_loaded( 'mysql' ) ? 1 : 0, + 'db_ext_mysqli' => extension_loaded( 'mysqli' ) ? 1 : 0, + 'ext_curl' => extension_loaded( 'curl' ) ? 1 : 0, + + // Config information + 'yourls_private' => defined( 'YOURLS_PRIVATE' ) && YOURLS_PRIVATE ? 1 : 0, + 'yourls_unique' => defined( 'YOURLS_UNIQUE_URLS' ) && YOURLS_UNIQUE_URLS ? 1 : 0, + 'yourls_url_convert' => defined( 'YOURLS_URL_CONVERT' ) ? YOURLS_URL_CONVERT : 'unknown', // Usage information 'num_users' => count( $yourls_user_passwords ), @@ -326,44 +322,44 @@ function yourls_check_core_version() { 'num_pages' => defined( 'YOURLS_PAGEDIR' ) ? count( (array) glob( YOURLS_PAGEDIR .'/*.php') ) : 0, 'num_links' => $total_urls, 'num_clicks' => $total_clicks, - ); + ); - $stuff = yourls_apply_filter( 'version_check_stuff', $stuff ); + $stuff = yourls_apply_filter( 'version_check_stuff', $stuff ); - // Send it in - $url = 'http://api.yourls.org/core/version/1.1/'; + // Send it in + $url = 'http://api.yourls.org/core/version/1.1/'; if( yourls_can_http_over_ssl() ) { $url = yourls_set_url_scheme($url, 'https'); } - $req = yourls_http_post( $url, array(), $stuff ); + $req = yourls_http_post( $url, array(), $stuff ); - $checks->last_attempt = time(); - $checks->version_checked = YOURLS_VERSION; + $checks->last_attempt = time(); + $checks->version_checked = YOURLS_VERSION; - // Unexpected results ? - if( is_string( $req ) or !$req->success ) { - $checks->failed_attempts = $checks->failed_attempts + 1; - yourls_update_option( 'core_version_checks', $checks ); - if( is_string($req) ) { + // Unexpected results ? + if( is_string( $req ) or !$req->success ) { + $checks->failed_attempts = $checks->failed_attempts + 1; + yourls_update_option( 'core_version_checks', $checks ); + if( is_string($req) ) { yourls_debug_log('Version check failed: ' . $req); } - return false; - } + return false; + } - // Parse response - $json = json_decode( trim( $req->body ) ); + // Parse response + $json = json_decode( trim( $req->body ) ); - if( yourls_validate_core_version_response($json) ) { - // All went OK - mark this down - $checks->failed_attempts = 0; - $checks->last_result = $json; - yourls_update_option( 'core_version_checks', $checks ); + if( yourls_validate_core_version_response($json) ) { + // All went OK - mark this down + $checks->failed_attempts = 0; + $checks->last_result = $json; + yourls_update_option( 'core_version_checks', $checks ); - return $json; - } + return $json; + } - // Request returned actual result, but not what we expected - return false; + // Request returned actual result, but not what we expected + return false; } /** @@ -467,33 +463,33 @@ function yourls_maybe_check_core_version() { return false; } - $checks = yourls_get_option( 'core_version_checks' ); - - /* We don't want to check if : - - last_result is set (a previous check was performed) - - and it was less than 24h ago (or less than 2h ago if it wasn't successful) - - and version checked matched version running - Otherwise, we want to check. - */ - if( !empty( $checks->last_result ) - AND - ( - ( $checks->failed_attempts == 0 && ( ( time() - $checks->last_attempt ) < 24 * 3600 ) ) - OR - ( $checks->failed_attempts > 0 && ( ( time() - $checks->last_attempt ) < 2 * 3600 ) ) - ) - AND ( $checks->version_checked == YOURLS_VERSION ) - ) - return false; - - // We want to check if there's a new version - $new_check = yourls_check_core_version(); - - // Could not check for a new version, and we don't have ancient data - if( false == $new_check && !isset( $checks->last_result->latest ) ) - return false; - - return true; + $checks = yourls_get_option( 'core_version_checks' ); + + /* We don't want to check if : + - last_result is set (a previous check was performed) + - and it was less than 24h ago (or less than 2h ago if it wasn't successful) + - and version checked matched version running + Otherwise, we want to check. + */ + if( !empty( $checks->last_result ) + AND + ( + ( $checks->failed_attempts == 0 && ( ( time() - $checks->last_attempt ) < 24 * 3600 ) ) + OR + ( $checks->failed_attempts > 0 && ( ( time() - $checks->last_attempt ) < 2 * 3600 ) ) + ) + AND ( $checks->version_checked == YOURLS_VERSION ) + ) + return false; + + // We want to check if there's a new version + $new_check = yourls_check_core_version(); + + // Could not check for a new version, and we don't have ancient data + if( false == $new_check && !isset( $checks->last_result->latest ) ) + return false; + + return true; } /** diff --git a/includes/functions-infos.php b/includes/functions-infos.php index 38c7d9c..4cbe895 100644 --- a/includes/functions-infos.php +++ b/includes/functions-infos.php @@ -9,27 +9,27 @@ */ function yourls_stats_countries_map($countries, $id = null) { - yourls_do_action( 'pre_stats_countries_map' ); + yourls_do_action( 'pre_stats_countries_map' ); - // if $id is null then assign a random string - if( $id === null ) - $id = uniqid ( 'yourls_stats_map_' ); + // if $id is null then assign a random string + if( $id === null ) + $id = uniqid ( 'yourls_stats_map_' ); - $data = array_merge( array( 'Country' => 'Hits' ), $countries ); - $data = yourls_google_array_to_data_table( $data ); + $data = array_merge( array( 'Country' => 'Hits' ), $countries ); + $data = yourls_google_array_to_data_table( $data ); - $options = array( - 'backgroundColor' => "white", - 'colorAxis' => "{colors:['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']}", - 'width' => "550", - 'height' => "340", - 'theme' => 'maximized' - ); - $options = yourls_apply_filter( 'stats_countries_map_options', $options ); + $options = array( + 'backgroundColor' => "white", + 'colorAxis' => "{colors:['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']}", + 'width' => "550", + 'height' => "340", + 'theme' => 'maximized' + ); + $options = yourls_apply_filter( 'stats_countries_map_options', $options ); - $map = yourls_google_viz_code( 'GeoChart', $data, $options, $id ); + $map = yourls_google_viz_code( 'GeoChart', $data, $options, $id ); - echo yourls_apply_filter( 'stats_countries_map', $map, $countries, $options, $id ); + echo yourls_apply_filter( 'stats_countries_map', $map, $countries, $options, $id ); } @@ -44,49 +44,49 @@ function yourls_stats_countries_map($countries, $id = null) { */ function yourls_stats_pie($data, $limit = 10, $size = '340x220', $id = null) { - yourls_do_action( 'pre_stats_pie' ); - - // if $id is null then assign a random string - if( $id === null ) - $id = uniqid ( 'yourls_stats_pie_' ); - - // Trim array: $limit first item + the sum of all others - if ( count( $data ) > $limit ) { - $i= 0; - $trim_data = array( 'Others' => 0 ); - foreach( $data as $item=>$value ) { - $i++; - if( $i <= $limit ) { - $trim_data[$item] = $value; - } else { - $trim_data['Others'] += $value; - } - } - $data = $trim_data; - } - - // Scale items - $_data = yourls_scale_data( $data ); - - list($width, $height) = explode( 'x', $size ); - - $options = array( - 'theme' => 'maximized', - 'width' => $width, - 'height' => $height, - 'colors' => "['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']", - 'legend' => 'none', - 'chartArea' => '{top: "5%", height: "90%"}', - 'pieSliceText' => 'label', - ); - $options = yourls_apply_filter( 'stats_pie_options', $options ); - - $script_data = array_merge( array( 'Country' => 'Value' ), $_data ); - $script_data = yourls_google_array_to_data_table( $script_data ); - - $pie = yourls_google_viz_code( 'PieChart', $script_data, $options, $id ); - - echo yourls_apply_filter( 'stats_pie', $pie, $data, $limit, $size, $options, $id ); + yourls_do_action( 'pre_stats_pie' ); + + // if $id is null then assign a random string + if( $id === null ) + $id = uniqid ( 'yourls_stats_pie_' ); + + // Trim array: $limit first item + the sum of all others + if ( count( $data ) > $limit ) { + $i= 0; + $trim_data = array( 'Others' => 0 ); + foreach( $data as $item=>$value ) { + $i++; + if( $i <= $limit ) { + $trim_data[$item] = $value; + } else { + $trim_data['Others'] += $value; + } + } + $data = $trim_data; + } + + // Scale items + $_data = yourls_scale_data( $data ); + + list($width, $height) = explode( 'x', $size ); + + $options = array( + 'theme' => 'maximized', + 'width' => $width, + 'height' => $height, + 'colors' => "['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']", + 'legend' => 'none', + 'chartArea' => '{top: "5%", height: "90%"}', + 'pieSliceText' => 'label', + ); + $options = yourls_apply_filter( 'stats_pie_options', $options ); + + $script_data = array_merge( array( 'Country' => 'Value' ), $_data ); + $script_data = yourls_google_array_to_data_table( $script_data ); + + $pie = yourls_google_viz_code( 'PieChart', $script_data, $options, $id ); + + echo yourls_apply_filter( 'stats_pie', $pie, $data, $limit, $size, $options, $id ); } @@ -97,79 +97,79 @@ function yourls_stats_pie($data, $limit = 10, $size = '340x220', $id = null) { * @return array[] Array of arrays of days, months, years */ function yourls_build_list_of_days($dates) { - /* Say we have an array like: - $dates = array ( - 2009 => array ( - '08' => array ( - 29 => 15, - 30 => 5, - ), - '09' => array ( - '02' => 3, - '03' => 5, - '04' => 2, - '05' => 99, - ), - ), - ) - */ - - if( !$dates ) - return array(); - - // Get first & last years from our range. In our example: 2009 & 2009 - $first_year = key( $dates ); - $_keys = array_keys( $dates ); - $last_year = end( $_keys ); - reset( $dates ); - - // Get first & last months from our range. In our example: 08 & 09 - $first_month = key( $dates[ $first_year ] ); - $_keys = array_keys( $dates[ $last_year ] ); - $last_month = end( $_keys ); - reset( $dates ); - - // Get first & last days from our range. In our example: 29 & 05 - $first_day = key( $dates[ $first_year ][ $first_month ] ); - $_keys = array_keys( $dates[ $last_year ][ $last_month ] ); - $last_day = end( $_keys ); - - unset( $_keys ); - - // Extend to today - $today = new DateTime(); - $today->setTime( 0, 0, 0 ); // Start of today - $today_year = $today->format( 'Y' ); - $today_month = $today->format( 'm' ); - $today_day = $today->format( 'd' ); - - // Now build a list of all years (2009), month (08 & 09) and days (all from 2009-08-29 to 2009-09-05) - $list_of_years = array(); - $list_of_months = array(); - $list_of_days = array(); - for ( $year = $first_year; $year <= $today_year; $year++ ) { - $_year = sprintf( '%04d', $year ); - $list_of_years[ $_year ] = $_year; - $current_first_month = ( $year == $first_year ? $first_month : '01' ); - $current_last_month = ( $year == $today_year ? $today_month : '12' ); - for ( $month = $current_first_month; $month <= $current_last_month; $month++ ) { - $_month = sprintf( '%02d', $month ); - $list_of_months[ $_month ] = $_month; - $current_first_day = ( $year == $first_year && $month == $first_month ? $first_day : '01' ); - $current_last_day = ( $year == $today_year && $month == $today_month ? $today_day : yourls_days_in_month( $month, $year ) ); - for ( $day = $current_first_day; $day <= $current_last_day; $day++ ) { - $day = sprintf( '%02d', $day ); - $key = date( 'M d, Y', mktime( 0, 0, 0, $_month, $day, $_year ) ); - $list_of_days[ $key ] = isset( $dates[$_year][$_month][$day] ) ? $dates[$_year][$_month][$day] : 0; - } - } - } - - return array( - 'list_of_days' => $list_of_days, - 'list_of_months' => $list_of_months, - 'list_of_years' => $list_of_years, - ); + /* Say we have an array like: + $dates = array ( + 2009 => array ( + '08' => array ( + 29 => 15, + 30 => 5, + ), + '09' => array ( + '02' => 3, + '03' => 5, + '04' => 2, + '05' => 99, + ), + ), + ) + */ + + if( !$dates ) + return array(); + + // Get first & last years from our range. In our example: 2009 & 2009 + $first_year = key( $dates ); + $_keys = array_keys( $dates ); + $last_year = end( $_keys ); + reset( $dates ); + + // Get first & last months from our range. In our example: 08 & 09 + $first_month = key( $dates[ $first_year ] ); + $_keys = array_keys( $dates[ $last_year ] ); + $last_month = end( $_keys ); + reset( $dates ); + + // Get first & last days from our range. In our example: 29 & 05 + $first_day = key( $dates[ $first_year ][ $first_month ] ); + $_keys = array_keys( $dates[ $last_year ][ $last_month ] ); + $last_day = end( $_keys ); + + unset( $_keys ); + + // Extend to today + $today = new DateTime(); + $today->setTime( 0, 0, 0 ); // Start of today + $today_year = $today->format( 'Y' ); + $today_month = $today->format( 'm' ); + $today_day = $today->format( 'd' ); + + // Now build a list of all years (2009), month (08 & 09) and days (all from 2009-08-29 to 2009-09-05) + $list_of_years = array(); + $list_of_months = array(); + $list_of_days = array(); + for ( $year = $first_year; $year <= $today_year; $year++ ) { + $_year = sprintf( '%04d', $year ); + $list_of_years[ $_year ] = $_year; + $current_first_month = ( $year == $first_year ? $first_month : '01' ); + $current_last_month = ( $year == $today_year ? $today_month : '12' ); + for ( $month = $current_first_month; $month <= $current_last_month; $month++ ) { + $_month = sprintf( '%02d', $month ); + $list_of_months[ $_month ] = $_month; + $current_first_day = ( $year == $first_year && $month == $first_month ? $first_day : '01' ); + $current_last_day = ( $year == $today_year && $month == $today_month ? $today_day : yourls_days_in_month( $month, $year ) ); + for ( $day = $current_first_day; $day <= $current_last_day; $day++ ) { + $day = sprintf( '%02d', $day ); + $key = date( 'M d, Y', mktime( 0, 0, 0, $_month, $day, $_year ) ); + $list_of_days[ $key ] = isset( $dates[$_year][$_month][$day] ) ? $dates[$_year][$_month][$day] : 0; + } + } + } + + return array( + 'list_of_days' => $list_of_days, + 'list_of_months' => $list_of_months, + 'list_of_years' => $list_of_years, + ); } @@ -184,38 +184,38 @@ function yourls_build_list_of_days($dates) { */ function yourls_stats_line($values, $id = null) { - yourls_do_action( 'pre_stats_line' ); + yourls_do_action( 'pre_stats_line' ); - // if $id is null then assign a random string - if( $id === null ) - $id = uniqid ( 'yourls_stats_line_' ); + // if $id is null then assign a random string + if( $id === null ) + $id = uniqid ( 'yourls_stats_line_' ); - // If we have only 1 day of data, prepend a fake day with 0 hits for a prettier graph - if ( count( $values ) == 1 ) - array_unshift( $values, 0 ); + // If we have only 1 day of data, prepend a fake day with 0 hits for a prettier graph + if ( count( $values ) == 1 ) + array_unshift( $values, 0 ); - // Keep only a subset of values to keep graph smooth - $values = yourls_array_granularity( $values, 30 ); + // Keep only a subset of values to keep graph smooth + $values = yourls_array_granularity( $values, 30 ); - $data = array_merge( array( 'Time' => 'Hits' ), $values ); - $data = yourls_google_array_to_data_table( $data ); + $data = array_merge( array( 'Time' => 'Hits' ), $values ); + $data = yourls_google_array_to_data_table( $data ); - $options = array( - "legend" => "none", - "pointSize" => "3", - "theme" => "maximized", - "curveType" => "function", - "width" => 430, - "height" => 220, - "hAxis" => "{minTextSpacing: 80, maxTextLines: 1, maxAlternation: 1}", - "vAxis" => "{minValue: 0, format: '#'}", - "colors" => "['#2a85b3']", - ); - $options = yourls_apply_filter( 'stats_line_options', $options ); + $options = array( + "legend" => "none", + "pointSize" => "3", + "theme" => "maximized", + "curveType" => "function", + "width" => 430, + "height" => 220, + "hAxis" => "{minTextSpacing: 80, maxTextLines: 1, maxAlternation: 1}", + "vAxis" => "{minValue: 0, format: '#'}", + "colors" => "['#2a85b3']", + ); + $options = yourls_apply_filter( 'stats_line_options', $options ); - $lineChart = yourls_google_viz_code( 'LineChart', $data, $options, $id ); + $lineChart = yourls_google_viz_code( 'LineChart', $data, $options, $id ); - echo yourls_apply_filter( 'stats_line', $lineChart, $values, $options, $id ); + echo yourls_apply_filter( 'stats_line', $lineChart, $values, $options, $id ); } @@ -227,8 +227,8 @@ function yourls_stats_line($values, $id = null) { * @return int */ function yourls_days_in_month($month, $year) { - // calculate number of days in a month - return $month == 2 ? ( $year % 4 ? 28 : ( $year % 100 ? 29 : ( $year % 400 ? 28 : 29 ) ) ) : ( ( $month - 1 ) % 7 % 2 ? 30 : 31 ); + // calculate number of days in a month + return $month == 2 ? ( $year % 4 ? 28 : ( $year % 100 ? 29 : ( $year % 400 ? 28 : 29 ) ) ) : ( ( $month - 1 ) % 7 % 2 ? 30 : 31 ); } @@ -239,11 +239,11 @@ function yourls_days_in_month($month, $year) { * @return array */ function yourls_stats_get_best_day($list_of_days) { - $max = max( $list_of_days ); - foreach( $list_of_days as $k=>$v ) { - if ( $v == $max ) - return array( 'day' => $k, 'max' => $max ); - } + $max = max( $list_of_days ); + foreach( $list_of_days as $k=>$v ) { + if ( $v == $max ) + return array( 'day' => $k, 'max' => $max ); + } } /** @@ -254,19 +254,19 @@ function yourls_stats_get_best_day($list_of_days) { * @return string */ function yourls_get_domain($url, $include_scheme = false) { - $parse = @parse_url( $url ); // Hiding ugly stuff coming from malformed referrer URLs + $parse = @parse_url( $url ); // Hiding ugly stuff coming from malformed referrer URLs - // Get host & scheme. Fall back to path if not found. - $host = isset( $parse['host'] ) ? $parse['host'] : ''; - $scheme = isset( $parse['scheme'] ) ? $parse['scheme'] : ''; - $path = isset( $parse['path'] ) ? $parse['path'] : ''; - if( !$host ) - $host = $path; + // Get host & scheme. Fall back to path if not found. + $host = isset( $parse['host'] ) ? $parse['host'] : ''; + $scheme = isset( $parse['scheme'] ) ? $parse['scheme'] : ''; + $path = isset( $parse['path'] ) ? $parse['path'] : ''; + if( !$host ) + $host = $path; - if ( $include_scheme && $scheme ) - $host = $scheme.'://'.$host; + if ( $include_scheme && $scheme ) + $host = $scheme.'://'.$host; - return $host; + return $host; } @@ -277,7 +277,7 @@ function yourls_get_domain($url, $include_scheme = false) { * @return string */ function yourls_get_favicon_url($url) { - return yourls_match_current_protocol( '//www.google.com/s2/favicons?domain=' . yourls_get_domain( $url, false ) ); + return yourls_match_current_protocol( '//www.google.com/s2/favicons?domain=' . yourls_get_domain( $url, false ) ); } /** @@ -287,13 +287,13 @@ function yourls_get_favicon_url($url) { * @return array */ function yourls_scale_data($data ) { - $max = max( $data ); - if( $max > 100 ) { - foreach( $data as $k=>$v ) { - $data[$k] = intval( $v / $max * 100 ); - } - } - return $data; + $max = max( $data ); + if( $max > 100 ) { + foreach( $data as $k=>$v ) { + $data[$k] = intval( $v / $max * 100 ); + } + } + return $data; } @@ -309,24 +309,24 @@ function yourls_scale_data($data ) { * @return array */ function yourls_array_granularity($array, $grain = 100, $preserve_max = true) { - if ( count( $array ) > $grain ) { - $max = max( $array ); - $step = intval( count( $array ) / $grain ); - $i = 0; - // Loop through each item and unset except every $step (optional preserve the max value) - foreach( $array as $k=>$v ) { - $i++; - if ( $i % $step != 0 ) { - if ( $preserve_max == false ) { - unset( $array[$k] ); - } else { - if ( $v < $max ) - unset( $array[$k] ); - } - } - } - } - return $array; + if ( count( $array ) > $grain ) { + $max = max( $array ); + $step = intval( count( $array ) / $grain ); + $i = 0; + // Loop through each item and unset except every $step (optional preserve the max value) + foreach( $array as $k=>$v ) { + $i++; + if ( $i % $step != 0 ) { + if ( $preserve_max == false ) { + unset( $array[$k] ); + } else { + if ( $v < $max ) + unset( $array[$k] ); + } + } + } + } + return $array; } /** @@ -336,23 +336,23 @@ function yourls_array_granularity($array, $grain = 100, $preserve_max = true) { * @return string */ function yourls_google_array_to_data_table($data){ - $str = "var data = google.visualization.arrayToDataTable([\n"; - foreach( $data as $label => $values ){ - if( !is_array( $values ) ) { - $values = array( $values ); - } - $str .= "\t['$label',"; - foreach( $values as $value ){ - if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) { - $value = "'$value'"; - } - $str .= "$value"; - } - $str .= "],\n"; - } - $str = substr( $str, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return - $str .= "]);\n"; // wrap it up - return $str; + $str = "var data = google.visualization.arrayToDataTable([\n"; + foreach( $data as $label => $values ){ + if( !is_array( $values ) ) { + $values = array( $values ); + } + $str .= "\t['$label',"; + foreach( $values as $value ){ + if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) { + $value = "'$value'"; + } + $str .= "$value"; + } + $str .= "],\n"; + } + $str = substr( $str, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return + $str .= "]);\n"; // wrap it up + return $str; } /** @@ -365,27 +365,27 @@ function yourls_google_array_to_data_table($data){ * @return string */ function yourls_google_viz_code($graph_type, $data, $options, $id ) { - $function_name = 'yourls_graph' . $id; - $code = "\n\n"; - $code .= "
\n"; - - return $code; + $function_name = 'yourls_graph' . $id; + $code = "\n\n"; + $code .= "
\n"; + + return $code; } diff --git a/includes/functions-install.php b/includes/functions-install.php index b420cd1..bbf3e26 100644 --- a/includes/functions-install.php +++ b/includes/functions-install.php @@ -20,19 +20,19 @@ function yourls_check_database_version() { } /** - * Get DB version + * Get DB server version * * @since 1.7 * @return string sanitized DB version */ function yourls_get_database_version() { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_get_database_version', false ); - if ( false !== $pre ) { - return $pre; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_get_database_version', false ); + if ( false !== $pre ) { + return $pre; } - return yourls_sanitize_version(yourls_get_db()->mysql_version()); + return yourls_sanitize_version(yourls_get_db('read-get_database_version')->mysql_version()); } /** @@ -53,12 +53,12 @@ function yourls_check_php_version() { * @return bool */ function yourls_is_apache() { - if( !array_key_exists( 'SERVER_SOFTWARE', $_SERVER ) ) - return false; - return ( - strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache' ) !== false - || strpos( $_SERVER['SERVER_SOFTWARE'], 'LiteSpeed' ) !== false - ); + if( !array_key_exists( 'SERVER_SOFTWARE', $_SERVER ) ) + return false; + return ( + strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache' ) !== false + || strpos( $_SERVER['SERVER_SOFTWARE'], 'LiteSpeed' ) !== false + ); } /** @@ -67,7 +67,7 @@ function yourls_is_apache() { * @return bool */ function yourls_is_iis() { - return ( array_key_exists( 'SERVER_SOFTWARE', $_SERVER ) ? ( strpos( $_SERVER['SERVER_SOFTWARE'], 'IIS' ) !== false ) : false ); + return ( array_key_exists( 'SERVER_SOFTWARE', $_SERVER ) ? ( strpos( $_SERVER['SERVER_SOFTWARE'], 'IIS' ) !== false ) : false ); } @@ -77,55 +77,55 @@ function yourls_is_iis() { * @return bool */ function yourls_create_htaccess() { - $host = parse_url( yourls_get_yourls_site() ); - $path = ( isset( $host['path'] ) ? $host['path'] : '' ); - - if ( yourls_is_iis() ) { - // Prepare content for a web.config file - $content = array( - '', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - ); - - $filename = YOURLS_ABSPATH.'/web.config'; - $marker = 'none'; - - } else { - // Prepare content for a .htaccess file - $content = array( - '', - 'RewriteEngine On', - 'RewriteBase '.$path.'/', - 'RewriteCond %{REQUEST_FILENAME} !-f', - 'RewriteCond %{REQUEST_FILENAME} !-d', - 'RewriteRule ^.*$ '.$path.'/yourls-loader.php [L]', - '', - ); - - $filename = YOURLS_ABSPATH.'/.htaccess'; - $marker = 'YOURLS'; - - } - - return ( yourls_insert_with_markers( $filename, $marker, $content ) ); + $host = parse_url( yourls_get_yourls_site() ); + $path = ( isset( $host['path'] ) ? $host['path'] : '' ); + + if ( yourls_is_iis() ) { + // Prepare content for a web.config file + $content = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '', + ); + + $filename = YOURLS_ABSPATH.'/web.config'; + $marker = 'none'; + + } else { + // Prepare content for a .htaccess file + $content = array( + '', + 'RewriteEngine On', + 'RewriteBase '.$path.'/', + 'RewriteCond %{REQUEST_FILENAME} !-f', + 'RewriteCond %{REQUEST_FILENAME} !-d', + 'RewriteRule ^.*$ '.$path.'/yourls-loader.php [L]', + '', + ); + + $filename = YOURLS_ABSPATH.'/.htaccess'; + $marker = 'YOURLS'; + + } + + return ( yourls_insert_with_markers( $filename, $marker, $content ) ); } /** @@ -143,54 +143,54 @@ function yourls_create_htaccess() { * @return bool True on write success, false on failure. */ function yourls_insert_with_markers( $filename, $marker, $insertion ) { - if ( !file_exists( $filename ) || is_writeable( $filename ) ) { - if ( !file_exists( $filename ) ) { - $markerdata = ''; - } else { - $markerdata = explode( "\n", implode( '', file( $filename ) ) ); - } - - if ( !$f = @fopen( $filename, 'w' ) ) - return false; - - $foundit = false; - if ( $markerdata ) { - $state = true; - foreach ( $markerdata as $n => $markerline ) { - if ( strpos( $markerline, '# BEGIN ' . $marker ) !== false ) - $state = false; - if ( $state ) { - if ( $n + 1 < count( $markerdata ) ) - fwrite( $f, "{$markerline}\n" ); - else - fwrite( $f, "{$markerline}" ); - } - if ( strpos( $markerline, '# END ' . $marker ) !== false ) { - if ( $marker != 'none' ) - fwrite( $f, "# BEGIN {$marker}\n" ); - if ( is_array( $insertion ) ) - foreach ( $insertion as $insertline ) - fwrite( $f, "{$insertline}\n" ); - if ( $marker != 'none' ) - fwrite( $f, "# END {$marker}\n" ); - $state = true; - $foundit = true; - } - } - } - if ( !$foundit ) { - if ( $marker != 'none' ) - fwrite( $f, "\n\n# BEGIN {$marker}\n" ); - foreach ( $insertion as $insertline ) - fwrite( $f, "{$insertline}\n" ); - if ( $marker != 'none' ) - fwrite( $f, "# END {$marker}\n\n" ); - } - fclose( $f ); - return true; - } else { - return false; - } + if ( !file_exists( $filename ) || is_writeable( $filename ) ) { + if ( !file_exists( $filename ) ) { + $markerdata = ''; + } else { + $markerdata = explode( "\n", implode( '', file( $filename ) ) ); + } + + if ( !$f = @fopen( $filename, 'w' ) ) + return false; + + $foundit = false; + if ( $markerdata ) { + $state = true; + foreach ( $markerdata as $n => $markerline ) { + if ( strpos( $markerline, '# BEGIN ' . $marker ) !== false ) + $state = false; + if ( $state ) { + if ( $n + 1 < count( $markerdata ) ) + fwrite( $f, "{$markerline}\n" ); + else + fwrite( $f, "{$markerline}" ); + } + if ( strpos( $markerline, '# END ' . $marker ) !== false ) { + if ( $marker != 'none' ) + fwrite( $f, "# BEGIN {$marker}\n" ); + if ( is_array( $insertion ) ) + foreach ( $insertion as $insertline ) + fwrite( $f, "{$insertline}\n" ); + if ( $marker != 'none' ) + fwrite( $f, "# END {$marker}\n" ); + $state = true; + $foundit = true; + } + } + } + if ( !$foundit ) { + if ( $marker != 'none' ) + fwrite( $f, "\n\n# BEGIN {$marker}\n" ); + foreach ( $insertion as $insertline ) + fwrite( $f, "{$insertline}\n" ); + if ( $marker != 'none' ) + fwrite( $f, "# END {$marker}\n\n" ); + } + fclose( $f ); + return true; + } else { + return false; + } } /** @@ -207,14 +207,14 @@ function yourls_create_sql_tables() { return $pre; } - $ydb = yourls_get_db(); + $ydb = yourls_get_db('write-create_sql_tables'); - $error_msg = array(); - $success_msg = array(); + $error_msg = array(); + $success_msg = array(); - // Create Table Query - $create_tables = array(); - $create_tables[YOURLS_DB_TABLE_URL] = + // Create Table Query + $create_tables = array(); + $create_tables[YOURLS_DB_TABLE_URL] = 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_URL.'` ('. '`keyword` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT \'\','. '`url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,'. @@ -224,64 +224,65 @@ function yourls_create_sql_tables() { '`clicks` int(10) unsigned NOT NULL,'. 'PRIMARY KEY (`keyword`),'. 'KEY `ip` (`ip`),'. - 'KEY `timestamp` (`timestamp`)'. + 'KEY `timestamp` (`timestamp`),'. + 'KEY `url_idx` (`url`(30))'. ') DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;'; - $create_tables[YOURLS_DB_TABLE_OPTIONS] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_OPTIONS.'` ('. - '`option_id` bigint(20) unsigned NOT NULL auto_increment,'. - '`option_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL default \'\','. - '`option_value` longtext COLLATE utf8mb4_unicode_ci NOT NULL,'. - 'PRIMARY KEY (`option_id`,`option_name`),'. - 'KEY `option_name` (`option_name`)'. - ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; - - $create_tables[YOURLS_DB_TABLE_LOG] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_LOG.'` ('. - '`click_id` int(11) NOT NULL auto_increment,'. - '`click_time` datetime NOT NULL,'. - '`shorturl` varchar(100) BINARY NOT NULL,'. - '`referrer` varchar(200) NOT NULL,'. - '`user_agent` varchar(255) NOT NULL,'. - '`ip_address` varchar(41) NOT NULL,'. - '`country_code` char(2) NOT NULL,'. - 'PRIMARY KEY (`click_id`),'. - 'KEY `shorturl` (`shorturl`)'. - ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; - - - $create_table_count = 0; + $create_tables[YOURLS_DB_TABLE_OPTIONS] = + 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_OPTIONS.'` ('. + '`option_id` bigint(20) unsigned NOT NULL auto_increment,'. + '`option_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL default \'\','. + '`option_value` longtext COLLATE utf8mb4_unicode_ci NOT NULL,'. + 'PRIMARY KEY (`option_id`,`option_name`),'. + 'KEY `option_name` (`option_name`)'. + ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; + + $create_tables[YOURLS_DB_TABLE_LOG] = + 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_LOG.'` ('. + '`click_id` int(11) NOT NULL auto_increment,'. + '`click_time` datetime NOT NULL,'. + '`shorturl` varchar(100) BINARY NOT NULL,'. + '`referrer` varchar(200) NOT NULL,'. + '`user_agent` varchar(255) NOT NULL,'. + '`ip_address` varchar(41) NOT NULL,'. + '`country_code` char(2) NOT NULL,'. + 'PRIMARY KEY (`click_id`),'. + 'KEY `shorturl` (`shorturl`)'. + ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; + + + $create_table_count = 0; yourls_debug_mode(true); - // Create tables - foreach ( $create_tables as $table_name => $table_query ) { - $ydb->perform( $table_query ); - $create_success = $ydb->fetchAffected( "SHOW TABLES LIKE '$table_name'" ); - if( $create_success ) { - $create_table_count++; - $success_msg[] = yourls_s( "Table '%s' created.", $table_name ); - } else { - $error_msg[] = yourls_s( "Error creating table '%s'.", $table_name ); - } - } - - // Initializes the option table - if( !yourls_initialize_options() ) - $error_msg[] = yourls__( 'Could not initialize options' ); - - // Insert sample links - if( !yourls_insert_sample_links() ) - $error_msg[] = yourls__( 'Could not insert sample short URLs' ); - - // Check results of operations - if ( sizeof( $create_tables ) == $create_table_count ) { - $success_msg[] = yourls__( 'YOURLS tables successfully created.' ); - } else { - $error_msg[] = yourls__( 'Error creating YOURLS tables.' ); - } - - return array( 'success' => $success_msg, 'error' => $error_msg ); + // Create tables + foreach ( $create_tables as $table_name => $table_query ) { + $ydb->perform( $table_query ); + $create_success = $ydb->fetchAffected( "SHOW TABLES LIKE '$table_name'" ); + if( $create_success ) { + $create_table_count++; + $success_msg[] = yourls_s( "Table '%s' created.", $table_name ); + } else { + $error_msg[] = yourls_s( "Error creating table '%s'.", $table_name ); + } + } + + // Initializes the option table + if( !yourls_initialize_options() ) + $error_msg[] = yourls__( 'Could not initialize options' ); + + // Insert sample links + if( !yourls_insert_sample_links() ) + $error_msg[] = yourls__( 'Could not insert sample short URLs' ); + + // Check results of operations + if ( sizeof( $create_tables ) == $create_table_count ) { + $success_msg[] = yourls__( 'YOURLS tables successfully created.' ); + } else { + $error_msg[] = yourls__( 'Error creating YOURLS tables.' ); + } + + return array( 'success' => $success_msg, 'error' => $error_msg ); } /** @@ -295,12 +296,12 @@ function yourls_create_sql_tables() { * @return bool */ function yourls_initialize_options() { - return ( bool ) ( - yourls_update_option( 'version', YOURLS_VERSION ) - & yourls_update_option( 'db_version', YOURLS_DB_VERSION ) - & yourls_update_option( 'next_id', 1 ) + return ( bool ) ( + yourls_update_option( 'version', YOURLS_VERSION ) + & yourls_update_option( 'db_version', YOURLS_DB_VERSION ) + & yourls_update_option( 'next_id', 1 ) & yourls_update_option( 'active_plugins', array() ) - ); + ); } /** @@ -310,14 +311,14 @@ function yourls_initialize_options() { * @return bool */ function yourls_insert_sample_links() { - $link1 = yourls_add_new_link( 'https://blog.yourls.org/', 'yourlsblog', 'YOURLS\' Blog' ); - $link2 = yourls_add_new_link( 'https://yourls.org/', 'yourls', 'YOURLS: Your Own URL Shortener' ); - $link3 = yourls_add_new_link( 'https://ozh.org/', 'ozh', 'ozh.org' ); - return ( bool ) ( - $link1['status'] == 'success' - & $link2['status'] == 'success' - & $link3['status'] == 'success' - ); + $link1 = yourls_add_new_link( 'https://blog.yourls.org/', 'yourlsblog', 'YOURLS\' Blog' ); + $link2 = yourls_add_new_link( 'https://yourls.org/', 'yourls', 'YOURLS: Your Own URL Shortener' ); + $link3 = yourls_add_new_link( 'https://ozh.org/', 'ozh', 'ozh.org' ); + return ( bool ) ( + $link1['status'] == 'success' + & $link2['status'] == 'success' + & $link3['status'] == 'success' + ); } @@ -329,23 +330,23 @@ function yourls_insert_sample_links() { */ function yourls_maintenance_mode( $maintenance = true ) { - $file = YOURLS_ABSPATH . '/.maintenance' ; + $file = YOURLS_ABSPATH . '/.maintenance' ; - // Turn maintenance mode on : create .maintenance file - if ( (bool)$maintenance ) { - if ( ! ( $fp = @fopen( $file, 'w' ) ) ) - return false; + // Turn maintenance mode on : create .maintenance file + if ( (bool)$maintenance ) { + if ( ! ( $fp = @fopen( $file, 'w' ) ) ) + return false; - $maintenance_string = ''; - @fwrite( $fp, $maintenance_string ); - @fclose( $fp ); - @chmod( $file, 0644 ); // Read and write for owner, read for everybody else + $maintenance_string = ''; + @fwrite( $fp, $maintenance_string ); + @fclose( $fp ); + @chmod( $file, 0644 ); // Read and write for owner, read for everybody else - // Not sure why the fwrite would fail if the fopen worked... Just in case - return( is_readable( $file ) ); + // Not sure why the fwrite would fail if the fopen worked... Just in case + return( is_readable( $file ) ); - // Turn maintenance mode off : delete the .maintenance file - } else { - return @unlink($file); - } + // Turn maintenance mode off : delete the .maintenance file + } else { + return @unlink($file); + } } diff --git a/includes/functions-kses.php b/includes/functions-kses.php index 08a20a2..7a81ffd 100644 --- a/includes/functions-kses.php +++ b/includes/functions-kses.php @@ -52,37 +52,37 @@ * @return void */ function yourls_kses_init() { - global $yourls_allowedentitynames, $yourls_allowedprotocols; - - if( ! $yourls_allowedentitynames ) { - $yourls_allowedentitynames = yourls_apply_filter( 'kses_allowed_entities', yourls_kses_allowed_entities() ); - } - - if( ! $yourls_allowedprotocols ) { - $yourls_allowedprotocols = yourls_apply_filter( 'kses_allowed_protocols', yourls_kses_allowed_protocols() ); - } - - /** See NOTE ABOUT GLOBALS ** - - if( ! $yourls_allowedtags_all ) { - $yourls_allowedtags_all = yourls_kses_allowed_tags_all(); - $yourls_allowedtags_all = array_map( '_yourls_add_global_attributes', $yourls_allowedtags_all ); - $yourls_allowedtags_all = yourls_apply_filter( 'kses_allowed_tags_all', $yourls_allowedtags_all ); - } else { - // User defined: let's sanitize - $yourls_allowedtags_all = yourls_kses_array_lc( $yourls_allowedtags_all ); - } - - if( ! $yourls_allowedtags ) { - $yourls_allowedtags = yourls_kses_allowed_tags(); - $yourls_allowedtags = array_map( '_yourls_add_global_attributes', $yourls_allowedtags ); - $yourls_allowedtags = yourls_apply_filter( 'kses_allowed_tags', $yourls_allowedtags ); - } else { - // User defined: let's sanitize - $yourls_allowedtags = yourls_kses_array_lc( $yourls_allowedtags ); - } - - /**/ + global $yourls_allowedentitynames, $yourls_allowedprotocols; + + if( ! $yourls_allowedentitynames ) { + $yourls_allowedentitynames = yourls_apply_filter( 'kses_allowed_entities', yourls_kses_allowed_entities() ); + } + + if( ! $yourls_allowedprotocols ) { + $yourls_allowedprotocols = yourls_apply_filter( 'kses_allowed_protocols', yourls_kses_allowed_protocols() ); + } + + /** See NOTE ABOUT GLOBALS ** + + if( ! $yourls_allowedtags_all ) { + $yourls_allowedtags_all = yourls_kses_allowed_tags_all(); + $yourls_allowedtags_all = array_map( '_yourls_add_global_attributes', $yourls_allowedtags_all ); + $yourls_allowedtags_all = yourls_apply_filter( 'kses_allowed_tags_all', $yourls_allowedtags_all ); + } else { + // User defined: let's sanitize + $yourls_allowedtags_all = yourls_kses_array_lc( $yourls_allowedtags_all ); + } + + if( ! $yourls_allowedtags ) { + $yourls_allowedtags = yourls_kses_allowed_tags(); + $yourls_allowedtags = array_map( '_yourls_add_global_attributes', $yourls_allowedtags ); + $yourls_allowedtags = yourls_apply_filter( 'kses_allowed_tags', $yourls_allowedtags ); + } else { + // User defined: let's sanitize + $yourls_allowedtags = yourls_kses_array_lc( $yourls_allowedtags ); + } + + /**/ } /** @@ -96,320 +96,320 @@ function yourls_kses_init() { * @return array All tags */ function yourls_kses_allowed_tags_all() { - return array( - 'address' => array(), - 'a' => array( - 'href' => true, - 'rel' => true, - 'rev' => true, - 'name' => true, - 'target' => true, - ), - 'abbr' => array(), - 'acronym' => array(), - 'area' => array( - 'alt' => true, - 'coords' => true, - 'href' => true, - 'nohref' => true, - 'shape' => true, - 'target' => true, - ), - 'article' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'aside' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'b' => array(), - 'big' => array(), - 'blockquote' => array( - 'cite' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'br' => array(), - 'button' => array( - 'disabled' => true, - 'name' => true, - 'type' => true, - 'value' => true, - ), - 'caption' => array( - 'align' => true, - ), - 'cite' => array( - 'dir' => true, - 'lang' => true, - ), - 'code' => array(), - 'col' => array( - 'align' => true, - 'char' => true, - 'charoff' => true, - 'span' => true, - 'dir' => true, - 'valign' => true, - 'width' => true, - ), - 'del' => array( - 'datetime' => true, - ), - 'dd' => array(), - 'details' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'open' => true, - 'xml:lang' => true, - ), - 'div' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'dl' => array(), - 'dt' => array(), - 'em' => array(), - 'fieldset' => array(), - 'figure' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'figcaption' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'font' => array( - 'color' => true, - 'face' => true, - 'size' => true, - ), - 'footer' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'form' => array( - 'action' => true, - 'accept' => true, - 'accept-charset' => true, - 'enctype' => true, - 'method' => true, - 'name' => true, - 'target' => true, - ), - 'h1' => array( - 'align' => true, - ), - 'h2' => array( - 'align' => true, - ), - 'h3' => array( - 'align' => true, - ), - 'h4' => array( - 'align' => true, - ), - 'h5' => array( - 'align' => true, - ), - 'h6' => array( - 'align' => true, - ), - 'header' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'hgroup' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'hr' => array( - 'align' => true, - 'noshade' => true, - 'size' => true, - 'width' => true, - ), - 'i' => array(), - 'img' => array( - 'alt' => true, - 'align' => true, - 'border' => true, - 'height' => true, - 'hspace' => true, - 'longdesc' => true, - 'vspace' => true, - 'src' => true, - 'usemap' => true, - 'width' => true, - ), - 'ins' => array( - 'datetime' => true, - 'cite' => true, - ), - 'kbd' => array(), - 'label' => array( - 'for' => true, - ), - 'legend' => array( - 'align' => true, - ), - 'li' => array( - 'align' => true, - ), - 'map' => array( - 'name' => true, - ), - 'menu' => array( - 'type' => true, - ), - 'nav' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'p' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'pre' => array( - 'width' => true, - ), - 'q' => array( - 'cite' => true, - ), - 's' => array(), - 'span' => array( - 'dir' => true, - 'align' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'section' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'small' => array(), - 'strike' => array(), - 'strong' => array(), - 'sub' => array(), - 'summary' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'sup' => array(), - 'table' => array( - 'align' => true, - 'bgcolor' => true, - 'border' => true, - 'cellpadding' => true, - 'cellspacing' => true, - 'dir' => true, - 'rules' => true, - 'summary' => true, - 'width' => true, - ), - 'tbody' => array( - 'align' => true, - 'char' => true, - 'charoff' => true, - 'valign' => true, - ), - 'td' => array( - 'abbr' => true, - 'align' => true, - 'axis' => true, - 'bgcolor' => true, - 'char' => true, - 'charoff' => true, - 'colspan' => true, - 'dir' => true, - 'headers' => true, - 'height' => true, - 'nowrap' => true, - 'rowspan' => true, - 'scope' => true, - 'valign' => true, - 'width' => true, - ), - 'textarea' => array( - 'cols' => true, - 'rows' => true, - 'disabled' => true, - 'name' => true, - 'readonly' => true, - ), - 'tfoot' => array( - 'align' => true, - 'char' => true, - 'charoff' => true, - 'valign' => true, - ), - 'th' => array( - 'abbr' => true, - 'align' => true, - 'axis' => true, - 'bgcolor' => true, - 'char' => true, - 'charoff' => true, - 'colspan' => true, - 'headers' => true, - 'height' => true, - 'nowrap' => true, - 'rowspan' => true, - 'scope' => true, - 'valign' => true, - 'width' => true, - ), - 'thead' => array( - 'align' => true, - 'char' => true, - 'charoff' => true, - 'valign' => true, - ), - 'title' => array(), - 'tr' => array( - 'align' => true, - 'bgcolor' => true, - 'char' => true, - 'charoff' => true, - 'valign' => true, - ), - 'tt' => array(), - 'u' => array(), - 'ul' => array( - 'type' => true, - ), - 'ol' => array( - 'start' => true, - 'type' => true, - ), - 'var' => array(), - ); + return array( + 'address' => array(), + 'a' => array( + 'href' => true, + 'rel' => true, + 'rev' => true, + 'name' => true, + 'target' => true, + ), + 'abbr' => array(), + 'acronym' => array(), + 'area' => array( + 'alt' => true, + 'coords' => true, + 'href' => true, + 'nohref' => true, + 'shape' => true, + 'target' => true, + ), + 'article' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'aside' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'b' => array(), + 'big' => array(), + 'blockquote' => array( + 'cite' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'br' => array(), + 'button' => array( + 'disabled' => true, + 'name' => true, + 'type' => true, + 'value' => true, + ), + 'caption' => array( + 'align' => true, + ), + 'cite' => array( + 'dir' => true, + 'lang' => true, + ), + 'code' => array(), + 'col' => array( + 'align' => true, + 'char' => true, + 'charoff' => true, + 'span' => true, + 'dir' => true, + 'valign' => true, + 'width' => true, + ), + 'del' => array( + 'datetime' => true, + ), + 'dd' => array(), + 'details' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'open' => true, + 'xml:lang' => true, + ), + 'div' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'dl' => array(), + 'dt' => array(), + 'em' => array(), + 'fieldset' => array(), + 'figure' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'figcaption' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'font' => array( + 'color' => true, + 'face' => true, + 'size' => true, + ), + 'footer' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'form' => array( + 'action' => true, + 'accept' => true, + 'accept-charset' => true, + 'enctype' => true, + 'method' => true, + 'name' => true, + 'target' => true, + ), + 'h1' => array( + 'align' => true, + ), + 'h2' => array( + 'align' => true, + ), + 'h3' => array( + 'align' => true, + ), + 'h4' => array( + 'align' => true, + ), + 'h5' => array( + 'align' => true, + ), + 'h6' => array( + 'align' => true, + ), + 'header' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'hgroup' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'hr' => array( + 'align' => true, + 'noshade' => true, + 'size' => true, + 'width' => true, + ), + 'i' => array(), + 'img' => array( + 'alt' => true, + 'align' => true, + 'border' => true, + 'height' => true, + 'hspace' => true, + 'longdesc' => true, + 'vspace' => true, + 'src' => true, + 'usemap' => true, + 'width' => true, + ), + 'ins' => array( + 'datetime' => true, + 'cite' => true, + ), + 'kbd' => array(), + 'label' => array( + 'for' => true, + ), + 'legend' => array( + 'align' => true, + ), + 'li' => array( + 'align' => true, + ), + 'map' => array( + 'name' => true, + ), + 'menu' => array( + 'type' => true, + ), + 'nav' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'p' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'pre' => array( + 'width' => true, + ), + 'q' => array( + 'cite' => true, + ), + 's' => array(), + 'span' => array( + 'dir' => true, + 'align' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'section' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'small' => array(), + 'strike' => array(), + 'strong' => array(), + 'sub' => array(), + 'summary' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'sup' => array(), + 'table' => array( + 'align' => true, + 'bgcolor' => true, + 'border' => true, + 'cellpadding' => true, + 'cellspacing' => true, + 'dir' => true, + 'rules' => true, + 'summary' => true, + 'width' => true, + ), + 'tbody' => array( + 'align' => true, + 'char' => true, + 'charoff' => true, + 'valign' => true, + ), + 'td' => array( + 'abbr' => true, + 'align' => true, + 'axis' => true, + 'bgcolor' => true, + 'char' => true, + 'charoff' => true, + 'colspan' => true, + 'dir' => true, + 'headers' => true, + 'height' => true, + 'nowrap' => true, + 'rowspan' => true, + 'scope' => true, + 'valign' => true, + 'width' => true, + ), + 'textarea' => array( + 'cols' => true, + 'rows' => true, + 'disabled' => true, + 'name' => true, + 'readonly' => true, + ), + 'tfoot' => array( + 'align' => true, + 'char' => true, + 'charoff' => true, + 'valign' => true, + ), + 'th' => array( + 'abbr' => true, + 'align' => true, + 'axis' => true, + 'bgcolor' => true, + 'char' => true, + 'charoff' => true, + 'colspan' => true, + 'headers' => true, + 'height' => true, + 'nowrap' => true, + 'rowspan' => true, + 'scope' => true, + 'valign' => true, + 'width' => true, + ), + 'thead' => array( + 'align' => true, + 'char' => true, + 'charoff' => true, + 'valign' => true, + ), + 'title' => array(), + 'tr' => array( + 'align' => true, + 'bgcolor' => true, + 'char' => true, + 'charoff' => true, + 'valign' => true, + ), + 'tt' => array(), + 'u' => array(), + 'ul' => array( + 'type' => true, + ), + 'ol' => array( + 'start' => true, + 'type' => true, + ), + 'var' => array(), + ); } /** @@ -422,34 +422,34 @@ function yourls_kses_allowed_tags_all() { * @return array Allowed tags */ function yourls_kses_allowed_tags() { - return array( - 'a' => array( - 'href' => true, - 'title' => true, - ), - 'abbr' => array( - 'title' => true, - ), - 'acronym' => array( - 'title' => true, - ), - 'b' => array(), - 'blockquote' => array( - 'cite' => true, - ), - 'cite' => array(), - 'code' => array(), - 'del' => array( - 'datetime' => true, - ), - 'em' => array(), - 'i' => array(), - 'q' => array( - 'cite' => true, - ), - 'strike' => array(), - 'strong' => array(), - ); + return array( + 'a' => array( + 'href' => true, + 'title' => true, + ), + 'abbr' => array( + 'title' => true, + ), + 'acronym' => array( + 'title' => true, + ), + 'b' => array(), + 'blockquote' => array( + 'cite' => true, + ), + 'cite' => array(), + 'code' => array(), + 'del' => array( + 'datetime' => true, + ), + 'em' => array(), + 'i' => array(), + 'q' => array( + 'cite' => true, + ), + 'strike' => array(), + 'strong' => array(), + ); } /** @@ -460,49 +460,49 @@ function yourls_kses_allowed_tags() { * @return array Allowed entities */ function yourls_kses_allowed_entities() { - return array( - 'nbsp', 'iexcl', 'cent', 'pound', 'curren', 'yen', - 'brvbar', 'sect', 'uml', 'copy', 'ordf', 'laquo', - 'not', 'shy', 'reg', 'macr', 'deg', 'plusmn', - 'acute', 'micro', 'para', 'middot', 'cedil', 'ordm', - 'raquo', 'iquest', 'Agrave', 'Aacute', 'Acirc', 'Atilde', - 'Auml', 'Aring', 'AElig', 'Ccedil', 'Egrave', 'Eacute', - 'Ecirc', 'Euml', 'Igrave', 'Iacute', 'Icirc', 'Iuml', - 'ETH', 'Ntilde', 'Ograve', 'Oacute', 'Ocirc', 'Otilde', - 'Ouml', 'times', 'Oslash', 'Ugrave', 'Uacute', 'Ucirc', - 'Uuml', 'Yacute', 'THORN', 'szlig', 'agrave', 'aacute', - 'acirc', 'atilde', 'auml', 'aring', 'aelig', 'ccedil', - 'egrave', 'eacute', 'ecirc', 'euml', 'igrave', 'iacute', - 'icirc', 'iuml', 'eth', 'ntilde', 'ograve', 'oacute', - 'ocirc', 'otilde', 'ouml', 'divide', 'oslash', 'ugrave', - 'uacute', 'ucirc', 'uuml', 'yacute', 'thorn', 'yuml', - 'quot', 'amp', 'lt', 'gt', 'apos', 'OElig', - 'oelig', 'Scaron', 'scaron', 'Yuml', 'circ', 'tilde', - 'ensp', 'emsp', 'thinsp', 'zwnj', 'zwj', 'lrm', - 'rlm', 'ndash', 'mdash', 'lsquo', 'rsquo', 'sbquo', - 'ldquo', 'rdquo', 'bdquo', 'dagger', 'Dagger', 'permil', - 'lsaquo', 'rsaquo', 'euro', 'fnof', 'Alpha', 'Beta', - 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', - 'Iota', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Xi', - 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon', - 'Phi', 'Chi', 'Psi', 'Omega', 'alpha', 'beta', - 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', - 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', - 'omicron', 'pi', 'rho', 'sigmaf', 'sigma', 'tau', - 'upsilon', 'phi', 'chi', 'psi', 'omega', 'thetasym', - 'upsih', 'piv', 'bull', 'hellip', 'prime', 'Prime', - 'oline', 'frasl', 'weierp', 'image', 'real', 'trade', - 'alefsym', 'larr', 'uarr', 'rarr', 'darr', 'harr', - 'crarr', 'lArr', 'uArr', 'rArr', 'dArr', 'hArr', - 'forall', 'part', 'exist', 'empty', 'nabla', 'isin', - 'notin', 'ni', 'prod', 'sum', 'minus', 'lowast', - 'radic', 'prop', 'infin', 'ang', 'and', 'or', - 'cap', 'cup', 'int', 'sim', 'cong', 'asymp', - 'ne', 'equiv', 'le', 'ge', 'sub', 'sup', - 'nsub', 'sube', 'supe', 'oplus', 'otimes', 'perp', - 'sdot', 'lceil', 'rceil', 'lfloor', 'rfloor', 'lang', - 'rang', 'loz', 'spades', 'clubs', 'hearts', 'diams', - ); + return array( + 'nbsp', 'iexcl', 'cent', 'pound', 'curren', 'yen', + 'brvbar', 'sect', 'uml', 'copy', 'ordf', 'laquo', + 'not', 'shy', 'reg', 'macr', 'deg', 'plusmn', + 'acute', 'micro', 'para', 'middot', 'cedil', 'ordm', + 'raquo', 'iquest', 'Agrave', 'Aacute', 'Acirc', 'Atilde', + 'Auml', 'Aring', 'AElig', 'Ccedil', 'Egrave', 'Eacute', + 'Ecirc', 'Euml', 'Igrave', 'Iacute', 'Icirc', 'Iuml', + 'ETH', 'Ntilde', 'Ograve', 'Oacute', 'Ocirc', 'Otilde', + 'Ouml', 'times', 'Oslash', 'Ugrave', 'Uacute', 'Ucirc', + 'Uuml', 'Yacute', 'THORN', 'szlig', 'agrave', 'aacute', + 'acirc', 'atilde', 'auml', 'aring', 'aelig', 'ccedil', + 'egrave', 'eacute', 'ecirc', 'euml', 'igrave', 'iacute', + 'icirc', 'iuml', 'eth', 'ntilde', 'ograve', 'oacute', + 'ocirc', 'otilde', 'ouml', 'divide', 'oslash', 'ugrave', + 'uacute', 'ucirc', 'uuml', 'yacute', 'thorn', 'yuml', + 'quot', 'amp', 'lt', 'gt', 'apos', 'OElig', + 'oelig', 'Scaron', 'scaron', 'Yuml', 'circ', 'tilde', + 'ensp', 'emsp', 'thinsp', 'zwnj', 'zwj', 'lrm', + 'rlm', 'ndash', 'mdash', 'lsquo', 'rsquo', 'sbquo', + 'ldquo', 'rdquo', 'bdquo', 'dagger', 'Dagger', 'permil', + 'lsaquo', 'rsaquo', 'euro', 'fnof', 'Alpha', 'Beta', + 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', + 'Iota', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Xi', + 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon', + 'Phi', 'Chi', 'Psi', 'Omega', 'alpha', 'beta', + 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', + 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', + 'omicron', 'pi', 'rho', 'sigmaf', 'sigma', 'tau', + 'upsilon', 'phi', 'chi', 'psi', 'omega', 'thetasym', + 'upsih', 'piv', 'bull', 'hellip', 'prime', 'Prime', + 'oline', 'frasl', 'weierp', 'image', 'real', 'trade', + 'alefsym', 'larr', 'uarr', 'rarr', 'darr', 'harr', + 'crarr', 'lArr', 'uArr', 'rArr', 'dArr', 'hArr', + 'forall', 'part', 'exist', 'empty', 'nabla', 'isin', + 'notin', 'ni', 'prod', 'sum', 'minus', 'lowast', + 'radic', 'prop', 'infin', 'ang', 'and', 'or', + 'cap', 'cup', 'int', 'sim', 'cong', 'asymp', + 'ne', 'equiv', 'le', 'ge', 'sub', 'sup', + 'nsub', 'sube', 'supe', 'oplus', 'otimes', 'perp', + 'sdot', 'lceil', 'rceil', 'lfloor', 'rfloor', 'lang', + 'rang', 'loz', 'spades', 'clubs', 'hearts', 'diams', + ); } /** @@ -513,51 +513,51 @@ function yourls_kses_allowed_entities() { * @return array Allowed protocols */ function yourls_kses_allowed_protocols() { - // More or less common stuff in links. From http://en.wikipedia.org/wiki/URI_scheme - return array( - // Common - 'http://', 'https://', 'ftp://', - 'file://', 'smb://', - 'sftp://', - 'feed:', 'feed://', - 'mailto:', - 'news:', 'nntp://', - - // Old school bearded geek - 'gopher://', 'telnet://', 'finger://', - 'nntp://', 'worldwind://', - - // Dev - 'ssh://', 'svn://', 'svn+ssh://', 'git://', 'cvs://', - 'apt:', - 'market://', // Google Play - 'view-source:', - - // P2P - 'ed2k://', 'magnet:', 'udp://', - - // Streaming stuff - 'mms://', 'lastfm://', 'spotify:', 'rtsp://', - - // Text & voice - 'aim:', 'facetime://', 'gtalk:', 'xmpp:', - 'irc://', 'ircs://', 'mumble://', - 'callto:', 'skype:', 'sip:', - 'teamspeak://', 'tel:', 'ventrilo://', 'xfire:', - 'ymsgr:', 'tg://', 'whatsapp://', - - // Misc - 'steam:', 'steam://', - 'bitcoin:', - 'ldap://', 'ldaps://', - - // Purposedly removed for security - /* - 'about:', 'chrome://', 'chrome-extension://', - 'javascript:', - 'data:', - */ - ); + // More or less common stuff in links. From http://en.wikipedia.org/wiki/URI_scheme + return array( + // Common + 'http://', 'https://', 'ftp://', + 'file://', 'smb://', + 'sftp://', + 'feed:', 'feed://', + 'mailto:', + 'news:', 'nntp://', + + // Old school bearded geek + 'gopher://', 'telnet://', 'finger://', + 'nntp://', 'worldwind://', + + // Dev + 'ssh://', 'svn://', 'svn+ssh://', 'git://', 'cvs://', + 'apt:', + 'market://', // Google Play + 'view-source:', + + // P2P + 'ed2k://', 'magnet:', 'udp://', + + // Streaming stuff + 'mms://', 'lastfm://', 'spotify:', 'rtsp://', + + // Text & voice + 'aim:', 'facetime://', 'gtalk:', 'xmpp:', + 'irc://', 'ircs://', 'mumble://', + 'callto:', 'skype:', 'sip:', + 'teamspeak://', 'tel:', 'ventrilo://', 'xfire:', + 'ymsgr:', 'tg://', 'whatsapp://', + + // Misc + 'steam:', 'steam://', + 'bitcoin:', + 'ldap://', 'ldaps://', + + // Purposedly removed for security + /* + 'about:', 'chrome://', 'chrome-extension://', + 'javascript:', + 'data:', + */ + ); } @@ -573,17 +573,17 @@ function yourls_kses_allowed_protocols() { * @return string Content with normalized entities */ function yourls_kses_normalize_entities($string) { - # Disarm all entities by converting & to & + # Disarm all entities by converting & to & - $string = str_replace('&', '&', $string); + $string = str_replace('&', '&', $string); - # Change back the allowed entities in our entity whitelist + # Change back the allowed entities in our entity whitelist - $string = preg_replace_callback('/&([A-Za-z]{2,8});/', 'yourls_kses_named_entities', $string); - $string = preg_replace_callback('/&#(0*[0-9]{1,7});/', 'yourls_kses_normalize_entities2', $string); - $string = preg_replace_callback('/&#[Xx](0*[0-9A-Fa-f]{1,6});/', 'yourls_kses_normalize_entities3', $string); + $string = preg_replace_callback('/&([A-Za-z]{2,8});/', 'yourls_kses_named_entities', $string); + $string = preg_replace_callback('/&#(0*[0-9]{1,7});/', 'yourls_kses_normalize_entities2', $string); + $string = preg_replace_callback('/&#[Xx](0*[0-9A-Fa-f]{1,6});/', 'yourls_kses_normalize_entities3', $string); - return $string; + return $string; } /** @@ -598,13 +598,13 @@ function yourls_kses_normalize_entities($string) { * @return string Correctly encoded entity */ function yourls_kses_named_entities($matches) { - global $yourls_allowedentitynames; + global $yourls_allowedentitynames; - if ( empty($matches[1]) ) - return ''; + if ( empty($matches[1]) ) + return ''; - $i = $matches[1]; - return ( ( ! in_array($i, $yourls_allowedentitynames) ) ? "&$i;" : "&$i;" ); + $i = $matches[1]; + return ( ( ! in_array($i, $yourls_allowedentitynames) ) ? "&$i;" : "&$i;" ); } /** @@ -620,18 +620,18 @@ function yourls_kses_named_entities($matches) { * @return string Correctly encoded entity */ function yourls_kses_normalize_entities2($matches) { - if ( empty($matches[1]) ) - return ''; - - $i = $matches[1]; - if (yourls_valid_unicode($i)) { - $i = str_pad(ltrim($i,'0'), 3, '0', STR_PAD_LEFT); - $i = "&#$i;"; - } else { - $i = "&#$i;"; - } - - return $i; + if ( empty($matches[1]) ) + return ''; + + $i = $matches[1]; + if (yourls_valid_unicode($i)) { + $i = str_pad(ltrim($i,'0'), 3, '0', STR_PAD_LEFT); + $i = "&#$i;"; + } else { + $i = "&#$i;"; + } + + return $i; } /** @@ -647,11 +647,11 @@ function yourls_kses_normalize_entities2($matches) { * @return string Correctly encoded entity */ function yourls_kses_normalize_entities3($matches) { - if ( empty($matches[1]) ) - return ''; + if ( empty($matches[1]) ) + return ''; - $hexchars = $matches[1]; - return ( ( ! yourls_valid_unicode(hexdec($hexchars)) ) ? "&#x$hexchars;" : '&#x'.ltrim($hexchars,'0').';' ); + $hexchars = $matches[1]; + return ( ( ! yourls_valid_unicode(hexdec($hexchars)) ) ? "&#x$hexchars;" : '&#x'.ltrim($hexchars,'0').';' ); } /** @@ -664,20 +664,20 @@ function yourls_kses_normalize_entities3($matches) { * @return array The array of attributes with global attributes added. */ function _yourls_add_global_attributes( $value ) { - $global_attributes = array( - 'class' => true, - 'id' => true, - 'style' => true, - 'title' => true, - ); + $global_attributes = array( + 'class' => true, + 'id' => true, + 'style' => true, + 'title' => true, + ); - if ( true === $value ) - $value = array(); + if ( true === $value ) + $value = array(); - if ( is_array( $value ) ) - return array_merge( $value, $global_attributes ); + if ( is_array( $value ) ) + return array_merge( $value, $global_attributes ); - return $value; + return $value; } /** @@ -689,10 +689,10 @@ function _yourls_add_global_attributes( $value ) { * @return bool True if the value was a valid Unicode number */ function yourls_valid_unicode($i) { - return ( $i == 0x9 || $i == 0xa || $i == 0xd || - ($i >= 0x20 && $i <= 0xd7ff) || - ($i >= 0xe000 && $i <= 0xfffd) || - ($i >= 0x10000 && $i <= 0x10ffff) ); + return ( $i == 0x9 || $i == 0xa || $i == 0xd || + ($i >= 0x20 && $i <= 0xd7ff) || + ($i >= 0xe000 && $i <= 0xfffd) || + ($i >= 0x10000 && $i <= 0x10ffff) ); } /** @@ -704,19 +704,19 @@ function yourls_valid_unicode($i) { * @return array Fixed array with all lowercase keys */ function yourls_kses_array_lc($inarray) { - $outarray = array (); + $outarray = array (); - foreach ( (array) $inarray as $inkey => $inval) { - $outkey = strtolower($inkey); - $outarray[$outkey] = array (); + foreach ( (array) $inarray as $inkey => $inval) { + $outkey = strtolower($inkey); + $outarray[$outkey] = array (); - foreach ( (array) $inval as $inkey2 => $inval2) { - $outkey2 = strtolower($inkey2); - $outarray[$outkey][$outkey2] = $inval2; - } # foreach $inval - } # foreach $inarray + foreach ( (array) $inval as $inkey2 => $inval2) { + $outkey2 = strtolower($inkey2); + $outarray[$outkey][$outkey2] = $inval2; + } # foreach $inval + } # foreach $inarray - return $outarray; + return $outarray; } /** @@ -732,10 +732,10 @@ function yourls_kses_array_lc($inarray) { * @return string Content after decoded entities */ function yourls_kses_decode_entities($string) { - $string = preg_replace_callback('/&#([0-9]+);/', '_yourls_kses_decode_entities_chr', $string); - $string = preg_replace_callback('/&#[Xx]([0-9A-Fa-f]+);/', '_yourls_kses_decode_entities_chr_hexdec', $string); + $string = preg_replace_callback('/&#([0-9]+);/', '_yourls_kses_decode_entities_chr', $string); + $string = preg_replace_callback('/&#[Xx]([0-9A-Fa-f]+);/', '_yourls_kses_decode_entities_chr_hexdec', $string); - return $string; + return $string; } /** @@ -747,7 +747,7 @@ function yourls_kses_decode_entities($string) { * @return string */ function _yourls_kses_decode_entities_chr( $match ) { - return chr( $match[1] ); + return chr( $match[1] ); } /** @@ -759,7 +759,7 @@ function _yourls_kses_decode_entities_chr( $match ) { * @return string */ function _yourls_kses_decode_entities_chr_hexdec( $match ) { - return chr( hexdec( $match[1] ) ); + return chr( hexdec( $match[1] ) ); } /** @@ -771,8 +771,8 @@ function _yourls_kses_decode_entities_chr_hexdec( $match ) { * @return string */ function yourls_kses_no_null($string) { - $string = preg_replace( '/\0+/', '', $string ); - $string = preg_replace( '/(\\\\0)+/', '', $string ); + $string = preg_replace( '/\0+/', '', $string ); + $string = preg_replace( '/(\\\\0)+/', '', $string ); - return $string; + return $string; } diff --git a/includes/functions-l10n.php b/includes/functions-l10n.php index d72c786..377a775 100644 --- a/includes/functions-l10n.php +++ b/includes/functions-l10n.php @@ -12,7 +12,7 @@ /** * Load POMO files required to run library */ -use \POMO\MO; +use POMO\MO; use POMO\Translations\NOOPTranslations; /** @@ -29,24 +29,22 @@ * always be filtered using the 'get_locale' hook. * * @since 1.6 - * @uses yourls_apply_filter() Calls 'get_locale' hook on locale value. - * @uses $yourls_locale Gets the locale stored in the global. * * @return string The locale of the YOURLS instance */ function yourls_get_locale() { - global $yourls_locale; + global $yourls_locale; - if ( !isset( $yourls_locale ) ) { - // YOURLS_LANG is defined in config. - if ( defined( 'YOURLS_LANG' ) ) - $yourls_locale = YOURLS_LANG; - } + if ( !isset( $yourls_locale ) ) { + // YOURLS_LANG is defined in config. + if ( defined( 'YOURLS_LANG' ) ) + $yourls_locale = YOURLS_LANG; + } if ( !$yourls_locale ) $yourls_locale = ''; - return yourls_apply_filter( 'get_locale', $yourls_locale ); + return yourls_apply_filter( 'get_locale', $yourls_locale ); } /** @@ -55,16 +53,14 @@ function yourls_get_locale() { * * @see yourls__() Don't use yourls_translate() directly, use yourls__() * @since 1.6 - * @uses yourls_apply_filter() Calls 'translate' on domain translated text - * with the untranslated text as second parameter. * * @param string $text Text to translate. * @param string $domain Domain to retrieve the translated text. * @return string Translated text */ function yourls_translate( $text, $domain = 'default' ) { - $translations = yourls_get_translations_for_domain( $domain ); - return yourls_apply_filter( 'translate', $translations->translate( $text ), $text, $domain ); + $translations = yourls_get_translations_for_domain( $domain ); + return yourls_apply_filter( 'translate', $translations->translate( $text ), $text, $domain ); } /** @@ -84,8 +80,8 @@ function yourls_translate( $text, $domain = 'default' ) { * @return string Translated text */ function yourls_translate_with_context( $text, $context, $domain = 'default' ) { - $translations = yourls_get_translations_for_domain( $domain ); - return yourls_apply_filter( 'translate_with_context', $translations->translate( $text, $context ), $text, $context, $domain ); + $translations = yourls_get_translations_for_domain( $domain ); + return yourls_apply_filter( 'translate_with_context', $translations->translate( $text, $context ), $text, $context, $domain ); } /** @@ -100,7 +96,7 @@ function yourls_translate_with_context( $text, $context, $domain = 'default' ) { * @return string Translated text */ function yourls__( $text, $domain = 'default' ) { - return yourls_translate( $text, $domain ); + return yourls_translate( $text, $domain ); } /** @@ -120,27 +116,27 @@ function yourls__( $text, $domain = 'default' ) { * @return string Translated text */ function yourls_s( $pattern ) { - // Get pattern and pattern arguments - $args = func_get_args(); - // If yourls_s() called by yourls_se(), all arguments are wrapped in the same array key - if( count( $args ) == 1 && is_array( $args[0] ) ) { - $args = $args[0]; - } - $pattern = $args[0]; - - // get list of sprintf tokens (%s and such) - $num_of_tokens = substr_count( $pattern, '%' ) - 2 * substr_count( $pattern, '%%' ); - - $domain = 'default'; - // More arguments passed than needed for the sprintf? The last one will be the domain - if( $num_of_tokens < ( count( $args ) - 1 ) ) { - $domain = array_pop( $args ); - } - - // Translate text - $args[0] = yourls__( $pattern, $domain ); - - return call_user_func_array( 'sprintf', $args ); + // Get pattern and pattern arguments + $args = func_get_args(); + // If yourls_s() called by yourls_se(), all arguments are wrapped in the same array key + if( count( $args ) == 1 && is_array( $args[0] ) ) { + $args = $args[0]; + } + $pattern = $args[0]; + + // get list of sprintf tokens (%s and such) + $num_of_tokens = substr_count( $pattern, '%' ) - 2 * substr_count( $pattern, '%%' ); + + $domain = 'default'; + // More arguments passed than needed for the sprintf? The last one will be the domain + if( $num_of_tokens < ( count( $args ) - 1 ) ) { + $domain = array_pop( $args ); + } + + // Translate text + $args[0] = yourls__( $pattern, $domain ); + + return call_user_func_array( 'sprintf', $args ); } /** @@ -161,7 +157,7 @@ function yourls_s( $pattern ) { * @return void Translated text */ function yourls_se( $pattern ) { - echo yourls_s( func_get_args() ); + echo yourls_s( func_get_args() ); } @@ -178,7 +174,7 @@ function yourls_se( $pattern ) { * @return string Translated text */ function yourls_esc_attr__( $text, $domain = 'default' ) { - return yourls_esc_attr( yourls_translate( $text, $domain ) ); + return yourls_esc_attr( yourls_translate( $text, $domain ) ); } /** @@ -194,7 +190,7 @@ function yourls_esc_attr__( $text, $domain = 'default' ) { * @return string Translated text */ function yourls_esc_html__( $text, $domain = 'default' ) { - return yourls_esc_html( yourls_translate( $text, $domain ) ); + return yourls_esc_html( yourls_translate( $text, $domain ) ); } /** @@ -208,7 +204,7 @@ function yourls_esc_html__( $text, $domain = 'default' ) { * @return void */ function yourls_e( $text, $domain = 'default' ) { - echo yourls_translate( $text, $domain ); + echo yourls_translate( $text, $domain ); } /** @@ -223,7 +219,7 @@ function yourls_e( $text, $domain = 'default' ) { * @return void */ function yourls_esc_attr_e( $text, $domain = 'default' ) { - echo yourls_esc_attr( yourls_translate( $text, $domain ) ); + echo yourls_esc_attr( yourls_translate( $text, $domain ) ); } /** @@ -238,7 +234,7 @@ function yourls_esc_attr_e( $text, $domain = 'default' ) { * @return void */ function yourls_esc_html_e( $text, $domain = 'default' ) { - echo yourls_esc_html( yourls_translate( $text, $domain ) ); + echo yourls_esc_html( yourls_translate( $text, $domain ) ); } /** @@ -258,7 +254,7 @@ function yourls_esc_html_e( $text, $domain = 'default' ) { * @return string Translated context string */ function yourls_x( $text, $context, $domain = 'default' ) { - return yourls_translate_with_context( $text, $context, $domain ); + return yourls_translate_with_context( $text, $context, $domain ); } /** @@ -273,7 +269,7 @@ function yourls_x( $text, $context, $domain = 'default' ) { * @return void Echoes translated context string */ function yourls_xe( $text, $context, $domain = 'default' ) { - echo yourls_x( $text, $context, $domain ); + echo yourls_x( $text, $context, $domain ); } @@ -288,11 +284,10 @@ function yourls_xe( $text, $context, $domain = 'default' ) { * @param string $single * @param string $context * @param string $domain Optional. Domain to retrieve the translated text - * @internal param string $text Text to translate * @return string */ function yourls_esc_attr_x( $single, $context, $domain = 'default' ) { - return yourls_esc_attr( yourls_translate_with_context( $single, $context, $domain ) ); + return yourls_esc_attr( yourls_translate_with_context( $single, $context, $domain ) ); } /** @@ -306,11 +301,10 @@ function yourls_esc_attr_x( $single, $context, $domain = 'default' ) { * @param string $single * @param string $context * @param string $domain Optional. Domain to retrieve the translated text - * @internal param string $text Text to translate * @return string */ function yourls_esc_html_x( $single, $context, $domain = 'default' ) { - return yourls_esc_html( yourls_translate_with_context( $single, $context, $domain ) ); + return yourls_esc_html( yourls_translate_with_context( $single, $context, $domain ) ); } /** @@ -325,9 +319,6 @@ function yourls_esc_html_x( $single, $context, $domain = 'default' ) { * type will be a string. * * @since 1.6 - * @uses $yourls_l10n Gets list of domain translated string (gettext_reader) objects - * @uses yourls_apply_filter() Calls 'translate_n' hook on domains text returned, - * along with $single, $plural, and $number parameters. Expected to return string. * * @param string $single The text that will be used if $number is 1 * @param string $plural The text that will be used if $number is not 1 @@ -336,9 +327,9 @@ function yourls_esc_html_x( $single, $context, $domain = 'default' ) { * @return string Either $single or $plural translated text */ function yourls_n( $single, $plural, $number, $domain = 'default' ) { - $translations = yourls_get_translations_for_domain( $domain ); - $translation = $translations->translate_plural( $single, $plural, $number ); - return yourls_apply_filter( 'translate_n', $translation, $single, $plural, $number, $domain ); + $translations = yourls_get_translations_for_domain( $domain ); + $translation = $translations->translate_plural( $single, $plural, $number ); + return yourls_apply_filter( 'translate_n', $translation, $single, $plural, $number, $domain ); } /** @@ -356,9 +347,9 @@ function yourls_n( $single, $plural, $number, $domain = 'default' ) { * @return string Either $single or $plural translated text */ function yourls_nx($single, $plural, $number, $context, $domain = 'default') { - $translations = yourls_get_translations_for_domain( $domain ); - $translation = $translations->translate_plural( $single, $plural, $number, $context ); - return yourls_apply_filter( 'translate_nx', $translation, $single, $plural, $number, $context, $domain ); + $translations = yourls_get_translations_for_domain( $domain ); + $translation = $translations->translate_plural( $single, $plural, $number, $context ); + return yourls_apply_filter( 'translate_nx', $translation, $single, $plural, $number, $context, $domain ); } /** @@ -369,8 +360,8 @@ function yourls_nx($single, $plural, $number, $context, $domain = 'default') { * * Example: * $messages = array( - * 'post' => yourls_n_noop('%s post', '%s posts'), - * 'page' => yourls_n_noop('%s pages', '%s pages') + * 'post' => yourls_n_noop('%s post', '%s posts'), + * 'page' => yourls_n_noop('%s pages', '%s pages') * ); * ... * $message = $messages[$type]; @@ -383,14 +374,14 @@ function yourls_nx($single, $plural, $number, $context, $domain = 'default') { * @return array array($singular, $plural) */ function yourls_n_noop( $singular, $plural, $domain = null ) { - return array( - 0 => $singular, - 1 => $plural, - 'singular' => $singular, - 'plural' => $plural, - 'context' => null, - 'domain' => $domain - ); + return array( + 0 => $singular, + 1 => $plural, + 'singular' => $singular, + 'plural' => $plural, + 'context' => null, + 'domain' => $domain + ); } /** @@ -406,15 +397,15 @@ function yourls_n_noop( $singular, $plural, $domain = null ) { * @return array array($singular, $plural) */ function yourls_nx_noop( $singular, $plural, $context, $domain = null ) { - return array( - 0 => $singular, - 1 => $plural, - 2 => $context, - 'singular' => $singular, - 'plural' => $plural, - 'context' => $context, - 'domain' => $domain - ); + return array( + 0 => $singular, + 1 => $plural, + 2 => $context, + 'singular' => $singular, + 'plural' => $plural, + 'context' => $context, + 'domain' => $domain + ); } /** @@ -424,17 +415,17 @@ function yourls_nx_noop( $singular, $plural, $context, $domain = null ) { * @param array $nooped_plural Array with singular, plural and context keys, usually the result of yourls_n_noop() or yourls_nx_noop() * @param int $count Number of objects * @param string $domain Optional. The domain identifier the text should be retrieved in. If $nooped_plural contains - * a domain passed to yourls_n_noop() or yourls_nx_noop(), it will override this value. + * a domain passed to yourls_n_noop() or yourls_nx_noop(), it will override this value. * @return string */ function yourls_translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) { - if ( $nooped_plural['domain'] ) - $domain = $nooped_plural['domain']; + if ( $nooped_plural['domain'] ) + $domain = $nooped_plural['domain']; - if ( $nooped_plural['context'] ) - return yourls_nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain ); - else - return yourls_n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain ); + if ( $nooped_plural['context'] ) + return yourls_nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain ); + else + return yourls_n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain ); } /** @@ -447,41 +438,40 @@ function yourls_translate_nooped_plural( $nooped_plural, $count, $domain = 'defa * and will be a MO object. * * @since 1.6 - * @uses $yourls_l10n Gets list of domain translated string objects * * @param string $domain Unique identifier for retrieving translated strings * @param string $mofile Path to the .mo file * @return bool True on success, false on failure */ function yourls_load_textdomain( $domain, $mofile ) { - global $yourls_l10n; + global $yourls_l10n; - $plugin_override = yourls_apply_filter( 'override_load_textdomain', false, $domain, $mofile ); + $plugin_override = yourls_apply_filter( 'override_load_textdomain', false, $domain, $mofile ); - if ( true == $plugin_override ) { - return true; - } + if ( true == $plugin_override ) { + return true; + } - yourls_do_action( 'load_textdomain', $domain, $mofile ); + yourls_do_action( 'load_textdomain', $domain, $mofile ); - $mofile = yourls_apply_filter( 'load_textdomain_mofile', $mofile, $domain ); + $mofile = yourls_apply_filter( 'load_textdomain_mofile', $mofile, $domain ); - if ( !is_readable( $mofile ) ) { + if ( !is_readable( $mofile ) ) { trigger_error( 'Cannot read file ' . str_replace( YOURLS_ABSPATH.'/', '', $mofile ) . '.' . ' Make sure there is a language file installed. More info: http://yourls.org/translations' ); return false; } - $mo = new MO(); - if ( !$mo->import_from_file( $mofile ) ) + $mo = new MO(); + if ( !$mo->import_from_file( $mofile ) ) return false; - if ( isset( $yourls_l10n[$domain] ) ) - $mo->merge_with( $yourls_l10n[$domain] ); + if ( isset( $yourls_l10n[$domain] ) ) + $mo->merge_with( $yourls_l10n[$domain] ); - $yourls_l10n[$domain] = &$mo; + $yourls_l10n[$domain] = &$mo; - return true; + return true; } /** @@ -492,21 +482,21 @@ function yourls_load_textdomain( $domain, $mofile ) { * @return bool Whether textdomain was unloaded */ function yourls_unload_textdomain( $domain ) { - global $yourls_l10n; + global $yourls_l10n; - $plugin_override = yourls_apply_filter( 'override_unload_textdomain', false, $domain ); + $plugin_override = yourls_apply_filter( 'override_unload_textdomain', false, $domain ); - if ( $plugin_override ) - return true; + if ( $plugin_override ) + return true; - yourls_do_action( 'unload_textdomain', $domain ); + yourls_do_action( 'unload_textdomain', $domain ); - if ( isset( $yourls_l10n[$domain] ) ) { - unset( $yourls_l10n[$domain] ); - return true; - } + if ( isset( $yourls_l10n[$domain] ) ) { + unset( $yourls_l10n[$domain] ); + return true; + } - return false; + return false; } /** @@ -519,7 +509,7 @@ function yourls_unload_textdomain( $domain ) { * @return bool True on success, false on failure */ function yourls_load_default_textdomain() { - $yourls_locale = yourls_get_locale(); + $yourls_locale = yourls_get_locale(); if( !empty( $yourls_locale ) ) return yourls_load_textdomain( 'default', YOURLS_LANG_DIR . "/$yourls_locale.mo" ); @@ -535,11 +525,11 @@ function yourls_load_default_textdomain() { * @return NOOPTranslations An NOOPTranslations translation instance */ function yourls_get_translations_for_domain( $domain ) { - global $yourls_l10n; - if ( !isset( $yourls_l10n[$domain] ) ) { - $yourls_l10n[$domain] = new NOOPTranslations; - } - return $yourls_l10n[$domain]; + global $yourls_l10n; + if ( !isset( $yourls_l10n[$domain] ) ) { + $yourls_l10n[$domain] = new NOOPTranslations; + } + return $yourls_l10n[$domain]; } /** @@ -550,8 +540,8 @@ function yourls_get_translations_for_domain( $domain ) { * @return bool Whether there are translations */ function yourls_is_textdomain_loaded( $domain ) { - global $yourls_l10n; - return isset( $yourls_l10n[$domain] ); + global $yourls_l10n; + return isset( $yourls_l10n[$domain] ); } /** @@ -567,7 +557,7 @@ function yourls_is_textdomain_loaded( $domain ) { * @return string Translated role name */ function yourls_translate_user_role( $name ) { - return yourls_translate_with_context( $name, 'User role' ); + return yourls_translate_with_context( $name, 'User role' ); } /** @@ -579,15 +569,15 @@ function yourls_translate_user_role( $name ) { * @return array Array of language codes or an empty array if no languages are present. Language codes are formed by stripping the .mo extension from the language file names. */ function yourls_get_available_languages( $dir = null ) { - $languages = array(); + $languages = array(); - $dir = is_null( $dir) ? YOURLS_LANG_DIR : $dir; + $dir = is_null( $dir) ? YOURLS_LANG_DIR : $dir; - foreach( (array) glob( $dir . '/*.mo' ) as $lang_file ) { - $languages[] = basename( $lang_file, '.mo' ); - } + foreach( (array) glob( $dir . '/*.mo' ) as $lang_file ) { + $languages[] = basename( $lang_file, '.mo' ); + } - return yourls_apply_filter( 'get_available_languages', $languages ); + return yourls_apply_filter( 'get_available_languages', $languages ); } /** @@ -600,12 +590,12 @@ function yourls_get_available_languages( $dir = null ) { * @return string Converted number in string format. */ function yourls_number_format_i18n( $number, $decimals = 0 ) { - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - $formatted = number_format( $number, abs( intval( $decimals ) ), $yourls_locale_formats->number_format['decimal_point'], $yourls_locale_formats->number_format['thousands_sep'] ); - return yourls_apply_filter( 'number_format_i18n', $formatted ); + $formatted = number_format( $number, abs( intval( $decimals ) ), $yourls_locale_formats->number_format['decimal_point'], $yourls_locale_formats->number_format['thousands_sep'] ); + return yourls_apply_filter( 'number_format_i18n', $formatted ); } /** @@ -625,46 +615,46 @@ function yourls_date_i18n( $dateformatstring, $timestamp = false ) { /** * @var YOURLS_Locale_Formats $yourls_locale_formats */ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - if ( false === $timestamp ) { + if ( false === $timestamp ) { $timestamp = yourls_get_timestamp( time() ); - } - - // store original value for language with untypical grammars - $req_format = $dateformatstring; - - /** - * Replace the date format characters with their translatation, if found - * Example: - * 'l d F Y' gets replaced with '\L\u\n\d\i d \M\a\i Y' in French - * We deliberately don't deal with 'I', 'O', 'P', 'T', 'Z' and 'e' in date format (timezones) - */ - if ( ( !empty( $yourls_locale_formats->month ) ) && ( !empty( $yourls_locale_formats->weekday ) ) ) { - $datemonth = $yourls_locale_formats->get_month( date( 'm', $timestamp ) ); - $datemonth_abbrev = $yourls_locale_formats->get_month_abbrev( $datemonth ); - $dateweekday = $yourls_locale_formats->get_weekday( date( 'w', $timestamp ) ); - $dateweekday_abbrev = $yourls_locale_formats->get_weekday_abbrev( $dateweekday ); - $datemeridiem = $yourls_locale_formats->get_meridiem( date( 'a', $timestamp ) ); - $datemeridiem_capital = $yourls_locale_formats->get_meridiem( date( 'A', $timestamp ) ); - - $dateformatstring = ' '.$dateformatstring; - $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . yourls_backslashit( $dateweekday_abbrev ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . yourls_backslashit( $datemonth ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . yourls_backslashit( $dateweekday ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . yourls_backslashit( $datemonth_abbrev ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . yourls_backslashit( $datemeridiem ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . yourls_backslashit( $datemeridiem_capital ), $dateformatstring ); - - $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 ); - } - - $date = date( $dateformatstring, $timestamp ); - - // Allow plugins to redo this entirely for languages with untypical grammars - return yourls_apply_filter('date_i18n', $date, $req_format, $timestamp); + } + + // store original value for language with untypical grammars + $req_format = $dateformatstring; + + /** + * Replace the date format characters with their translatation, if found + * Example: + * 'l d F Y' gets replaced with '\L\u\n\d\i d \M\a\i Y' in French + * We deliberately don't deal with 'I', 'O', 'P', 'T', 'Z' and 'e' in date format (timezones) + */ + if ( ( !empty( $yourls_locale_formats->month ) ) && ( !empty( $yourls_locale_formats->weekday ) ) ) { + $datemonth = $yourls_locale_formats->get_month( date( 'm', $timestamp ) ); + $datemonth_abbrev = $yourls_locale_formats->get_month_abbrev( $datemonth ); + $dateweekday = $yourls_locale_formats->get_weekday( date( 'w', $timestamp ) ); + $dateweekday_abbrev = $yourls_locale_formats->get_weekday_abbrev( $dateweekday ); + $datemeridiem = $yourls_locale_formats->get_meridiem( date( 'a', $timestamp ) ); + $datemeridiem_capital = $yourls_locale_formats->get_meridiem( date( 'A', $timestamp ) ); + + $dateformatstring = ' '.$dateformatstring; + $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . yourls_backslashit( $dateweekday_abbrev ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . yourls_backslashit( $datemonth ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . yourls_backslashit( $dateweekday ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . yourls_backslashit( $datemonth_abbrev ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . yourls_backslashit( $datemeridiem ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . yourls_backslashit( $datemeridiem_capital ), $dateformatstring ); + + $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 ); + } + + $date = date( $dateformatstring, $timestamp ); + + // Allow plugins to redo this entirely for languages with untypical grammars + return yourls_apply_filter('date_i18n', $date, $req_format, $timestamp); } /** @@ -673,332 +663,328 @@ function yourls_date_i18n( $dateformatstring, $timestamp = false ) { * @since 1.6 */ class YOURLS_Locale_Formats { - /** - * Stores the translated strings for the full weekday names. - * - * @since 1.6 - * @var array - * @access private - */ - var $weekday; - - /** - * Stores the translated strings for the one character weekday names. - * - * There is a hack to make sure that Tuesday and Thursday, as well - * as Sunday and Saturday, don't conflict. See init() method for more. - * - * @see YOURLS_Locale_Formats::init() for how to handle the hack. - * - * @since 1.6 - * @var array - * @access private - */ - var $weekday_initial; - - /** - * Stores the translated strings for the abbreviated weekday names. - * - * @since 1.6 - * @var array - * @access private - */ - var $weekday_abbrev; - - /** - * Stores the translated strings for the full month names. - * - * @since 1.6 - * @var array - * @access private - */ - var $month; - - /** - * Stores the translated strings for the abbreviated month names. - * - * @since 1.6 - * @var array - * @access private - */ - var $month_abbrev; - - /** - * Stores the translated strings for 'am' and 'pm'. - * - * Also the capitalized versions. - * - * @since 1.6 - * @var array - * @access private - */ - var $meridiem; - - /** - * Stores the translated number format - * - * @since 1.6 - * @var array - * @access private - */ - var $number_format; - - /** - * The text direction of the locale language. - * - * Default is left to right 'ltr'. - * - * @since 1.6 - * @var string - * @access private - */ - var $text_direction = 'ltr'; - - /** - * Sets up the translated strings and object properties. - * - * The method creates the translatable strings for various - * calendar elements. Which allows for specifying locale - * specific calendar names and text direction. - * - * @since 1.6 - * @access private + /** + * Stores the translated strings for the full weekday names. + * + * @since 1.6 + * @var array + * @access private + */ + var $weekday; + + /** + * Stores the translated strings for the one character weekday names. + * + * There is a hack to make sure that Tuesday and Thursday, as well + * as Sunday and Saturday, don't conflict. See init() method for more. + * + * @see YOURLS_Locale_Formats::init() for how to handle the hack. + * + * @since 1.6 + * @var array + * @access private + */ + var $weekday_initial; + + /** + * Stores the translated strings for the abbreviated weekday names. + * + * @since 1.6 + * @var array + * @access private + */ + var $weekday_abbrev; + + /** + * Stores the translated strings for the full month names. + * + * @since 1.6 + * @var array + * @access private + */ + var $month; + + /** + * Stores the translated strings for the abbreviated month names. + * + * @since 1.6 + * @var array + * @access private + */ + var $month_abbrev; + + /** + * Stores the translated strings for 'am' and 'pm'. + * + * Also the capitalized versions. + * + * @since 1.6 + * @var array + * @access private + */ + var $meridiem; + + /** + * Stores the translated number format + * + * @since 1.6 + * @var array + * @access private + */ + var $number_format; + + /** + * The text direction of the locale language. + * + * Default is left to right 'ltr'. + * + * @since 1.6 + * @var string + * @access private + */ + var $text_direction = 'ltr'; + + /** + * Sets up the translated strings and object properties. + * + * The method creates the translatable strings for various + * calendar elements. Which allows for specifying locale + * specific calendar names and text direction. + * + * @since 1.6 + * @access private * @return void - */ - function init() { - // The Weekdays - $this->weekday[0] = /* //translators: weekday */ yourls__( 'Sunday' ); - $this->weekday[1] = /* //translators: weekday */ yourls__( 'Monday' ); - $this->weekday[2] = /* //translators: weekday */ yourls__( 'Tuesday' ); - $this->weekday[3] = /* //translators: weekday */ yourls__( 'Wednesday' ); - $this->weekday[4] = /* //translators: weekday */ yourls__( 'Thursday' ); - $this->weekday[5] = /* //translators: weekday */ yourls__( 'Friday' ); - $this->weekday[6] = /* //translators: weekday */ yourls__( 'Saturday' ); - - // The first letter of each day. The _%day%_initial suffix is a hack to make - // sure the day initials are unique. - $this->weekday_initial[yourls__( 'Sunday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Sunday_initial' ); - $this->weekday_initial[yourls__( 'Monday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'M_Monday_initial' ); - $this->weekday_initial[yourls__( 'Tuesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Tuesday_initial' ); - $this->weekday_initial[yourls__( 'Wednesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'W_Wednesday_initial' ); - $this->weekday_initial[yourls__( 'Thursday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Thursday_initial' ); - $this->weekday_initial[yourls__( 'Friday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'F_Friday_initial' ); - $this->weekday_initial[yourls__( 'Saturday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Saturday_initial' ); - - foreach ($this->weekday_initial as $weekday_ => $weekday_initial_) { - $this->weekday_initial[$weekday_] = preg_replace('/_.+_initial$/', '', $weekday_initial_); - } - - // Abbreviations for each day. - $this->weekday_abbrev[ yourls__( 'Sunday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sun' ); - $this->weekday_abbrev[ yourls__( 'Monday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Mon' ); - $this->weekday_abbrev[ yourls__( 'Tuesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Tue' ); - $this->weekday_abbrev[ yourls__( 'Wednesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Wed' ); - $this->weekday_abbrev[ yourls__( 'Thursday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Thu' ); - $this->weekday_abbrev[ yourls__( 'Friday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Fri' ); - $this->weekday_abbrev[ yourls__( 'Saturday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sat' ); - - // The Months - $this->month['01'] = /* //translators: month name */ yourls__( 'January' ); - $this->month['02'] = /* //translators: month name */ yourls__( 'February' ); - $this->month['03'] = /* //translators: month name */ yourls__( 'March' ); - $this->month['04'] = /* //translators: month name */ yourls__( 'April' ); - $this->month['05'] = /* //translators: month name */ yourls__( 'May' ); - $this->month['06'] = /* //translators: month name */ yourls__( 'June' ); - $this->month['07'] = /* //translators: month name */ yourls__( 'July' ); - $this->month['08'] = /* //translators: month name */ yourls__( 'August' ); - $this->month['09'] = /* //translators: month name */ yourls__( 'September' ); - $this->month['10'] = /* //translators: month name */ yourls__( 'October' ); - $this->month['11'] = /* //translators: month name */ yourls__( 'November' ); - $this->month['12'] = /* //translators: month name */ yourls__( 'December' ); - - // Abbreviations for each month. Uses the same hack as above to get around the - // 'May' duplication. - $this->month_abbrev[ yourls__( 'January' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jan_January_abbreviation' ); - $this->month_abbrev[ yourls__( 'February' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Feb_February_abbreviation' ); - $this->month_abbrev[ yourls__( 'March' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Mar_March_abbreviation' ); - $this->month_abbrev[ yourls__( 'April' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Apr_April_abbreviation' ); - $this->month_abbrev[ yourls__( 'May' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'May_May_abbreviation' ); - $this->month_abbrev[ yourls__( 'June' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jun_June_abbreviation' ); - $this->month_abbrev[ yourls__( 'July' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jul_July_abbreviation' ); - $this->month_abbrev[ yourls__( 'August' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Aug_August_abbreviation' ); - $this->month_abbrev[ yourls__( 'September' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Sep_September_abbreviation' ); - $this->month_abbrev[ yourls__( 'October' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Oct_October_abbreviation' ); - $this->month_abbrev[ yourls__( 'November' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Nov_November_abbreviation' ); - $this->month_abbrev[ yourls__( 'December' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Dec_December_abbreviation' ); - - foreach ($this->month_abbrev as $month_ => $month_abbrev_) { - $this->month_abbrev[$month_] = preg_replace('/_.+_abbreviation$/', '', $month_abbrev_); - } - - // The Meridiems - $this->meridiem['am'] = yourls__( 'am' ); - $this->meridiem['pm'] = yourls__( 'pm' ); - $this->meridiem['AM'] = yourls__( 'AM' ); - $this->meridiem['PM'] = yourls__( 'PM' ); - - // Numbers formatting - // See http://php.net/number_format - - /* //translators: $thousands_sep argument for http://php.net/number_format, default is , */ - $trans = yourls__( 'number_format_thousands_sep' ); - $this->number_format['thousands_sep'] = ('number_format_thousands_sep' == $trans) ? ',' : $trans; - - /* //translators: $dec_point argument for http://php.net/number_format, default is . */ - $trans = yourls__( 'number_format_decimal_point' ); - $this->number_format['decimal_point'] = ('number_format_decimal_point' == $trans) ? '.' : $trans; - - // Set text direction. - if ( isset( $GLOBALS['text_direction'] ) ) - $this->text_direction = $GLOBALS['text_direction']; - /* //translators: 'rtl' or 'ltr'. This sets the text direction for YOURLS. */ - elseif ( 'rtl' == yourls_x( 'ltr', 'text direction' ) ) - $this->text_direction = 'rtl'; - } - - /** - * Retrieve the full translated weekday word. - * - * Week starts on translated Sunday and can be fetched - * by using 0 (zero). So the week starts with 0 (zero) - * and ends on Saturday with is fetched by using 6 (six). - * - * @since 1.6 - * @access public - * - * @param int|string $weekday_number 0 for Sunday through 6 Saturday - * @return string Full translated weekday - */ - function get_weekday( $weekday_number ) { - return $this->weekday[ $weekday_number ]; - } - - /** - * Retrieve the translated weekday initial. - * - * The weekday initial is retrieved by the translated - * full weekday word. When translating the weekday initial - * pay attention to make sure that the starting letter does - * not conflict. - * - * @since 1.6 - * @access public - * - * @param string $weekday_name - * @return string - */ - function get_weekday_initial( $weekday_name ) { - return $this->weekday_initial[ $weekday_name ]; - } - - /** - * Retrieve the translated weekday abbreviation. - * - * The weekday abbreviation is retrieved by the translated - * full weekday word. - * - * @since 1.6 - * @access public - * - * @param string $weekday_name Full translated weekday word - * @return string Translated weekday abbreviation - */ - function get_weekday_abbrev( $weekday_name ) { - return $this->weekday_abbrev[ $weekday_name ]; - } - - /** - * Retrieve the full translated month by month number. - * - * The $month_number parameter has to be a string - * because it must have the '0' in front of any number - * that is less than 10. Starts from '01' and ends at - * '12'. - * - * You can use an integer instead and it will add the - * '0' before the numbers less than 10 for you. - * - * @since 1.6 - * @access public - * - * @param string|int $month_number '01' through '12' - * @return string Translated full month name - */ - function get_month( $month_number ) { - return $this->month[ sprintf( '%02s', $month_number ) ]; - } - - /** - * Retrieve translated version of month abbreviation string. - * - * The $month_name parameter is expected to be the translated or - * translatable version of the month. - * - * @since 1.6 - * @access public - * - * @param string $month_name Translated month to get abbreviated version - * @return string Translated abbreviated month - */ - function get_month_abbrev( $month_name ) { - return $this->month_abbrev[ $month_name ]; - } - - /** - * Retrieve translated version of meridiem string. - * - * The $meridiem parameter is expected to not be translated. - * - * @since 1.6 - * @access public - * - * @param string $meridiem Either 'am', 'pm', 'AM', or 'PM'. Not translated version. - * @return string Translated version - */ - function get_meridiem( $meridiem ) { - return $this->meridiem[ $meridiem ]; - } - - /** - * Global variables are deprecated. For backwards compatibility only. - * - * @deprecated For backwards compatibility only. - * @access private - * - * @since 1.6 + */ + function init() { + // The Weekdays + $this->weekday[0] = /* //translators: weekday */ yourls__( 'Sunday' ); + $this->weekday[1] = /* //translators: weekday */ yourls__( 'Monday' ); + $this->weekday[2] = /* //translators: weekday */ yourls__( 'Tuesday' ); + $this->weekday[3] = /* //translators: weekday */ yourls__( 'Wednesday' ); + $this->weekday[4] = /* //translators: weekday */ yourls__( 'Thursday' ); + $this->weekday[5] = /* //translators: weekday */ yourls__( 'Friday' ); + $this->weekday[6] = /* //translators: weekday */ yourls__( 'Saturday' ); + + // The first letter of each day. The _%day%_initial suffix is a hack to make + // sure the day initials are unique. + $this->weekday_initial[yourls__( 'Sunday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Sunday_initial' ); + $this->weekday_initial[yourls__( 'Monday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'M_Monday_initial' ); + $this->weekday_initial[yourls__( 'Tuesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Tuesday_initial' ); + $this->weekday_initial[yourls__( 'Wednesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'W_Wednesday_initial' ); + $this->weekday_initial[yourls__( 'Thursday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Thursday_initial' ); + $this->weekday_initial[yourls__( 'Friday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'F_Friday_initial' ); + $this->weekday_initial[yourls__( 'Saturday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Saturday_initial' ); + + foreach ($this->weekday_initial as $weekday_ => $weekday_initial_) { + $this->weekday_initial[$weekday_] = preg_replace('/_.+_initial$/', '', $weekday_initial_); + } + + // Abbreviations for each day. + $this->weekday_abbrev[ yourls__( 'Sunday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sun' ); + $this->weekday_abbrev[ yourls__( 'Monday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Mon' ); + $this->weekday_abbrev[ yourls__( 'Tuesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Tue' ); + $this->weekday_abbrev[ yourls__( 'Wednesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Wed' ); + $this->weekday_abbrev[ yourls__( 'Thursday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Thu' ); + $this->weekday_abbrev[ yourls__( 'Friday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Fri' ); + $this->weekday_abbrev[ yourls__( 'Saturday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sat' ); + + // The Months + $this->month['01'] = /* //translators: month name */ yourls__( 'January' ); + $this->month['02'] = /* //translators: month name */ yourls__( 'February' ); + $this->month['03'] = /* //translators: month name */ yourls__( 'March' ); + $this->month['04'] = /* //translators: month name */ yourls__( 'April' ); + $this->month['05'] = /* //translators: month name */ yourls__( 'May' ); + $this->month['06'] = /* //translators: month name */ yourls__( 'June' ); + $this->month['07'] = /* //translators: month name */ yourls__( 'July' ); + $this->month['08'] = /* //translators: month name */ yourls__( 'August' ); + $this->month['09'] = /* //translators: month name */ yourls__( 'September' ); + $this->month['10'] = /* //translators: month name */ yourls__( 'October' ); + $this->month['11'] = /* //translators: month name */ yourls__( 'November' ); + $this->month['12'] = /* //translators: month name */ yourls__( 'December' ); + + // Abbreviations for each month. Uses the same hack as above to get around the + // 'May' duplication. + $this->month_abbrev[ yourls__( 'January' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jan_January_abbreviation' ); + $this->month_abbrev[ yourls__( 'February' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Feb_February_abbreviation' ); + $this->month_abbrev[ yourls__( 'March' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Mar_March_abbreviation' ); + $this->month_abbrev[ yourls__( 'April' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Apr_April_abbreviation' ); + $this->month_abbrev[ yourls__( 'May' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'May_May_abbreviation' ); + $this->month_abbrev[ yourls__( 'June' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jun_June_abbreviation' ); + $this->month_abbrev[ yourls__( 'July' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jul_July_abbreviation' ); + $this->month_abbrev[ yourls__( 'August' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Aug_August_abbreviation' ); + $this->month_abbrev[ yourls__( 'September' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Sep_September_abbreviation' ); + $this->month_abbrev[ yourls__( 'October' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Oct_October_abbreviation' ); + $this->month_abbrev[ yourls__( 'November' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Nov_November_abbreviation' ); + $this->month_abbrev[ yourls__( 'December' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Dec_December_abbreviation' ); + + foreach ($this->month_abbrev as $month_ => $month_abbrev_) { + $this->month_abbrev[$month_] = preg_replace('/_.+_abbreviation$/', '', $month_abbrev_); + } + + // The Meridiems + $this->meridiem['am'] = yourls__( 'am' ); + $this->meridiem['pm'] = yourls__( 'pm' ); + $this->meridiem['AM'] = yourls__( 'AM' ); + $this->meridiem['PM'] = yourls__( 'PM' ); + + // Numbers formatting + // See http://php.net/number_format + + /* //translators: $thousands_sep argument for http://php.net/number_format, default is , */ + $trans = yourls__( 'number_format_thousands_sep' ); + $this->number_format['thousands_sep'] = ('number_format_thousands_sep' == $trans) ? ',' : $trans; + + /* //translators: $dec_point argument for http://php.net/number_format, default is . */ + $trans = yourls__( 'number_format_decimal_point' ); + $this->number_format['decimal_point'] = ('number_format_decimal_point' == $trans) ? '.' : $trans; + + // Set text direction. + if ( isset( $GLOBALS['text_direction'] ) ) + $this->text_direction = $GLOBALS['text_direction']; + /* //translators: 'rtl' or 'ltr'. This sets the text direction for YOURLS. */ + elseif ( 'rtl' == yourls_x( 'ltr', 'text direction' ) ) + $this->text_direction = 'rtl'; + } + + /** + * Retrieve the full translated weekday word. + * + * Week starts on translated Sunday and can be fetched + * by using 0 (zero). So the week starts with 0 (zero) + * and ends on Saturday with is fetched by using 6 (six). + * + * @since 1.6 + * @access public + * + * @param int|string $weekday_number 0 for Sunday through 6 Saturday + * @return string Full translated weekday + */ + function get_weekday( $weekday_number ) { + return $this->weekday[ $weekday_number ]; + } + + /** + * Retrieve the translated weekday initial. + * + * The weekday initial is retrieved by the translated + * full weekday word. When translating the weekday initial + * pay attention to make sure that the starting letter does + * not conflict. + * + * @since 1.6 + * @access public + * + * @param string $weekday_name + * @return string + */ + function get_weekday_initial( $weekday_name ) { + return $this->weekday_initial[ $weekday_name ]; + } + + /** + * Retrieve the translated weekday abbreviation. + * + * The weekday abbreviation is retrieved by the translated + * full weekday word. + * + * @since 1.6 + * @access public + * + * @param string $weekday_name Full translated weekday word + * @return string Translated weekday abbreviation + */ + function get_weekday_abbrev( $weekday_name ) { + return $this->weekday_abbrev[ $weekday_name ]; + } + + /** + * Retrieve the full translated month by month number. + * + * The $month_number parameter has to be a string + * because it must have the '0' in front of any number + * that is less than 10. Starts from '01' and ends at + * '12'. + * + * You can use an integer instead and it will add the + * '0' before the numbers less than 10 for you. + * + * @since 1.6 + * @access public + * + * @param string|int $month_number '01' through '12' + * @return string Translated full month name + */ + function get_month( $month_number ) { + return $this->month[ sprintf( '%02s', $month_number ) ]; + } + + /** + * Retrieve translated version of month abbreviation string. + * + * The $month_name parameter is expected to be the translated or + * translatable version of the month. + * + * @since 1.6 + * @access public + * + * @param string $month_name Translated month to get abbreviated version + * @return string Translated abbreviated month + */ + function get_month_abbrev( $month_name ) { + return $this->month_abbrev[ $month_name ]; + } + + /** + * Retrieve translated version of meridiem string. + * + * The $meridiem parameter is expected to not be translated. + * + * @since 1.6 + * @access public + * + * @param string $meridiem Either 'am', 'pm', 'AM', or 'PM'. Not translated version. + * @return string Translated version + */ + function get_meridiem( $meridiem ) { + return $this->meridiem[ $meridiem ]; + } + + /** + * Global variables are deprecated. For backwards compatibility only. + * + * @deprecated For backwards compatibility only. + * @access private + * + * @since 1.6 * @return void - */ - function register_globals() { - $GLOBALS['weekday'] = $this->weekday; - $GLOBALS['weekday_initial'] = $this->weekday_initial; - $GLOBALS['weekday_abbrev'] = $this->weekday_abbrev; - $GLOBALS['month'] = $this->month; - $GLOBALS['month_abbrev'] = $this->month_abbrev; - } - - /** - * Constructor which calls helper methods to set up object variables - * - * @uses YOURLS_Locale_Formats::init() - * @uses YOURLS_Locale_Formats::register_globals() - * @since 1.6 - * - * @return YOURLS_Locale_Formats - */ - function __construct() { - $this->init(); - $this->register_globals(); - } - - /** - * Checks if current locale is RTL. - * - * @since 1.6 - * @return bool Whether locale is RTL. - */ - function is_rtl() { - return 'rtl' == $this->text_direction; - } + */ + function register_globals() { + $GLOBALS['weekday'] = $this->weekday; + $GLOBALS['weekday_initial'] = $this->weekday_initial; + $GLOBALS['weekday_abbrev'] = $this->weekday_abbrev; + $GLOBALS['month'] = $this->month; + $GLOBALS['month_abbrev'] = $this->month_abbrev; + } + + /** + * Constructor which calls helper methods to set up object variables + * + * @since 1.6 + */ + function __construct() { + $this->init(); + $this->register_globals(); + } + + /** + * Checks if current locale is RTL. + * + * @since 1.6 + * @return bool Whether locale is RTL. + */ + function is_rtl() { + return 'rtl' == $this->text_direction; + } } /** @@ -1011,10 +997,10 @@ function is_rtl() { * * @param string $domain Unique identifier (the "domain") for retrieving translated strings * @param string $path Full path to directory containing MO files. - * @return mixed Returns nothing if locale undefined, otherwise return bool: true on success, false on failure + * @return mixed|void Returns nothing if locale undefined, otherwise return bool: true on success, false on failure */ function yourls_load_custom_textdomain( $domain, $path ) { - $locale = yourls_apply_filter( 'load_custom_textdomain', yourls_get_locale(), $domain ); + $locale = yourls_apply_filter( 'load_custom_textdomain', yourls_get_locale(), $domain ); if( !empty( $locale ) ) { $mofile = rtrim( $path, '/' ) . '/'. $domain . '-' . $locale . '.mo'; return yourls_load_textdomain( $domain, $mofile ); @@ -1028,11 +1014,11 @@ function yourls_load_custom_textdomain( $domain, $path ) { * @return bool Whether locale is RTL. */ function yourls_is_rtl() { - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - return $yourls_locale_formats->is_rtl(); + return $yourls_locale_formats->is_rtl(); } /** @@ -1046,19 +1032,19 @@ function yourls_is_rtl() { * @return mixed Translated weekday abbreviation, eg "Ven" (abbrev of "Vendredi") for "Friday" or 5, or array of all weekday abbrev */ function yourls_l10n_weekday_abbrev( $weekday = '' ){ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); - - if( $weekday === '' ) - return $yourls_locale_formats->weekday_abbrev; - - if( is_int( $weekday ) ) { - $day = $yourls_locale_formats->weekday[ $weekday ]; - return $yourls_locale_formats->weekday_abbrev[ $day ]; - } else { - return $yourls_locale_formats->weekday_abbrev[ yourls__( $weekday ) ]; - } + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); + + if( $weekday === '' ) + return $yourls_locale_formats->weekday_abbrev; + + if( is_int( $weekday ) ) { + $day = $yourls_locale_formats->weekday[ $weekday ]; + return $yourls_locale_formats->weekday_abbrev[ $day ]; + } else { + return $yourls_locale_formats->weekday_abbrev[ yourls__( $weekday ) ]; + } } /** @@ -1072,19 +1058,19 @@ function yourls_l10n_weekday_abbrev( $weekday = '' ){ * @return mixed Translated weekday initial, eg "V" (initial of "Vendredi") for "Friday" or 5, or array of all weekday initials */ function yourls_l10n_weekday_initial( $weekday = '' ){ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); - - if( $weekday === '' ) - return $yourls_locale_formats->weekday_initial; - - if( is_int( $weekday ) ) { - $weekday = $yourls_locale_formats->weekday[ $weekday ]; - return $yourls_locale_formats->weekday_initial[ $weekday ]; - } else { - return $yourls_locale_formats->weekday_initial[ yourls__( $weekday ) ]; - } + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); + + if( $weekday === '' ) + return $yourls_locale_formats->weekday_initial; + + if( is_int( $weekday ) ) { + $weekday = $yourls_locale_formats->weekday[ $weekday ]; + return $yourls_locale_formats->weekday_initial[ $weekday ]; + } else { + return $yourls_locale_formats->weekday_initial[ yourls__( $weekday ) ]; + } } /** @@ -1098,20 +1084,20 @@ function yourls_l10n_weekday_initial( $weekday = '' ){ * @return mixed Translated month abbrev (eg "Nov"), or array of all translated abbrev months */ function yourls_l10n_month_abbrev( $month = '' ){ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - if( $month === '' ) - return $yourls_locale_formats->month_abbrev; + if( $month === '' ) + return $yourls_locale_formats->month_abbrev; - if( intval( $month ) > 0 ) { + if( intval( $month ) > 0 ) { $month = sprintf('%02d', intval( $month ) ); - $month = $yourls_locale_formats->month[ $month ]; - return $yourls_locale_formats->month_abbrev[ $month ]; - } else { - return $yourls_locale_formats->month_abbrev[ yourls__( $month ) ]; - } + $month = $yourls_locale_formats->month[ $month ]; + return $yourls_locale_formats->month_abbrev[ $month ]; + } else { + return $yourls_locale_formats->month_abbrev[ yourls__( $month ) ]; + } } /** @@ -1121,9 +1107,9 @@ function yourls_l10n_month_abbrev( $month = '' ){ * @return array Array of all translated months */ function yourls_l10n_months(){ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - return $yourls_locale_formats->month; + return $yourls_locale_formats->month; } diff --git a/includes/functions-options.php b/includes/functions-options.php index f2728f4..30fce60 100644 --- a/includes/functions-options.php +++ b/includes/functions-options.php @@ -21,7 +21,7 @@ function yourls_get_option( $option_name, $default = false ) { return $pre; } - $option = new \YOURLS\Database\Options(yourls_get_db()); + $option = new \YOURLS\Database\Options(yourls_get_db('read-get_option')); $value = $option->get($option_name, $default); return yourls_apply_filter( 'get_option_'.$option_name, $value ); @@ -45,7 +45,7 @@ function yourls_get_all_options() { return $pre; } - $options = new \YOURLS\Database\Options(yourls_get_db()); + $options = new \YOURLS\Database\Options(yourls_get_db('read-get_all_options')); if ($options->get_all_options() === false) { // Zero option found but no unexpected error so far: YOURLS isn't installed @@ -67,7 +67,7 @@ function yourls_get_all_options() { * @return bool False if value was not updated, true otherwise. */ function yourls_update_option( $option_name, $newvalue ) { - $option = new \YOURLS\Database\Options(yourls_get_db()); + $option = new \YOURLS\Database\Options(yourls_get_db('write-update_option')); $update = $option->update($option_name, $newvalue); return $update; @@ -84,7 +84,7 @@ function yourls_update_option( $option_name, $newvalue ) { * @return bool False if option was not added and true otherwise. */ function yourls_add_option( $name, $value = '' ) { - $option = new \YOURLS\Database\Options(yourls_get_db()); + $option = new \YOURLS\Database\Options(yourls_get_db('write-add_option')); $add = $option->add($name, $value); return $add; @@ -100,7 +100,7 @@ function yourls_add_option( $name, $value = '' ) { * @return bool True, if option is successfully deleted. False on failure. */ function yourls_delete_option( $name ) { - $option = new \YOURLS\Database\Options(yourls_get_db()); + $option = new \YOURLS\Database\Options(yourls_get_db('write-delete_option')); $delete = $option->delete($name); return $delete; diff --git a/includes/functions-plugins.php b/includes/functions-plugins.php index 5bf3561..107a184 100644 --- a/includes/functions-plugins.php +++ b/includes/functions-plugins.php @@ -87,7 +87,6 @@ * @param int $accepted_args optional. The number of arguments the function accept (default is the number * provided). * @param string $type - * @global array $yourls_filters Storage for all of the filters * @return void */ function yourls_add_filter( $hook, $function_name, $priority = 10, $accepted_args = NULL, $type = 'filter' ) { @@ -123,7 +122,7 @@ function yourls_add_filter( $hook, $function_name, $priority = 10, $accepted_arg * @return void */ function yourls_add_action( $hook, $function_name, $priority = 10, $accepted_args = 1 ) { - yourls_add_filter( $hook, $function_name, $priority, $accepted_args, 'action' ); + yourls_add_filter( $hook, $function_name, $priority, $accepted_args, 'action' ); } /** @@ -175,17 +174,16 @@ function yourls_filter_unique_id($function) { * * Typical use: * - * 1) Modify a variable if a function is attached to hook 'yourls_hook' - * $yourls_var = "default value"; - * $yourls_var = yourls_apply_filter( 'yourls_hook', $yourls_var ); + * 1) Modify a variable if a function is attached to hook 'yourls_hook' + * $yourls_var = "default value"; + * $yourls_var = yourls_apply_filter( 'yourls_hook', $yourls_var ); * - * 2) Trigger functions is attached to event 'yourls_event' - * yourls_apply_filter( 'yourls_event' ); + * 2) Trigger functions is attached to event 'yourls_event' + * yourls_apply_filter( 'yourls_event' ); * (see yourls_do_action() ) * * Returns a value which may have been modified by a filter. * - * @global array $yourls_filters storage for all of the filters * @param string $hook the name of the YOURLS element or action * @param mixed $value the value of the element before filtering * @param true|mixed $is_action true if the function is called by yourls_do_action() - otherwise may be the second parameter of an arbitrary number of parameters @@ -332,7 +330,6 @@ function yourls_call_all_hooks($type, $hook, ...$args) { * To remove a hook, the $function_to_remove and $priority arguments must match * when the hook was added. * - * @global array $yourls_filters storage for all of the filters * @param string $hook The filter hook to which the function to be removed is hooked. * @param callable $function_to_remove The name of the function which should be removed. * @param int $priority optional. The priority of the function (default: 10). @@ -433,7 +430,6 @@ function yourls_get_actions($hook) { * Check if any filter has been registered for a hook. * * @since 1.5 - * @global array $yourls_filters storage for all of the filters * @param string $hook The name of the filter hook. * @param callable|false $function_to_check optional. If specified, return the priority of that function on this hook or false if not attached. * @return int|bool Optionally returns the priority on that hook for the specified function. @@ -477,7 +473,7 @@ function yourls_has_action( $hook, $function_to_check = false ) { * @return int Number of activated plugins */ function yourls_has_active_plugins() { - return count( yourls_get_db()->get_plugins() ); + return count( yourls_get_db('read-has_active_plugins')->get_plugins() ); } /** @@ -506,7 +502,7 @@ function yourls_get_plugins() { */ function yourls_is_active_plugin( $plugin ) { return yourls_has_active_plugins() > 0 ? - in_array( yourls_plugin_basename( $plugin ), yourls_get_db()->get_plugins() ) + in_array( yourls_plugin_basename( $plugin ), yourls_get_db('read-is_active_plugin')->get_plugins() ) : false; } @@ -602,7 +598,7 @@ function yourls_load_plugins() { } // Replace active plugin list with list of plugins we just activated - yourls_get_db()->set_plugins( $plugins ); + yourls_get_db('read-load_plugins')->set_plugins( $plugins ); $info = count( $plugins ).' activated'; // $active_plugins should be empty now, if not, a plugin could not be found, or is erroneous : remove it @@ -653,7 +649,7 @@ function yourls_activate_plugin( $plugin ) { } // check not activated already - $ydb = yourls_get_db(); + $ydb = yourls_get_db('read-activate_plugin'); if ( yourls_is_active_plugin( $plugin ) ) { return yourls__( 'Plugin already activated' ); } @@ -703,7 +699,7 @@ function yourls_deactivate_plugin( $plugin ) { } // Deactivate the plugin - $ydb = yourls_get_db(); + $ydb = yourls_get_db('read-deactivate_plugin'); $plugins = $ydb->get_plugins(); $key = array_search( $plugin, $plugins ); if ( $key !== false ) { @@ -726,7 +722,7 @@ function yourls_deactivate_plugin( $plugin ) { * @return string */ function yourls_plugin_basename( $file ) { - return trim( str_replace( yourls_sanitize_filename( YOURLS_PLUGINDIR ), '', yourls_sanitize_filename( $file ) ), '/' ); + return trim( str_replace( yourls_sanitize_filename( YOURLS_PLUGINDIR ), '', yourls_sanitize_filename( $file ) ), '/' ); } /** @@ -752,7 +748,7 @@ function yourls_plugin_url( $file ) { */ function yourls_list_plugin_admin_pages() { $plugin_links = []; - foreach ( yourls_get_db()->get_plugin_pages() as $plugin => $page ) { + foreach ( yourls_get_db('read-list_plugin_admin_pages')->get_plugin_pages() as $plugin => $page ) { $plugin_links[ $plugin ] = [ 'url' => yourls_admin_url( 'plugins.php?page='.$page[ 'slug' ] ), 'anchor' => $page[ 'title' ], @@ -771,7 +767,7 @@ function yourls_list_plugin_admin_pages() { * @return void */ function yourls_register_plugin_page( $slug, $title, $function ) { - yourls_get_db()->add_plugin_page( $slug, $title, $function ); + yourls_get_db('read-register_plugin_page')->add_plugin_page( $slug, $title, $function ); } /** @@ -783,7 +779,7 @@ function yourls_register_plugin_page( $slug, $title, $function ) { */ function yourls_plugin_admin_page( $plugin_page ) { // Check the plugin page is actually registered - $pages = yourls_get_db()->get_plugin_pages(); + $pages = yourls_get_db('read-plugin_admin_page')->get_plugin_pages(); if ( !isset( $pages[ $plugin_page ] ) ) { yourls_die( yourls__( 'This page does not exist. Maybe a plugin you thought was activated is inactive?' ), yourls__( 'Invalid link' ) ); } diff --git a/includes/functions-shorturls.php b/includes/functions-shorturls.php index ecc1c64..d1fc918 100644 --- a/includes/functions-shorturls.php +++ b/includes/functions-shorturls.php @@ -207,6 +207,20 @@ function yourls_is_shorturl( $shorturl ) { return yourls_apply_filter( 'is_shorturl', $is_short, $shorturl ); } +/** + * Get the list of reserved keywords for URLs. + * + * @return array Array of reserved keywords + */ +function yourls_get_reserved_URL() { + global $yourls_reserved_URL; + if ( ! isset( $yourls_reserved_URL ) || ! is_array( $yourls_reserved_URL ) ) { + return array(); + } + + return $yourls_reserved_URL; +} + /** * Check to see if a given keyword is reserved (ie reserved URL or an existing page). Returns bool * @@ -214,11 +228,10 @@ function yourls_is_shorturl( $shorturl ) { * @return bool True if keyword reserved, false if free to be used */ function yourls_keyword_is_reserved( $keyword ) { - global $yourls_reserved_URL; $keyword = yourls_sanitize_keyword( $keyword ); $reserved = false; - if ( in_array( $keyword, $yourls_reserved_URL) + if ( in_array( $keyword, yourls_get_reserved_URL() ) or yourls_is_page($keyword) or is_dir( YOURLS_ABSPATH ."/$keyword" ) ) @@ -242,7 +255,9 @@ function yourls_delete_link_by_keyword( $keyword ) { $table = YOURLS_DB_TABLE_URL; $keyword = yourls_sanitize_keyword($keyword); - $delete = yourls_get_db()->fetchAffected("DELETE FROM `$table` WHERE `keyword` = :keyword", array('keyword' => $keyword)); + $ydb = yourls_get_db('write-delete_link_by_keyword'); + $delete = $ydb->fetchAffected("DELETE FROM `$table` WHERE `keyword` = :keyword", array('keyword' => $keyword)); + $ydb->delete_infos($keyword); // Clear the cache. yourls_do_action( 'delete_link', $keyword, $delete ); return $delete; } @@ -270,7 +285,14 @@ function yourls_insert_link_in_db($url, $keyword, $title = '' ) { 'timestamp' => $timestamp, 'ip' => $ip, ); - $insert = yourls_get_db()->fetchAffected("INSERT INTO `$table` (`keyword`, `url`, `title`, `timestamp`, `ip`, `clicks`) VALUES(:keyword, :url, :title, :timestamp, :ip, 0);", $binds); + $ydb = yourls_get_db('write-insert_link_in_db'); + $insert = $ydb->fetchAffected("INSERT INTO `$table` (`keyword`, `url`, `title`, `timestamp`, `ip`, `clicks`) VALUES(:keyword, :url, :title, :timestamp, :ip, 0);", $binds); + + if ( $insert ) { + $infos = $binds; + $infos['clicks'] = 0; + $ydb->set_infos($keyword, $infos); + } yourls_do_action( 'insert_link', (bool)$insert, $url, $keyword, $title, $timestamp, $ip ); @@ -295,7 +317,7 @@ function yourls_long_url_exists( $url ) { $table = YOURLS_DB_TABLE_URL; $url = yourls_sanitize_url($url); - $url_exists = yourls_get_db()->fetchObject("SELECT * FROM `$table` WHERE `url` = :url", array('url'=>$url)); + $url_exists = yourls_get_db('read-long_url_exists')->fetchObject("SELECT * FROM `$table` WHERE `url` = :url", array('url'=>$url)); if ($url_exists === false) { $url_exists = NULL; @@ -319,7 +341,7 @@ function yourls_edit_link($url, $keyword, $newkeyword='', $title='' ) { if ( null !== $pre ) return $pre; - $ydb = yourls_get_db(); + $ydb = yourls_get_db('write-edit_link'); $table = YOURLS_DB_TABLE_URL; $url = yourls_sanitize_url($url); @@ -366,6 +388,10 @@ function yourls_edit_link($url, $keyword, $newkeyword='', $title='' ) { ); $return['status'] = 'success'; $return['message'] = yourls__( 'Link updated in database' ); + $ydb->update_infos_if_exists($newkeyword, array('url' => $url, 'title' => $title)); // Clear the cache. + if ($keyword != $newkeyword) { + $ydb->delete_infos($keyword); // Clear the cache on the old keyword. + } } else { $return['status'] = 'fail'; $return['message'] = /* //translators: "Error updating http://someurl/ (Shorturl: http://sho.rt/blah)" */ yourls_s( 'Error updating %s (Short URL: %s)', yourls_esc_html(yourls_trim_long_string($url)), $keyword ) ; @@ -398,7 +424,12 @@ function yourls_edit_link_title( $keyword, $title ) { $title = yourls_sanitize_title( $title ); $table = YOURLS_DB_TABLE_URL; - $update = yourls_get_db()->fetchAffected("UPDATE `$table` SET `title` = :title WHERE `keyword` = :keyword;", array('title' => $title, 'keyword' => $keyword)); + $ydb = yourls_get_db('write-edit_link_title'); + $update = $ydb->fetchAffected("UPDATE `$table` SET `title` = :title WHERE `keyword` = :keyword;", array('title' => $title, 'keyword' => $keyword)); + + if ( $update ) { + $ydb->update_infos_if_exists( $keyword, array('title' => $title) ); + } return $update; } @@ -471,7 +502,7 @@ function yourls_keyword_is_taken( $keyword, $use_cache = true ) { * @return false|object false if not found, object with URL properties if found */ function yourls_get_keyword_infos( $keyword, $use_cache = true ) { - $ydb = yourls_get_db(); + $ydb = yourls_get_db('read-get_keyword_infos'); $keyword = yourls_sanitize_keyword( $keyword ); yourls_do_action( 'pre_get_keyword', $keyword, $use_cache ); @@ -590,7 +621,7 @@ function yourls_get_keyword_stats( $shorturl ) { $table_url = YOURLS_DB_TABLE_URL; $shorturl = yourls_sanitize_keyword( $shorturl ); - $res = yourls_get_db()->fetchObject("SELECT * FROM `$table_url` WHERE `keyword` = :keyword", array('keyword' => $shorturl)); + $res = yourls_get_db('read-get_keyword_stats')->fetchObject("SELECT * FROM `$table_url` WHERE `keyword` = :keyword", array('keyword' => $shorturl)); if( !$res ) { // non existent link @@ -633,5 +664,5 @@ function yourls_get_longurl_keywords( $longurl, $order = 'ASC' ) { $sql .= " ORDER BY `keyword` ".$order; } - return yourls_apply_filter( 'get_longurl_keywords', yourls_get_db()->fetchCol($sql, array('url'=>$longurl)), $longurl ); + return yourls_apply_filter( 'get_longurl_keywords', yourls_get_db('read-get_longurl_keywords')->fetchCol($sql, array('url'=>$longurl)), $longurl ); } diff --git a/includes/functions-upgrade.php b/includes/functions-upgrade.php index af8c284..bff246e 100644 --- a/includes/functions-upgrade.php +++ b/includes/functions-upgrade.php @@ -32,28 +32,28 @@ function yourls_upgrade($step, $oldver, $newver, $oldsql, $newsql ) { yourls_maintenance_mode(true); // special case for 1.3: the upgrade is a multi step procedure - if( $oldsql == 100 ) { - yourls_upgrade_to_14( $step ); - } + if( $oldsql == 100 ) { + yourls_upgrade_to_14( $step ); + } - // other upgrades which are done in a single pass - switch( $step ) { + // other upgrades which are done in a single pass + switch( $step ) { - case 1: - case 2: - if( $oldsql < 210 ) - yourls_upgrade_to_141(); + case 1: + case 2: + if( $oldsql < 210 ) + yourls_upgrade_to_141(); - if( $oldsql < 220 ) - yourls_upgrade_to_143(); + if( $oldsql < 220 ) + yourls_upgrade_to_143(); - if( $oldsql < 250 ) - yourls_upgrade_to_15(); + if( $oldsql < 250 ) + yourls_upgrade_to_15(); - if( $oldsql < 482 ) - yourls_upgrade_482(); // that was somewhere 1.5 and 1.5.1 ... + if( $oldsql < 482 ) + yourls_upgrade_482(); // that was somewhere 1.5 and 1.5.1 ... - if( $oldsql < 506 ) { + if( $oldsql < 506 ) { /** * 505 was the botched update with the wrong collation, see #2766 * 506 is the updated collation. @@ -61,45 +61,74 @@ function yourls_upgrade($step, $oldver, $newver, $oldsql, $newsql ) { * people on 505 to update to 506 * people before 505 to update to the FIXED complete upgrade */ - if( $oldsql == 505 ) { + if( $oldsql == 505 ) { yourls_upgrade_505_to_506(); } else { yourls_upgrade_to_506(); } } - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3" ) ); + if( $oldsql < 507 ) { + yourls_upgrade_to_507(); + } + + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3" ) ); - break; + break; - case 3: - // Update options to reflect latest version - yourls_update_option( 'version', YOURLS_VERSION ); - yourls_update_option( 'db_version', YOURLS_DB_VERSION ); + case 3: + // Update options to reflect latest version + yourls_update_option( 'version', YOURLS_VERSION ); + yourls_update_option( 'db_version', YOURLS_DB_VERSION ); yourls_maintenance_mode(false); - break; - } + break; + } } /************************** 1.6 -> 1.8 **************************/ +/** + * Add sort index for fast URL lookups. + * DB version 507. + */ +function yourls_upgrade_to_507() { + echo "

Adding index for url column. Please wait...

"; + + $table = YOURLS_DB_TABLE_URL; + + $query = sprintf("ALTER TABLE `%s` ADD INDEX `url_idx` (`url`(50));", $table); + + try { + yourls_get_db('write-upgrade_to_507')->perform($query); + } catch (\Exception $e) { + echo "

Unable to update the DB.

"; + echo "

Could not index urls. You will have to fix things manually :(. The error was +

";
+        echo $e->getMessage();
+        echo "\n
"; + die(); + } + + echo "

OK!

"; +} + /** * Update to 506, just the fix for people who had updated to master on 1.7.10 * */ function yourls_upgrade_505_to_506() { echo "

Updating DB. Please wait...

"; - // Fix collation which was wrongly set at first to utf8mb4_unicode_ci - $query = sprintf('ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;', YOURLS_DB_TABLE_URL); + // Fix collation which was wrongly set at first to utf8mb4_unicode_ci + $query = sprintf('ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;', YOURLS_DB_TABLE_URL); try { - yourls_get_db()->perform($query); + yourls_get_db('write-upgrade_505_to_506')->perform($query); } catch (\Exception $e) { echo "

Unable to update the DB.

"; echo "

Could not change collation. You will have to fix things manually :(. The error was

";
         echo $e->getMessage();
-        echo "/n
"; + echo "\n"; die(); } @@ -111,7 +140,7 @@ function yourls_upgrade_505_to_506() { * */ function yourls_upgrade_to_506() { - $ydb = yourls_get_db(); + $ydb = yourls_get_db('write-upgrade_to_506'); $error_msg = []; echo "

Updating DB. Please wait...

"; @@ -155,11 +184,11 @@ function yourls_upgrade_to_506() { * */ function yourls_upgrade_482() { - // Change URL title charset to UTF8 - $table_url = YOURLS_DB_TABLE_URL; - $sql = "ALTER TABLE `$table_url` CHANGE `title` `title` TEXT CHARACTER SET utf8;"; - yourls_get_db()->perform( $sql ); - echo "

Updating table structure. Please wait...

"; + // Change URL title charset to UTF8 + $table_url = YOURLS_DB_TABLE_URL; + $sql = "ALTER TABLE `$table_url` CHANGE `title` `title` TEXT CHARACTER SET utf8;"; + yourls_get_db('write-upgrade_482')->perform( $sql ); + echo "

Updating table structure. Please wait...

"; } /************************** 1.4.3 -> 1.5 **************************/ @@ -169,20 +198,20 @@ function yourls_upgrade_482() { * */ function yourls_upgrade_to_15( ) { - // Create empty 'active_plugins' entry in the option if needed - if( yourls_get_option( 'active_plugins' ) === false ) - yourls_add_option( 'active_plugins', array() ); - echo "

Enabling the plugin API. Please wait...

"; - - // Alter URL table to store titles - $table_url = YOURLS_DB_TABLE_URL; - $sql = "ALTER TABLE `$table_url` ADD `title` TEXT AFTER `url`;"; - yourls_get_db()->perform( $sql ); - echo "

Updating table structure. Please wait...

"; - - // Update .htaccess - yourls_create_htaccess(); - echo "

Updating .htaccess file. Please wait...

"; + // Create empty 'active_plugins' entry in the option if needed + if( yourls_get_option( 'active_plugins' ) === false ) + yourls_add_option( 'active_plugins', array() ); + echo "

Enabling the plugin API. Please wait...

"; + + // Alter URL table to store titles + $table_url = YOURLS_DB_TABLE_URL; + $sql = "ALTER TABLE `$table_url` ADD `title` TEXT AFTER `url`;"; + yourls_get_db('write-upgrade_to_15')->perform( $sql ); + echo "

Updating table structure. Please wait...

"; + + // Update .htaccess + yourls_create_htaccess(); + echo "

Updating .htaccess file. Please wait...

"; } /************************** 1.4.1 -> 1.4.3 **************************/ @@ -192,16 +221,16 @@ function yourls_upgrade_to_15( ) { * */ function yourls_upgrade_to_143( ) { - // Check if we have 'keyword' (borked install) or 'shorturl' (ok install) - $ydb = yourls_get_db(); - $table_log = YOURLS_DB_TABLE_LOG; - $sql = "SHOW COLUMNS FROM `$table_log`"; - $cols = $ydb->fetchObjects( $sql ); - if ( $cols[2]->Field == 'keyword' ) { - $sql = "ALTER TABLE `$table_log` CHANGE `keyword` `shorturl` VARCHAR( 200 ) BINARY;"; - $ydb->query( $sql ); - } - echo "

Structure of existing tables updated. Please wait...

"; + // Check if we have 'keyword' (borked install) or 'shorturl' (ok install) + $ydb = yourls_get_db('write-upgrade_to_143'); + $table_log = YOURLS_DB_TABLE_LOG; + $sql = "SHOW COLUMNS FROM `$table_log`"; + $cols = $ydb->fetchObjects( $sql ); + if ( $cols[2]->Field == 'keyword' ) { + $sql = "ALTER TABLE `$table_log` CHANGE `keyword` `shorturl` VARCHAR( 200 ) BINARY;"; + $ydb->query( $sql ); + } + echo "

Structure of existing tables updated. Please wait...

"; } /************************** 1.4 -> 1.4.1 **************************/ @@ -211,13 +240,13 @@ function yourls_upgrade_to_143( ) { * */ function yourls_upgrade_to_141( ) { - // Kill old cookies from 1.3 and prior - setcookie('yourls_username', '', time() - 3600 ); - setcookie('yourls_password', '', time() - 3600 ); - // alter table URL - yourls_alter_url_table_to_141(); - // recreate the htaccess file if needed - yourls_create_htaccess(); + // Kill old cookies from 1.3 and prior + setcookie('yourls_username', '', time() - 3600 ); + setcookie('yourls_password', '', time() - 3600 ); + // alter table URL + yourls_alter_url_table_to_141(); + // recreate the htaccess file if needed + yourls_create_htaccess(); } /** @@ -225,10 +254,10 @@ function yourls_upgrade_to_141( ) { * */ function yourls_alter_url_table_to_141() { - $table_url = YOURLS_DB_TABLE_URL; - $alter = "ALTER TABLE `$table_url` CHANGE `keyword` `keyword` VARCHAR( 200 ) BINARY, CHANGE `url` `url` TEXT BINARY "; - yourls_get_db()->perform( $alter ); - echo "

Structure of existing tables updated. Please wait...

"; + $table_url = YOURLS_DB_TABLE_URL; + $alter = "ALTER TABLE `$table_url` CHANGE `keyword` `keyword` VARCHAR( 200 ) BINARY, CHANGE `url` `url` TEXT BINARY "; + yourls_get_db('write-alter_url_table_to_141')->perform( $alter ); + echo "

Structure of existing tables updated. Please wait...

"; } @@ -240,35 +269,35 @@ function yourls_alter_url_table_to_141() { */ function yourls_upgrade_to_14( $step ) { - switch( $step ) { - case 1: - // create table log & table options - // update table url structure - // update .htaccess - yourls_create_tables_for_14(); // no value returned, assuming it went OK - yourls_alter_url_table_to_14(); // no value returned, assuming it went OK - $clean = yourls_clean_htaccess_for_14(); // returns bool - $create = yourls_create_htaccess(); // returns bool - if ( !$create ) - echo "

Please create your .htaccess file (I could not do it for you). Please refer to http://yourls.org/htaccess."; - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200" ), $create ); - break; - - case 2: - // convert each link in table url - yourls_update_table_to_14(); - break; - - case 3: - // update table url structure part 2: recreate indexes - yourls_alter_url_table_to_14_part_two(); - // update version & db_version & next_id in the option table - // attempt to drop YOURLS_DB_TABLE_NEXTDEC - yourls_update_options_to_14(); - // Now upgrade to 1.4.1 - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=1&oldver=1.4&newver=1.4.1&oldsql=200&newsql=210" ) ); - break; - } + switch( $step ) { + case 1: + // create table log & table options + // update table url structure + // update .htaccess + yourls_create_tables_for_14(); // no value returned, assuming it went OK + yourls_alter_url_table_to_14(); // no value returned, assuming it went OK + $clean = yourls_clean_htaccess_for_14(); // returns bool + $create = yourls_create_htaccess(); // returns bool + if ( !$create ) + echo "

Please create your .htaccess file (I could not do it for you). Please refer to http://yourls.org/htaccess."; + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200" ), $create ); + break; + + case 2: + // convert each link in table url + yourls_update_table_to_14(); + break; + + case 3: + // update table url structure part 2: recreate indexes + yourls_alter_url_table_to_14_part_two(); + // update version & db_version & next_id in the option table + // attempt to drop YOURLS_DB_TABLE_NEXTDEC + yourls_update_options_to_14(); + // Now upgrade to 1.4.1 + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=1&oldver=1.4&newver=1.4.1&oldsql=200&newsql=210" ) ); + break; + } } /** @@ -276,17 +305,17 @@ function yourls_upgrade_to_14( $step ) { * */ function yourls_update_options_to_14() { - yourls_update_option( 'version', '1.4' ); - yourls_update_option( 'db_version', '200' ); - - if( defined('YOURLS_DB_TABLE_NEXTDEC') ) { - $table = YOURLS_DB_TABLE_NEXTDEC; - $next_id = yourls_get_db()->fetchValue("SELECT `next_id` FROM `$table`"); - yourls_update_option( 'next_id', $next_id ); - yourls_get_db()->perform( "DROP TABLE `$table`" ); - } else { - yourls_update_option( 'next_id', 1 ); // In case someone mistakenly deleted the next_id constant or table too early - } + yourls_update_option( 'version', '1.4' ); + yourls_update_option( 'db_version', '200' ); + + if( defined('YOURLS_DB_TABLE_NEXTDEC') ) { + $table = YOURLS_DB_TABLE_NEXTDEC; + $next_id = yourls_get_db('read-update_options_to_14')->fetchValue("SELECT `next_id` FROM `$table`"); + yourls_update_option( 'next_id', $next_id ); + yourls_get_db('write-update_options_to_14')->perform( "DROP TABLE `$table`" ); + } else { + yourls_update_option( 'next_id', 1 ); // In case someone mistakenly deleted the next_id constant or table too early + } } /** @@ -294,37 +323,37 @@ function yourls_update_options_to_14() { * */ function yourls_create_tables_for_14() { - $ydb = yourls_get_db(); - - $queries = array(); - - $queries[YOURLS_DB_TABLE_OPTIONS] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_OPTIONS.'` ('. - '`option_id` int(11) unsigned NOT NULL auto_increment,'. - '`option_name` varchar(64) NOT NULL default "",'. - '`option_value` longtext NOT NULL,'. - 'PRIMARY KEY (`option_id`,`option_name`),'. - 'KEY `option_name` (`option_name`)'. - ');'; - - $queries[YOURLS_DB_TABLE_LOG] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_LOG.'` ('. - '`click_id` int(11) NOT NULL auto_increment,'. - '`click_time` datetime NOT NULL,'. - '`shorturl` varchar(200) NOT NULL,'. - '`referrer` varchar(200) NOT NULL,'. - '`user_agent` varchar(255) NOT NULL,'. - '`ip_address` varchar(41) NOT NULL,'. - '`country_code` char(2) NOT NULL,'. - 'PRIMARY KEY (`click_id`),'. - 'KEY `shorturl` (`shorturl`)'. - ');'; - - foreach( $queries as $query ) { - $ydb->perform( $query ); // There's no result to be returned to check if table was created (except making another query to check table existence, which we'll avoid) - } - - echo "

New tables created. Please wait...

"; + $ydb = yourls_get_db('write-create_tables_for_14'); + + $queries = array(); + + $queries[YOURLS_DB_TABLE_OPTIONS] = + 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_OPTIONS.'` ('. + '`option_id` int(11) unsigned NOT NULL auto_increment,'. + '`option_name` varchar(64) NOT NULL default "",'. + '`option_value` longtext NOT NULL,'. + 'PRIMARY KEY (`option_id`,`option_name`),'. + 'KEY `option_name` (`option_name`)'. + ');'; + + $queries[YOURLS_DB_TABLE_LOG] = + 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_LOG.'` ('. + '`click_id` int(11) NOT NULL auto_increment,'. + '`click_time` datetime NOT NULL,'. + '`shorturl` varchar(200) NOT NULL,'. + '`referrer` varchar(200) NOT NULL,'. + '`user_agent` varchar(255) NOT NULL,'. + '`ip_address` varchar(41) NOT NULL,'. + '`country_code` char(2) NOT NULL,'. + 'PRIMARY KEY (`click_id`),'. + 'KEY `shorturl` (`shorturl`)'. + ');'; + + foreach( $queries as $query ) { + $ydb->perform( $query ); // There's no result to be returned to check if table was created (except making another query to check table existence, which we'll avoid) + } + + echo "

New tables created. Please wait...

"; } @@ -333,20 +362,20 @@ function yourls_create_tables_for_14() { * */ function yourls_alter_url_table_to_14() { - $ydb = yourls_get_db(); - $table = YOURLS_DB_TABLE_URL; + $ydb = yourls_get_db('write-alter_url_table_to_14'); + $table = YOURLS_DB_TABLE_URL; - $alters = array(); - $results = array(); - $alters[] = "ALTER TABLE `$table` CHANGE `id` `keyword` VARCHAR( 200 ) NOT NULL"; - $alters[] = "ALTER TABLE `$table` CHANGE `url` `url` TEXT NOT NULL"; - $alters[] = "ALTER TABLE `$table` DROP PRIMARY KEY"; + $alters = array(); + $results = array(); + $alters[] = "ALTER TABLE `$table` CHANGE `id` `keyword` VARCHAR( 200 ) NOT NULL"; + $alters[] = "ALTER TABLE `$table` CHANGE `url` `url` TEXT NOT NULL"; + $alters[] = "ALTER TABLE `$table` DROP PRIMARY KEY"; - foreach ( $alters as $query ) { - $ydb->perform( $query ); - } + foreach ( $alters as $query ) { + $ydb->perform( $query ); + } - echo "

Structure of existing tables updated. Please wait...

"; + echo "

Structure of existing tables updated. Please wait...

"; } /** @@ -354,19 +383,19 @@ function yourls_alter_url_table_to_14() { * */ function yourls_alter_url_table_to_14_part_two() { - $ydb = yourls_get_db(); - $table = YOURLS_DB_TABLE_URL; + $ydb = yourls_get_db('write-alter_url_table_to_14_part_two'); + $table = YOURLS_DB_TABLE_URL; - $alters = array(); - $alters[] = "ALTER TABLE `$table` ADD PRIMARY KEY ( `keyword` )"; - $alters[] = "ALTER TABLE `$table` ADD INDEX ( `ip` )"; - $alters[] = "ALTER TABLE `$table` ADD INDEX ( `timestamp` )"; + $alters = array(); + $alters[] = "ALTER TABLE `$table` ADD PRIMARY KEY ( `keyword` )"; + $alters[] = "ALTER TABLE `$table` ADD INDEX ( `ip` )"; + $alters[] = "ALTER TABLE `$table` ADD INDEX ( `timestamp` )"; - foreach ( $alters as $query ) { - $ydb->perform( $query ); - } + foreach ( $alters as $query ) { + $ydb->perform( $query ); + } - echo "

New table index created

"; + echo "

New table index created

"; } /** @@ -374,52 +403,52 @@ function yourls_alter_url_table_to_14_part_two() { * */ function yourls_update_table_to_14() { - $ydb = yourls_get_db(); - $table = YOURLS_DB_TABLE_URL; - - // Modify each link to reflect new structure - $chunk = 45; - $from = isset($_GET['from']) ? intval( $_GET['from'] ) : 0 ; - $total = yourls_get_db_stats(); - $total = $total['total_links']; - - $sql = "SELECT `keyword`,`url` FROM `$table` WHERE 1=1 ORDER BY `url` ASC LIMIT $from, $chunk ;"; - - $rows = $ydb->fetchObjects($sql); - - $count = 0; - $queries = 0; - foreach( $rows as $row ) { - $keyword = $row->keyword; - $url = $row->url; - $newkeyword = yourls_int2string( $keyword ); - if( true === $ydb->perform("UPDATE `$table` SET `keyword` = '$newkeyword' WHERE `url` = '$url';") ) { - $queries++; - } else { - echo "

Huho... Could not update rown with url='$url', from keyword '$keyword' to keyword '$newkeyword'

"; // Find what went wrong :/ - } - $count++; - } - - // All done for this chunk of queries, did it all go as expected? - $success = true; - if( $count != $queries ) { - $success = false; - $num = $count - $queries; - echo "

$num error(s) occurred while updating the URL table :(

"; - } - - if ( $count == $chunk ) { - // there are probably other rows to convert - $from = $from + $chunk; - $remain = $total - $from; - echo "

Converted $chunk database rows ($remain remaining). Continuing... Please do not close this window until it's finished!

"; - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200&from=$from" ), $success ); - } else { - // All done - echo '

All rows converted! Please wait...

'; - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3&oldver=1.3&newver=1.4&oldsql=100&newsql=200" ), $success ); - } + $ydb = yourls_get_db('write-update_table_to_14'); + $table = YOURLS_DB_TABLE_URL; + + // Modify each link to reflect new structure + $chunk = 45; + $from = isset($_GET['from']) ? intval( $_GET['from'] ) : 0 ; + $total = yourls_get_db_stats(); + $total = $total['total_links']; + + $sql = "SELECT `keyword`,`url` FROM `$table` WHERE 1=1 ORDER BY `url` ASC LIMIT $from, $chunk ;"; + + $rows = $ydb->fetchObjects($sql); + + $count = 0; + $queries = 0; + foreach( $rows as $row ) { + $keyword = $row->keyword; + $url = $row->url; + $newkeyword = yourls_int2string( $keyword ); + if( true === $ydb->perform("UPDATE `$table` SET `keyword` = '$newkeyword' WHERE `url` = '$url';") ) { + $queries++; + } else { + echo "

Huho... Could not update rown with url='$url', from keyword '$keyword' to keyword '$newkeyword'

"; // Find what went wrong :/ + } + $count++; + } + + // All done for this chunk of queries, did it all go as expected? + $success = true; + if( $count != $queries ) { + $success = false; + $num = $count - $queries; + echo "

$num error(s) occurred while updating the URL table :(

"; + } + + if ( $count == $chunk ) { + // there are probably other rows to convert + $from = $from + $chunk; + $remain = $total - $from; + echo "

Converted $chunk database rows ($remain remaining). Continuing... Please do not close this window until it's finished!

"; + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200&from=$from" ), $success ); + } else { + // All done + echo '

All rows converted! Please wait...

'; + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3&oldver=1.3&newver=1.4&oldsql=100&newsql=200" ), $success ); + } } @@ -428,26 +457,26 @@ function yourls_update_table_to_14() { * */ function yourls_clean_htaccess_for_14() { - $filename = YOURLS_ABSPATH.'/.htaccess'; - - $result = false; - if( is_writeable( $filename ) ) { - $contents = implode( '', file( $filename ) ); - // remove "ShortURL" block - $contents = preg_replace( '/# BEGIN ShortURL.*# END ShortURL/s', '', $contents ); - // comment out deprecated RewriteRule - $find = 'RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]'; - $replace = "# You can safely remove this 5 lines block -- it's no longer used in YOURLS\n". - "# $find"; - $contents = str_replace( $find, $replace, $contents ); - - // Write cleaned file - $f = fopen( $filename, 'w' ); - fwrite( $f, $contents ); - fclose( $f ); - - $result = true; - } - - return $result; + $filename = YOURLS_ABSPATH.'/.htaccess'; + + $result = false; + if( is_writeable( $filename ) ) { + $contents = implode( '', file( $filename ) ); + // remove "ShortURL" block + $contents = preg_replace( '/# BEGIN ShortURL.*# END ShortURL/s', '', $contents ); + // comment out deprecated RewriteRule + $find = 'RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]'; + $replace = "# You can safely remove this 5 lines block -- it's no longer used in YOURLS\n". + "# $find"; + $contents = str_replace( $find, $replace, $contents ); + + // Write cleaned file + $f = fopen( $filename, 'w' ); + fwrite( $f, $contents ); + fclose( $f ); + + $result = true; + } + + return $result; } diff --git a/includes/functions.php b/includes/functions.php index 5068e2f..3884e74 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -22,22 +22,22 @@ function yourls_make_regexp_pattern( $string ) { * @return string */ function yourls_get_IP() { - $ip = ''; - - // Precedence: if set, X-Forwarded-For > HTTP_X_FORWARDED_FOR > HTTP_CLIENT_IP > HTTP_VIA > REMOTE_ADDR - $headers = [ 'X-Forwarded-For', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_VIA', 'REMOTE_ADDR' ]; - foreach( $headers as $header ) { - if ( !empty( $_SERVER[ $header ] ) ) { - $ip = $_SERVER[ $header ]; - break; - } - } - - // headers can contain multiple IPs (X-Forwarded-For = client, proxy1, proxy2). Take first one. - if ( strpos( $ip, ',' ) !== false ) - $ip = substr( $ip, 0, strpos( $ip, ',' ) ); - - return (string)yourls_apply_filter( 'get_IP', yourls_sanitize_ip( $ip ) ); + $ip = ''; + + // Precedence: if set, X-Forwarded-For > HTTP_X_FORWARDED_FOR > HTTP_CLIENT_IP > HTTP_VIA > REMOTE_ADDR + $headers = [ 'X-Forwarded-For', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_VIA', 'REMOTE_ADDR' ]; + foreach( $headers as $header ) { + if ( !empty( $_SERVER[ $header ] ) ) { + $ip = $_SERVER[ $header ]; + break; + } + } + + // headers can contain multiple IPs (X-Forwarded-For = client, proxy1, proxy2). Take first one. + if ( strpos( $ip, ',' ) !== false ) + $ip = substr( $ip, 0, strpos( $ip, ',' ) ); + + return (string)yourls_apply_filter( 'get_IP', yourls_sanitize_ip( $ip ) ); } /** @@ -47,7 +47,7 @@ function yourls_get_IP() { * @return int id of next link */ function yourls_get_next_decimal() { - return (int)yourls_apply_filter( 'get_next_decimal', (int)yourls_get_option( 'next_id' ) ); + return (int)yourls_apply_filter( 'get_next_decimal', (int)yourls_get_option( 'next_id' ) ); } /** @@ -64,10 +64,10 @@ function yourls_get_next_decimal() { * @return bool true or false depending on if there has been an actual MySQL query. See note above. */ function yourls_update_next_decimal( $int = 0 ) { - $int = ( $int == 0 ) ? yourls_get_next_decimal() + 1 : (int)$int ; - $update = yourls_update_option( 'next_id', $int ); - yourls_do_action( 'update_next_decimal', $int, $update ); - return $update; + $int = ( $int == 0 ) ? yourls_get_next_decimal() + 1 : (int)$int ; + $update = yourls_update_option( 'next_id', $int ); + yourls_do_action( 'update_next_decimal', $int, $update ); + return $update; } /** @@ -88,32 +88,52 @@ function yourls_xml_encode( $array ) { * @return int 0 or 1 for error/success */ function yourls_update_clicks( $keyword, $clicks = false ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_update_clicks', false, $keyword, $clicks ); - if ( false !== $pre ) { + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_update_clicks', false, $keyword, $clicks ); + if ( false !== $pre ) { return $pre; } - $keyword = yourls_sanitize_keyword( $keyword ); - $table = YOURLS_DB_TABLE_URL; - if ( $clicks !== false && is_int( $clicks ) && $clicks >= 0 ) { + $keyword = yourls_sanitize_keyword( $keyword ); + $table = YOURLS_DB_TABLE_URL; + if ( $clicks !== false && is_int( $clicks ) && $clicks >= 0 ) { $update = "UPDATE `$table` SET `clicks` = :clicks WHERE `keyword` = :keyword"; $values = [ 'clicks' => $clicks, 'keyword' => $keyword ]; + $update_type = 'set'; } else { $update = "UPDATE `$table` SET `clicks` = clicks + 1 WHERE `keyword` = :keyword"; $values = [ 'keyword' => $keyword ]; + $update_type = 'increment'; } - // Try and update click count. An error probably means a concurrency problem : just skip the update + $ydb = yourls_get_db('write-update_clicks'); + + // Try and update click count. An error probably means a concurrency problem : just skip the update try { - $result = yourls_get_db()->fetchAffected($update, $values); + $result = $ydb->fetchAffected($update, $values); } catch (Exception $e) { - $result = 0; + $result = 0; + } + + if ( $result ) { + if ( $ydb->has_infos($keyword) ) { + if ( $update_type === 'increment' ) { + $infos = $ydb->get_infos($keyword); + if ( isset( $infos['clicks'] ) ) { + $infos['clicks']++; + $ydb->set_infos($keyword, $infos); + } else { + $ydb->delete_infos($keyword); // We don't know why it's missing, so just purge the cache. + } + } elseif ( $update_type === 'set' ) { + $ydb->update_infos_if_exists($keyword, ['clicks' => $clicks]); + } + } } - yourls_do_action( 'update_clicks', $keyword, $result, $clicks ); + yourls_do_action( 'update_clicks', $keyword, $result, $clicks ); - return $result; + return $result; } @@ -126,55 +146,55 @@ function yourls_update_clicks( $keyword, $clicks = false ) { * @return array Array of links */ function yourls_get_stats($filter = 'top', $limit = 10, $start = 0) { - switch( $filter ) { - case 'bottom': - $sort_by = '`clicks`'; - $sort_order = 'asc'; - break; - case 'last': - $sort_by = '`timestamp`'; - $sort_order = 'desc'; - break; - case 'rand': - case 'random': - $sort_by = 'RAND()'; - $sort_order = ''; - break; - case 'top': - default: - $sort_by = '`clicks`'; - $sort_order = 'desc'; - break; - } - - // Fetch links - $limit = intval( $limit ); - $start = intval( $start ); - if ( $limit > 0 ) { - - $table_url = YOURLS_DB_TABLE_URL; - $results = yourls_get_db()->fetchObjects( "SELECT * FROM `$table_url` WHERE 1=1 ORDER BY $sort_by $sort_order LIMIT $start, $limit;" ); - - $return = []; - $i = 1; - - foreach ( (array)$results as $res ) { - $return['links']['link_'.$i++] = [ - 'shorturl' => yourls_link($res->keyword), - 'url' => $res->url, - 'title' => $res->title, - 'timestamp'=> $res->timestamp, - 'ip' => $res->ip, - 'clicks' => $res->clicks, + switch( $filter ) { + case 'bottom': + $sort_by = '`clicks`'; + $sort_order = 'asc'; + break; + case 'last': + $sort_by = '`timestamp`'; + $sort_order = 'desc'; + break; + case 'rand': + case 'random': + $sort_by = 'RAND()'; + $sort_order = ''; + break; + case 'top': + default: + $sort_by = '`clicks`'; + $sort_order = 'desc'; + break; + } + + // Fetch links + $limit = intval( $limit ); + $start = intval( $start ); + if ( $limit > 0 ) { + + $table_url = YOURLS_DB_TABLE_URL; + $results = yourls_get_db('read-get_stats')->fetchObjects( "SELECT * FROM `$table_url` WHERE 1=1 ORDER BY $sort_by $sort_order LIMIT $start, $limit;" ); + + $return = []; + $i = 1; + + foreach ( (array)$results as $res ) { + $return['links']['link_'.$i++] = [ + 'shorturl' => yourls_link($res->keyword), + 'url' => $res->url, + 'title' => $res->title, + 'timestamp'=> $res->timestamp, + 'ip' => $res->ip, + 'clicks' => $res->clicks, ]; - } - } + } + } - $return['stats'] = yourls_get_db_stats(); + $return['stats'] = yourls_get_db_stats(); - $return['statusCode'] = '200'; + $return['statusCode'] = '200'; - return yourls_apply_filter( 'get_stats', $return, $filter, $limit, $start ); + return yourls_apply_filter( 'get_stats', $return, $filter, $limit, $start ); } /** @@ -188,12 +208,12 @@ function yourls_get_stats($filter = 'top', $limit = 10, $start = 0) { * @return array */ function yourls_get_db_stats( $where = [ 'sql' => '', 'binds' => [] ] ) { - $table_url = YOURLS_DB_TABLE_URL; + $table_url = YOURLS_DB_TABLE_URL; - $totals = yourls_get_db()->fetchObject( "SELECT COUNT(keyword) as count, SUM(clicks) as sum FROM `$table_url` WHERE 1=1 " . $where['sql'] , $where['binds'] ); - $return = [ 'total_links' => $totals->count, 'total_clicks' => $totals->sum ]; + $totals = yourls_get_db('read-get_db_stats')->fetchObject( "SELECT COUNT(keyword) as count, SUM(clicks) as sum FROM `$table_url` WHERE 1=1 " . $where['sql'] , $where['binds'] ); + $return = [ 'total_links' => $totals->count, 'total_clicks' => $totals->sum ]; - return yourls_apply_filter( 'get_db_stats', $return, $where ); + return yourls_apply_filter( 'get_db_stats', $return, $where ); } /** @@ -239,25 +259,25 @@ function yourls_get_referrer() { * @return int 1 for header redirection, 2 for js redirection, 3 otherwise (CLI) */ function yourls_redirect( $location, $code = 301 ) { - yourls_do_action( 'pre_redirect', $location, $code ); - $location = yourls_apply_filter( 'redirect_location', $location, $code ); - $code = yourls_apply_filter( 'redirect_code', $code, $location ); - - // Redirect, either properly if possible, or via Javascript otherwise - if( !headers_sent() ) { - yourls_status_header( $code ); - header( "Location: $location" ); + yourls_do_action( 'pre_redirect', $location, $code ); + $location = yourls_apply_filter( 'redirect_location', $location, $code ); + $code = yourls_apply_filter( 'redirect_code', $code, $location ); + + // Redirect, either properly if possible, or via Javascript otherwise + if( !headers_sent() ) { + yourls_status_header( $code ); + header( "Location: $location" ); return 1; - } + } - // Headers sent : redirect with JS if not in CLI - if( php_sapi_name() !== 'cli') { + // Headers sent : redirect with JS if not in CLI + if( php_sapi_name() !== 'cli') { yourls_redirect_javascript( $location ); return 2; - } + } - // We're in CLI - return 3; + // We're in CLI + return 3; } /** @@ -355,12 +375,12 @@ function yourls_no_frame_header() { */ function yourls_content_type_header( $type ) { yourls_do_action( 'content_type_header', $type ); - if( !headers_sent() ) { - $charset = yourls_apply_filter( 'content_type_header_charset', 'utf-8' ); - header( "Content-Type: $type; charset=$charset" ); - return true; - } - return false; + if( !headers_sent() ) { + $charset = yourls_apply_filter( 'content_type_header_charset', 'utf-8' ); + header( "Content-Type: $type; charset=$charset" ); + return true; + } + return false; } /** @@ -371,19 +391,19 @@ function yourls_content_type_header( $type ) { * @return bool whether header was sent */ function yourls_status_header( $code = 200 ) { - yourls_do_action( 'status_header', $code ); + yourls_do_action( 'status_header', $code ); - if( headers_sent() ) - return false; + if( headers_sent() ) + return false; - $protocol = $_SERVER['SERVER_PROTOCOL']; - if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol ) - $protocol = 'HTTP/1.0'; + $protocol = $_SERVER['SERVER_PROTOCOL']; + if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol ) + $protocol = 'HTTP/1.0'; - $code = intval( $code ); - $desc = yourls_get_HTTP_status( $code ); + $code = intval( $code ); + $desc = yourls_get_HTTP_status( $code ); - @header ("$protocol $code $desc"); // This causes problems on IIS and some FastCGI setups + @header ("$protocol $code $desc"); // This causes problems on IIS and some FastCGI setups return true; } @@ -402,10 +422,10 @@ function yourls_redirect_javascript( $location, $dontwait = true ) { if ( $dontwait ) { $message = yourls_s( 'if you are not redirected after 10 seconds, please click here', $location ); echo << - window.location="$location"; - - ($message) + + ($message) REDIR; } else { @@ -421,63 +441,63 @@ function yourls_redirect_javascript( $location, $dontwait = true ) { * @return string */ function yourls_get_HTTP_status( $code ) { - $code = intval( $code ); - $headers_desc = [ - 100 => 'Continue', - 101 => 'Switching Protocols', - 102 => 'Processing', - - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 207 => 'Multi-Status', - 226 => 'IM Used', - - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 306 => 'Reserved', - 307 => 'Temporary Redirect', - - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 422 => 'Unprocessable Entity', - 423 => 'Locked', - 424 => 'Failed Dependency', - 426 => 'Upgrade Required', - - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - 506 => 'Variant Also Negotiates', - 507 => 'Insufficient Storage', - 510 => 'Not Extended' + $code = intval( $code ); + $headers_desc = [ + 100 => 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 226 => 'IM Used', + + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => 'Reserved', + 307 => 'Temporary Redirect', + + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 426 => 'Upgrade Required', + + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', + 510 => 'Not Extended' ]; return $headers_desc[$code] ?? ''; @@ -494,17 +514,17 @@ function yourls_get_HTTP_status( $code ) { * @return mixed Result of the INSERT query (1 on success) */ function yourls_log_redirect( $keyword ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_log_redirect', false, $keyword ); - if ( false !== $pre ) { + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_log_redirect', false, $keyword ); + if ( false !== $pre ) { return $pre; } - if (!yourls_do_log_redirect()) { + if (!yourls_do_log_redirect()) { return true; } - $table = YOURLS_DB_TABLE_LOG; + $table = YOURLS_DB_TABLE_LOG; $ip = yourls_get_IP(); $binds = [ 'now' => date( 'Y-m-d H:i:s' ), @@ -517,7 +537,7 @@ function yourls_log_redirect( $keyword ) { // Try and log. An error probably means a concurrency problem : just skip the logging try { - $result = yourls_get_db()->fetchAffected("INSERT INTO `$table` (click_time, shorturl, referrer, user_agent, ip_address, country_code) VALUES (:now, :keyword, :referrer, :ua, :ip, :location)", $binds ); + $result = yourls_get_db('write-log_redirect')->fetchAffected("INSERT INTO `$table` (click_time, shorturl, referrer, user_agent, ip_address, country_code) VALUES (:now, :keyword, :referrer, :ua, :ip, :location)", $binds ); } catch (Exception $e) { $result = 0; } @@ -531,7 +551,7 @@ function yourls_log_redirect( $keyword ) { * @return bool */ function yourls_do_log_redirect() { - return ( !defined( 'YOURLS_NOSTATS' ) || YOURLS_NOSTATS != true ); + return ( !defined( 'YOURLS_NOSTATS' ) || YOURLS_NOSTATS != true ); } /** @@ -622,54 +642,54 @@ function yourls_allow_duplicate_longurls() { */ function yourls_check_IP_flood( $ip = '' ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_check_IP_flood', false, $ip ); - if ( false !== $pre ) - return $pre; - - yourls_do_action( 'pre_check_ip_flood', $ip ); // at this point $ip can be '', check it if your plugin hooks in here - - // Raise white flag if installing or if no flood delay defined - if( - ( defined('YOURLS_FLOOD_DELAY_SECONDS') && YOURLS_FLOOD_DELAY_SECONDS === 0 ) || - !defined('YOURLS_FLOOD_DELAY_SECONDS') || - yourls_is_installing() - ) - return true; - - // Don't throttle logged in users - if( yourls_is_private() ) { - if( yourls_is_valid_user() === true ) - return true; - } - - // Don't throttle whitelist IPs - if( defined( 'YOURLS_FLOOD_IP_WHITELIST' ) && YOURLS_FLOOD_IP_WHITELIST ) { - $whitelist_ips = explode( ',', YOURLS_FLOOD_IP_WHITELIST ); - foreach( (array)$whitelist_ips as $whitelist_ip ) { - $whitelist_ip = trim( $whitelist_ip ); - if ( $whitelist_ip == $ip ) - return true; - } - } - - $ip = ( $ip ? yourls_sanitize_ip( $ip ) : yourls_get_IP() ); - - yourls_do_action( 'check_ip_flood', $ip ); - - $table = YOURLS_DB_TABLE_URL; - $lasttime = yourls_get_db()->fetchValue( "SELECT `timestamp` FROM $table WHERE `ip` = :ip ORDER BY `timestamp` DESC LIMIT 1", [ 'ip' => $ip ] ); - if( $lasttime ) { - $now = date( 'U' ); - $then = date( 'U', strtotime( $lasttime ) ); - if( ( $now - $then ) <= YOURLS_FLOOD_DELAY_SECONDS ) { - // Flood! - yourls_do_action( 'ip_flood', $ip, $now - $then ); - yourls_die( yourls__( 'Too many URLs added too fast. Slow down please.' ), yourls__( 'Too Many Requests' ), 429 ); - } - } - - return true; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_check_IP_flood', false, $ip ); + if ( false !== $pre ) + return $pre; + + yourls_do_action( 'pre_check_ip_flood', $ip ); // at this point $ip can be '', check it if your plugin hooks in here + + // Raise white flag if installing or if no flood delay defined + if( + ( defined('YOURLS_FLOOD_DELAY_SECONDS') && YOURLS_FLOOD_DELAY_SECONDS === 0 ) || + !defined('YOURLS_FLOOD_DELAY_SECONDS') || + yourls_is_installing() + ) + return true; + + // Don't throttle logged in users + if( yourls_is_private() ) { + if( yourls_is_valid_user() === true ) + return true; + } + + // Don't throttle whitelist IPs + if( defined( 'YOURLS_FLOOD_IP_WHITELIST' ) && YOURLS_FLOOD_IP_WHITELIST ) { + $whitelist_ips = explode( ',', YOURLS_FLOOD_IP_WHITELIST ); + foreach( (array)$whitelist_ips as $whitelist_ip ) { + $whitelist_ip = trim( $whitelist_ip ); + if ( $whitelist_ip == $ip ) + return true; + } + } + + $ip = ( $ip ? yourls_sanitize_ip( $ip ) : yourls_get_IP() ); + + yourls_do_action( 'check_ip_flood', $ip ); + + $table = YOURLS_DB_TABLE_URL; + $lasttime = yourls_get_db('read-check_ip_flood')->fetchValue( "SELECT `timestamp` FROM $table WHERE `ip` = :ip ORDER BY `timestamp` DESC LIMIT 1", [ 'ip' => $ip ] ); + if( $lasttime ) { + $now = date( 'U' ); + $then = date( 'U', strtotime( $lasttime ) ); + if( ( $now - $then ) <= YOURLS_FLOOD_DELAY_SECONDS ) { + // Flood! + yourls_do_action( 'ip_flood', $ip, $now - $then ); + yourls_die( yourls__( 'Too many URLs added too fast. Slow down please.' ), yourls__( 'Too Many Requests' ), 429 ); + } + } + + return true; } /** @@ -679,7 +699,7 @@ function yourls_check_IP_flood( $ip = '' ) { * @return bool */ function yourls_is_installing() { - return (bool)yourls_apply_filter( 'is_installing', defined( 'YOURLS_INSTALLING' ) && YOURLS_INSTALLING ); + return (bool)yourls_apply_filter( 'is_installing', defined( 'YOURLS_INSTALLING' ) && YOURLS_INSTALLING ); } /** @@ -702,7 +722,7 @@ function yourls_is_upgrading() { * @return bool */ function yourls_is_installed() { - return (bool)yourls_apply_filter( 'is_installed', yourls_get_db()->is_installed() ); + return (bool)yourls_apply_filter( 'is_installed', yourls_get_db('read-is_installed')->is_installed() ); } /** @@ -713,7 +733,7 @@ function yourls_is_installed() { * @return void */ function yourls_set_installed( $bool ) { - yourls_get_db()->set_installed( $bool ); + yourls_get_db('read-set_installed')->set_installed( $bool ); } /** @@ -822,7 +842,7 @@ function yourls_is_admin() { * @return bool */ function yourls_is_windows() { - return defined( 'DIRECTORY_SEPARATOR' ) && DIRECTORY_SEPARATOR == '\\'; + return defined( 'DIRECTORY_SEPARATOR' ) && DIRECTORY_SEPARATOR == '\\'; } /** @@ -914,14 +934,19 @@ function yourls_get_remote_title( $url ) { // // or and all possible variations: see https://gist.github.com/ozh/7951236 if ( preg_match( '/]*charset\s*=["\' ]*([a-zA-Z0-9\-_]+)/is', $content, $found ) ) { - $charset = $found[ 1 ]; + if ( yourls_is_valid_charset( $found[ 1 ] ) ) { + $charset = $found[ 1 ]; + } unset( $found ); } - else { + if ( empty( $charset ) ) { // No charset found in HTML. Get charset as (and if) defined by the server response $_charset = current( $response->headers->getValues( 'content-type' ) ); if ( preg_match( '/charset=(\S+)/', $_charset, $found ) ) { - $charset = trim( $found[ 1 ], ';' ); + $_charset = trim( $found[ 1 ], ';' ); + if ( yourls_is_valid_charset( $_charset ) ) { + $charset = $_charset; + } unset( $found ); } } @@ -946,28 +971,43 @@ function yourls_get_remote_title( $url ) { return (string)yourls_apply_filter( 'get_remote_title', $title, $url ); } +/** + * Is supported charset encoding for conversion. + * + * @return bool + */ +function yourls_is_valid_charset( $charset ) { + if ( ! function_exists( 'mb_list_encodings' ) ) { + return false; // Okay to return false if mb_list_encodings() is not available since we won't be able to convert the charset. + } + $charset = strtolower( $charset ); + $charsets = array_map( 'strtolower', mb_list_encodings() ); + + return in_array( $charset, $charsets ); +} + /** * Quick UA check for mobile devices. * * @return bool */ function yourls_is_mobile_device() { - // Strings searched - $mobiles = [ - 'android', 'blackberry', 'blazer', - 'compal', 'elaine', 'fennec', 'hiptop', - 'iemobile', 'iphone', 'ipod', 'ipad', - 'iris', 'kindle', 'opera mobi', 'opera mini', - 'palm', 'phone', 'pocket', 'psp', 'symbian', - 'treo', 'wap', 'windows ce', 'windows phone' + // Strings searched + $mobiles = [ + 'android', 'blackberry', 'blazer', + 'compal', 'elaine', 'fennec', 'hiptop', + 'iemobile', 'iphone', 'ipod', 'ipad', + 'iris', 'kindle', 'opera mobi', 'opera mini', + 'palm', 'phone', 'pocket', 'psp', 'symbian', + 'treo', 'wap', 'windows ce', 'windows phone' ]; - // Current user-agent - $current = strtolower( $_SERVER['HTTP_USER_AGENT'] ); + // Current user-agent + $current = strtolower( $_SERVER['HTTP_USER_AGENT'] ); - // Check and return - $is_mobile = ( str_replace( $mobiles, '', $current ) != $current ); - return (bool)yourls_apply_filter( 'is_mobile_device', $is_mobile ); + // Check and return + $is_mobile = ( str_replace( $mobiles, '', $current ) != $current ); + return (bool)yourls_apply_filter( 'is_mobile_device', $is_mobile ); } /** @@ -1091,20 +1131,20 @@ function yourls_fix_request_uri() { * @return void */ function yourls_check_maintenance_mode() { - $dot_file = YOURLS_ABSPATH . '/.maintenance' ; + $dot_file = YOURLS_ABSPATH . '/.maintenance' ; if ( !file_exists( $dot_file ) || yourls_is_upgrading() || yourls_is_installing() ) { return; } - global $maintenance_start; - yourls_include_file_sandbox( $dot_file ); - // If the $maintenance_start timestamp is older than 10 minutes, don't die. - if ( ( time() - $maintenance_start ) >= 600 ) { + global $maintenance_start; + yourls_include_file_sandbox( $dot_file ); + // If the $maintenance_start timestamp is older than 10 minutes, don't die. + if ( ( time() - $maintenance_start ) >= 600 ) { return; } - // Use any /user/maintenance.php file + // Use any /user/maintenance.php file $file = YOURLS_USERDIR . '/maintenance.php'; if(file_exists($file)) { if(yourls_include_file_sandbox( $file ) == true) { @@ -1158,15 +1198,15 @@ function yourls_is_allowed_protocol( $url, $protocols = [] ) { * @return string Protocol, with slash slash if applicable. Empty string if no protocol */ function yourls_get_protocol( $url ) { - /* - http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax - The scheme name consists of a sequence of characters beginning with a letter and followed by any - combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). Although schemes are - case-insensitive, the canonical form is lowercase and documents that specify schemes must do so - with lowercase letters. It is followed by a colon (":"). - */ + /* + http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax + The scheme name consists of a sequence of characters beginning with a letter and followed by any + combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). Although schemes are + case-insensitive, the canonical form is lowercase and documents that specify schemes must do so + with lowercase letters. It is followed by a colon (":"). + */ preg_match( '!^[a-zA-Z][a-zA-Z0-9+.-]+:(//)?!', $url, $matches ); - return (string)yourls_apply_filter( 'get_protocol', isset( $matches[0] ) ? $matches[0] : '', $url ); + return (string)yourls_apply_filter( 'get_protocol', isset( $matches[0] ) ? $matches[0] : '', $url ); } /** @@ -1207,10 +1247,6 @@ function yourls_get_relative_url( $url, $strict = true ) { * This function is to be used in every function that is deprecated. * * @since 1.6 - * @uses yourls_do_action() Calls 'deprecated_function' and passes the function name, what to use instead, - * and the version the function was deprecated in. - * @uses yourls_apply_filter() Calls 'deprecated_function_trigger_error' and expects boolean value of true to do - * trigger or false to not trigger error. * * @param string $function The function that was called * @param string $version The version of WordPress that deprecated the function @@ -1219,15 +1255,15 @@ function yourls_get_relative_url( $url, $strict = true ) { */ function yourls_deprecated_function( $function, $version, $replacement = null ) { - yourls_do_action( 'deprecated_function', $function, $replacement, $version ); + yourls_do_action( 'deprecated_function', $function, $replacement, $version ); - // Allow plugin to filter the output error trigger - if ( yourls_get_debug_mode() && yourls_apply_filter( 'deprecated_function_trigger_error', true ) ) { - if ( ! is_null( $replacement ) ) - trigger_error( sprintf( yourls__('%1$s is deprecated since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) ); - else - trigger_error( sprintf( yourls__('%1$s is deprecated since version %2$s with no alternative available.'), $function, $version ) ); - } + // Allow plugin to filter the output error trigger + if ( yourls_get_debug_mode() && yourls_apply_filter( 'deprecated_function_trigger_error', true ) ) { + if ( ! is_null( $replacement ) ) + trigger_error( sprintf( yourls__('%1$s is deprecated since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) ); + else + trigger_error( sprintf( yourls__('%1$s is deprecated since version %2$s with no alternative available.'), $function, $version ) ); + } } /** diff --git a/includes/geo/COPYRIGHT.txt b/includes/geo/COPYRIGHT.txt index 7076361..51e7fe6 100644 --- a/includes/geo/COPYRIGHT.txt +++ b/includes/geo/COPYRIGHT.txt @@ -1 +1 @@ -Database and Contents Copyright (c) 2025 MaxMind, Inc. +Database and Contents Copyright (c) 2026 MaxMind, Inc. diff --git a/includes/geo/GeoLite2-Country.mmdb b/includes/geo/GeoLite2-Country.mmdb index c9cae78..fe2bce7 100644 Binary files a/includes/geo/GeoLite2-Country.mmdb and b/includes/geo/GeoLite2-Country.mmdb differ diff --git a/includes/version.php b/includes/version.php index 5ad2f40..62df24c 100644 --- a/includes/version.php +++ b/includes/version.php @@ -9,7 +9,7 @@ * MAJOR.MINOR.PATCH-SOMETHING (1.8.1-donotuse) * */ -define( 'YOURLS_VERSION', '1.10.2' ); +define( 'YOURLS_VERSION', '1.10.3' ); /** * YOURLS DB version. Increments when changes are made to the DB schema, to trigger a DB update @@ -17,4 +17,4 @@ * Must be a string of an integer. * */ -define( 'YOURLS_DB_VERSION', '506' ); +define( 'YOURLS_DB_VERSION', '507' ); diff --git a/js/common.js b/js/common.js index 65f5b6d..5850a8b 100644 --- a/js/common.js +++ b/js/common.js @@ -55,7 +55,7 @@ function logout() { // Begin the spinning animation & disable a button function add_loading(el) { - $(el).attr("disabled", "disabled").addClass('disabled').addClass('loading'); + $(el).attr("disabled", "disabled").addClass('disabled').addClass('loading').attr("aria-disabled", "true"); } // End spinning animation @@ -65,7 +65,7 @@ function end_loading(el) { // Un-disable an element function end_disable(el) { - $(el).removeAttr("disabled").removeClass('disabled'); + $(el).removeAttr("disabled").removeClass('disabled').removeAttr("aria-disabled"); } // Trim long string @@ -165,4 +165,4 @@ function get_protocol_slashes_and_rest( url ) { } else { return { protocol: '', slashes: '', rest: url };; } -} \ No newline at end of file +} diff --git a/js/insert.js b/js/insert.js index 03e004e..1f373d6 100644 --- a/js/insert.js +++ b/js/insert.js @@ -90,34 +90,65 @@ function edit_link_display(id) { // Delete a link function remove_link(id) { - if( $('#delete-button-'+id).hasClass('disabled') ) { - return false; - } - if (!confirm('Really delete?')) { - return; - } - var keyword = $('#keyword_'+id).val(); - var nonce = get_var_from_query( $('#delete-button-'+id).attr('href'), 'nonce' ); - $.getJSON( - ajaxurl, - { action: "delete", keyword: keyword, nonce: nonce, id: id }, - function(data){ - if (data.success == 1) { - $("#id-" + id).fadeOut(function(){ - $(this).remove(); - if( $('#main_table tbody tr').length == 1 ) { - $('#nourl_found').css('display', ''); - } - - zebra_table(); - }); - decrement_counter(); - decrease_total_clicks( id ); - } else { - alert('something wrong happened while deleting :/'); - } - } - ); + if( $('#delete-button-'+id).hasClass('disabled') ) { + return false; + } + var dialog = $('#delete-confirm-dialog')[0]; + dialog.showModal(); + + $('#delete-confirm-dialog input[name="keyword_id"]').val(id); + var keyword = trim_long_string( $('#keyword-'+id+' > a').text() ); + $('#delete-confirm-dialog span[name="short_url"]').text(keyword); + var title = trim_long_string( $('#url-'+id+' > a').attr('title') ); + $('#delete-confirm-dialog span[name="title"]').text(title); + var url = trim_long_string( $('#url-'+id+' > a').attr('href') ); + $('#delete-confirm-dialog span[name="url"]').text(url); + + // Listen for dialog close event (handles Escape key) + $(dialog).one('close', function() { + if (document.activeElement) { + document.activeElement.blur(); + } + }); + + // Show dialog, don't follow link + return false; +} + +function remove_link_confirmed(id) { + var id = $('#delete-confirm-dialog input[name="keyword_id"]').val(); + var keyword = $('#keyword_'+id).val(); + var nonce = get_var_from_query( $('#delete-button-'+id).attr('href'), 'nonce' ); + $.getJSON( + ajaxurl, + { action: "delete", keyword: keyword, nonce: nonce, id: id }, + function(data){ + if (data.success == 1) { + $("#id-" + id).fadeOut(function(){ + $(this).remove(); + if( $('#main_table tbody tr').length == 1 ) { + $('#nourl_found').css('display', ''); + } + + zebra_table(); + }); + decrement_counter(); + decrease_total_clicks( id ); + } else { + feedback('something wrong happened while deleting!' , 'fail'); + } + $('#delete-confirm-dialog')[0].close(); + } + ); +} + +function remove_link_canceled() { + $('#delete-confirm-dialog')[0].close(); + + // Force blur on all interactive elements to restore action buttons opacity + if (document.activeElement) { + document.activeElement.blur(); + } } // Redirect to stat page @@ -230,4 +261,3 @@ function split_search_text_before_search() { $('#filter_form input[name=search_protocol]').val( search.protocol ); $('#filter_form input[name=search_slashes]').val( search.slashes ); } - diff --git a/user/config-sample.php b/user/config-sample.php index fa2c4a1..7cfc348 100644 --- a/user/config-sample.php +++ b/user/config-sample.php @@ -8,26 +8,21 @@ /* ** MySQL settings - You can get this info from your web host - * DDev local environment: - * - Database name: db - * - Database user: db - * - Database password: db - * - Database host: db */ /** MySQL database username */ -define( 'YOURLS_DB_USER', 'db' ); +define( 'YOURLS_DB_USER', 'your db user name' ); /** MySQL database password */ -define( 'YOURLS_DB_PASS', 'db' ); +define( 'YOURLS_DB_PASS', 'your db password' ); /** The name of the database for YOURLS ** Use lower case letters [a-z], digits [0-9] and underscores [_] only */ -define( 'YOURLS_DB_NAME', 'db' ); +define( 'YOURLS_DB_NAME', 'yourls' ); /** MySQL hostname. ** If using a non standard port, specify it like 'hostname:port', e.g. 'localhost:9999' or '127.0.0.1:666' */ -define( 'YOURLS_DB_HOST', 'db' ); +define( 'YOURLS_DB_HOST', 'localhost' ); /** MySQL tables prefix ** YOURLS will create tables using this prefix (eg `yourls_url`, `yourls_options`, ...) @@ -40,14 +35,14 @@ /** YOURLS installation URL ** All lowercase, no trailing slash at the end. - ** If you define it to "http://sho.rt", don't use "http://www.sho.rt" in your browser (and vice-versa) - ** To use an IDN domain (eg http://héhé.com), write its ascii form here (eg http://xn--hh-bjab.com) */ -define( 'YOURLS_SITE', 'http://utctiny.ddev.site' ); + ** If you define it to "https://sho.rt", don't use "https://www.sho.rt" in your browser (and vice-versa) + ** To use an IDN domain (eg https://héhé.com), write its ascii form here (eg https://xn--hh-bjab.com) */ +define( 'YOURLS_SITE', 'https://your-own-domain-here.com' ); /** YOURLS language ** Change this setting to use a translation file for your language, instead of the default English. ** That translation file (a .mo file) must be installed in the user/language directory. - ** See http://yourls.org/translations for more information */ + ** See https://yourls.org/translations for more information */ define( 'YOURLS_LANG', '' ); /** Allow multiple short URLs for a same long URL @@ -57,25 +52,25 @@ /** Private means the Admin area will be protected with login/pass as defined below. ** Set to false for public usage (eg on a restricted intranet or for test setups) - ** Read http://yourls.org/privatepublic for more details if you're unsure */ + ** Read https://yourls.org/privatepublic for more details if you're unsure */ define( 'YOURLS_PRIVATE', true ); /** A random secret hash used to encrypt cookies. You don't have to remember it, make it long and complicated - ** Hint: copy from http://yourls.org/cookie */ -define( 'YOURLS_COOKIEKEY', 'YOURLS_LOCAL_COOKIEKEY' ); + ** Hint: copy from https://yourls.org/cookie */ +define( 'YOURLS_COOKIEKEY', 'modify this text with something random' ); /** Username(s) and password(s) allowed to access the site. Passwords either in plain text or as encrypted hashes ** YOURLS will auto encrypt plain text passwords in this file - ** Read http://yourls.org/userpassword for more information */ + ** Read https://yourls.org/userpassword for more information */ $yourls_user_passwords = [ - 'admin' => 'yourls', - // 'username2' => 'password2', - // You can have one or more 'login'=>'password' lines + 'username' => 'password', + // 'username2' => 'password2', + // You can have one or more 'login'=>'password' lines ]; /** URL shortening method: either 36 or 62 ** 36: generates all lowercase keywords (ie: 13jkm) - ** 62: generates mixed case keywords (ie: 13jKm or 13JKm) + ** 62: generates mixed case keywords (ie: 13jKm or 13JKm) ** For more information, see https://yourls.org/urlconvert */ define( 'YOURLS_URL_CONVERT', 36 ); @@ -88,7 +83,13 @@ * Define here negative, unwanted or potentially misleading keywords. */ $yourls_reserved_URL = [ - 'porn', 'faggot', 'sex', 'nigger', 'fuck', 'cunt', 'dick', + 'porn', + 'faggot', + 'sex', + 'nigger', + 'fuck', + 'cunt', + 'dick', ]; /* diff --git a/user/pages/examplepage.php b/user/pages/examplepage.php index f02d6ec..76f0776 100644 --- a/user/pages/examplepage.php +++ b/user/pages/examplepage.php @@ -2,8 +2,8 @@ // Make sure we're in YOURLS context if( !defined( 'YOURLS_ABSPATH' ) ) { - echo "Try using a URL without the /pages/ part"; - die(); + echo "Try using a URL without the /pages/ part"; + die(); } // Display page content. Any PHP, HTML and YOURLS function can go here. diff --git a/user/plugins/hyphens-in-urls/plugin.php b/user/plugins/hyphens-in-urls/plugin.php index c604dd5..727d369 100644 --- a/user/plugins/hyphens-in-urls/plugin.php +++ b/user/plugins/hyphens-in-urls/plugin.php @@ -23,5 +23,5 @@ yourls_add_action('add_new_link_create_keyword', function() {yourls_remove_filter('get_shorturl_charset', 'ozh_hyphen_in_charset');}); function ozh_hyphen_in_charset( $in ) { - return $in.'-'; + return $in.'-'; } diff --git a/user/plugins/index.html b/user/plugins/index.html index b08be00..cfce37c 100644 --- a/user/plugins/index.html +++ b/user/plugins/index.html @@ -3,6 +3,6 @@ -go.UTC.edu has nothing for you to see here. +YOURLS has nothing for you to see here. - + \ No newline at end of file diff --git a/user/plugins/random-bg/plugin.php b/user/plugins/random-bg/plugin.php index a6768ff..8bba3f4 100644 --- a/user/plugins/random-bg/plugin.php +++ b/user/plugins/random-bg/plugin.php @@ -14,13 +14,13 @@ // Add the inline style yourls_add_action( 'html_head', 'ozh_yourls_randombg' ); function ozh_yourls_randombg() { - $bg = glob( __DIR__.'/img/*png' ); - $url = yourls_plugin_url( __DIR__ ); - $rnd = yourls_plugin_url( $bg[ mt_rand( 0, count( $bg ) - 1 ) ] ); - echo << - body {background:#e3f3ff url($rnd) repeat;} - + body {background:#e3f3ff url($rnd) repeat;} + CSS; } diff --git a/user/plugins/sample-page/plugin.php b/user/plugins/sample-page/plugin.php index 5f5479a..4195345 100644 --- a/user/plugins/sample-page/plugin.php +++ b/user/plugins/sample-page/plugin.php @@ -14,50 +14,50 @@ // Register our plugin admin page yourls_add_action( 'plugins_loaded', 'ozh_yourls_samplepage_add_page' ); function ozh_yourls_samplepage_add_page() { - yourls_register_plugin_page( 'sample_page', 'Sample Admin Page', 'ozh_yourls_samplepage_do_page' ); - // parameters: page slug, page title, and function that will display the page itself + yourls_register_plugin_page( 'sample_page', 'Sample Admin Page', 'ozh_yourls_samplepage_do_page' ); + // parameters: page slug, page title, and function that will display the page itself } // Display admin page function ozh_yourls_samplepage_do_page() { - // Check if a form was submitted - if( isset( $_POST['test_option'] ) ) { - // Check nonce - yourls_verify_nonce( 'sample_page' ); + // Check if a form was submitted + if( isset( $_POST['test_option'] ) ) { + // Check nonce + yourls_verify_nonce( 'sample_page' ); - // Process form - ozh_yourls_samplepage_update_option(); - } + // Process form + ozh_yourls_samplepage_update_option(); + } - // Get value from database - $test_option = yourls_get_option( 'test_option' ); + // Get value from database + $test_option = yourls_get_option( 'test_option' ); - // Create nonce - $nonce = yourls_create_nonce( 'sample_page' ); + // Create nonce + $nonce = yourls_create_nonce( 'sample_page' ); - echo <<Sample Plugin Administration Page -

This plugin stores an integer in the option database

-
- -

-

-
+ echo <<Sample Plugin Administration Page +

This plugin stores an integer in the option database

+
+ +

+

+
HTML; } // Update option in database function ozh_yourls_samplepage_update_option() { - $in = $_POST['test_option']; + $in = $_POST['test_option']; - if( $in ) { - // Validate test_option. ALWAYS validate and sanitize user input. - // Here, we want an integer - $in = intval( $in); + if( $in ) { + // Validate test_option. ALWAYS validate and sanitize user input. + // Here, we want an integer + $in = intval( $in); - // Update value in database - yourls_update_option( 'test_option', $in ); - } + // Update value in database + yourls_update_option( 'test_option', $in ); + } } diff --git a/user/plugins/sample-plugin/plugin.php b/user/plugins/sample-plugin/plugin.php index 40dc1ab..dcfdc4e 100644 --- a/user/plugins/sample-plugin/plugin.php +++ b/user/plugins/sample-plugin/plugin.php @@ -28,7 +28,7 @@ */ function ozh_sample_add_menu() { - echo '
  • Ozh
  • '; + echo '
  • Ozh
  • '; } /* And that's it. Activate the plugin and notice the new menu entry. */ @@ -54,8 +54,8 @@ function ozh_sample_add_menu() { */ function ozh_sample_change_title( $value ) { - $value = $value . ' -- the sample plugin is activated'; - return $value; // a filter *always* has to return a value + $value = $value . ' -- the sample plugin is activated'; + return $value; // a filter *always* has to return a value } /* And that's it. Activate the plugin and notice how the page title changes */ diff --git a/user/plugins/sample-toolbar/plugin.php b/user/plugins/sample-toolbar/plugin.php index d48c7bc..7fde678 100644 --- a/user/plugins/sample-toolbar/plugin.php +++ b/user/plugins/sample-toolbar/plugin.php @@ -19,78 +19,78 @@ // When a redirection to a shorturl is about to happen, register variables yourls_add_action( 'redirect_shorturl', 'ozh_toolbar_add' ); function ozh_toolbar_add( $args ) { - global $ozh_toolbar; - $ozh_toolbar['do'] = true; - $ozh_toolbar['keyword'] = $args[1]; + global $ozh_toolbar; + $ozh_toolbar['do'] = true; + $ozh_toolbar['keyword'] = $args[1]; } // On redirection, check if this is a toolbar and draw it if needed yourls_add_action( 'pre_redirect', 'ozh_toolbar_do' ); function ozh_toolbar_do( $args ) { - global $ozh_toolbar; + global $ozh_toolbar; - // Does this redirection need a toolbar? - if( !$ozh_toolbar['do'] ) { - return; + // Does this redirection need a toolbar? + if( !$ozh_toolbar['do'] ) { + return; } - // Do we have a cookie stating the user doesn't want a toolbar? - if( isset( $_COOKIE['yourls_no_toolbar'] ) && $_COOKIE['yourls_no_toolbar'] == 1 ) { - return; + // Do we have a cookie stating the user doesn't want a toolbar? + if( isset( $_COOKIE['yourls_no_toolbar'] ) && $_COOKIE['yourls_no_toolbar'] == 1 ) { + return; } - // Get URL and page title - $url = $args[0]; - $pagetitle = yourls_get_keyword_title( $ozh_toolbar['keyword'] ); + // Get URL and page title + $url = $args[0]; + $pagetitle = yourls_get_keyword_title( $ozh_toolbar['keyword'] ); - // Update title if it hasn't been stored yet - if( $pagetitle == '' ) { - $pagetitle = yourls_get_remote_title( $url ); - yourls_edit_link_title( $ozh_toolbar['keyword'], $pagetitle ); - } - $_pagetitle = htmlentities( yourls_get_remote_title( $url ) ); + // Update title if it hasn't been stored yet + if( $pagetitle == '' ) { + $pagetitle = yourls_get_remote_title( $url ); + yourls_edit_link_title( $ozh_toolbar['keyword'], $pagetitle ); + } + $_pagetitle = htmlentities( yourls_get_remote_title( $url ) ); - $www = YOURLS_SITE; - $ver = YOURLS_VERSION; + $www = YOURLS_SITE; + $ver = YOURLS_VERSION; $favicon = yourls_get_yourls_favicon_url(false); - // When was the link created (in days) - $diff = abs( time() - strtotime( yourls_get_keyword_timestamp( $ozh_toolbar['keyword'] ) ) ); - $days = floor( $diff / (60*60*24) ); - if( $days == 0 ) { - $created = 'today'; - } else { - $created = $days . ' ' . yourls_n( 'day', 'days', $days ) . ' ago'; - } + // When was the link created (in days) + $diff = abs( time() - strtotime( yourls_get_keyword_timestamp( $ozh_toolbar['keyword'] ) ) ); + $days = floor( $diff / (60*60*24) ); + if( $days == 0 ) { + $created = 'today'; + } else { + $created = $days . ' ' . yourls_n( 'day', 'days', $days ) . ' ago'; + } - // How many hits on the page - $hits = 1 + yourls_get_keyword_clicks( $ozh_toolbar['keyword'] ); - $hits = $hits . ' ' . yourls_n( 'view', 'views', $hits ); + // How many hits on the page + $hits = 1 + yourls_get_keyword_clicks( $ozh_toolbar['keyword'] ); + $hits = $hits . ' ' . yourls_n( 'view', 'views', $hits ); - // Plugin URL (no URL is hardcoded) - $pluginurl = YOURLS_PLUGINURL . '/'.yourls_plugin_basename( __DIR__ ); + // Plugin URL (no URL is hardcoded) + $pluginurl = YOURLS_PLUGINURL . '/'.yourls_plugin_basename( __DIR__ ); - // All set. Draw the toolbar itself. - echo << - $pagetitle — YOURLS - - - - - + $pagetitle — YOURLS + + + + +
    -
    - Short link powered by YOURLS and created $created. $hits. -
    - -
    - close - close -
    +
    + Short link powered by YOURLS and created $created. $hits. +
    + +
    + close + close +
    @@ -99,6 +99,6 @@ function ozh_toolbar_do( $args ) { PAGE; - // Don't forget to die, to interrupt the flow of normal events (ie redirecting to long URL) - die(); + // Don't forget to die, to interrupt the flow of normal events (ie redirecting to long URL) + die(); } diff --git a/user/plugins/sleeky-backend/assets/js/theme.js b/user/plugins/sleeky-backend/assets/js/theme.js index d4b8c78..a067a91 100644 --- a/user/plugins/sleeky-backend/assets/js/theme.js +++ b/user/plugins/sleeky-backend/assets/js/theme.js @@ -136,9 +136,7 @@ $( document ).ready(function() { } else if (/Powered by/.test($(this).text())) { // Update footer var content = $(this).html(); - var i = 77 - var updated_content = "Running on" + content.slice(13, i) + ' & Sleeky' + content.slice(i-0) - $(this).html(updated_content); + var updated_content = `${content.replace(/Powered by.*?(?=<|$)/i, '')}
    Sleeky v 2.6.0`; $(this).html(updated_content); } }); }); diff --git a/user/plugins/sleeky-backend/plugin.php b/user/plugins/sleeky-backend/plugin.php index 1470ebb..93b2d31 100755 --- a/user/plugins/sleeky-backend/plugin.php +++ b/user/plugins/sleeky-backend/plugin.php @@ -3,7 +3,7 @@ Plugin Name: Sleeky Backend Plugin URI: https://sleeky.flynntes.com Description: UI overhaul of the YOURLS backend -Version: 2.4.1 +Version: 2.6.0 Author: Flynn Tesoriero Author URI: https://flynntes.com */ @@ -92,14 +92,14 @@ function sleeky_do_settings_page() { if( isset( $_POST['theme_choice'] ) ) { // Check nonce yourls_verify_nonce( 'sleeky_settings' ); - + // Process form sleeky_settings_update(); } // Get value from database $theme_choice = yourls_get_option( 'theme_choice' ); - + // Create nonce $nonce = yourls_create_nonce( 'sleeky_settings' ); @@ -124,7 +124,7 @@ function sleeky_do_settings_page() { // Update option in database function sleeky_settings_update() { $in = $_POST['theme_choice']; - + if( $in ) { // Validate theme_choice. ALWAYS validate and sanitize user input. // Here, we want an integer @@ -135,7 +135,7 @@ function sleeky_settings_update() { } else { echo "Error"; } - + } } diff --git a/yourls-api.php b/yourls-api.php index 1125a7b..8f54206 100644 --- a/yourls-api.php +++ b/yourls-api.php @@ -17,34 +17,34 @@ // Define standard API actions $api_actions = array( - 'shorturl' => 'yourls_api_action_shorturl', - 'stats' => 'yourls_api_action_stats', - 'db-stats' => 'yourls_api_action_db_stats', - 'url-stats' => 'yourls_api_action_url_stats', - 'expand' => 'yourls_api_action_expand', - 'version' => 'yourls_api_action_version', + 'shorturl' => 'yourls_api_action_shorturl', + 'stats' => 'yourls_api_action_stats', + 'db-stats' => 'yourls_api_action_db_stats', + 'url-stats' => 'yourls_api_action_url_stats', + 'expand' => 'yourls_api_action_expand', + 'version' => 'yourls_api_action_version', ); $api_actions = yourls_apply_filter( 'api_actions', $api_actions ); // Register API actions foreach( (array) $api_actions as $_action => $_callback ) { - yourls_add_filter( 'api_action_' . $_action, $_callback, 99 ); + yourls_add_filter( 'api_action_' . $_action, $_callback, 99 ); } // Try requested API method. Properly registered actions should return an array. $return = yourls_apply_filter( 'api_action_' . $action, false ); if ( false === $return ) { - $return = array( - 'errorCode' => '400', - 'message' => 'Unknown or missing "action" parameter', - 'simple' => 'Unknown or missing "action" parameter', - ); + $return = array( + 'errorCode' => '400', + 'message' => 'Unknown or missing "action" parameter', + 'simple' => 'Unknown or missing "action" parameter', + ); } if( isset( $_REQUEST['callback'] ) ) - $return['callback'] = $_REQUEST['callback']; + $return['callback'] = $_REQUEST['callback']; elseif ( isset( $_REQUEST['jsonp'] ) ) - $return['callback'] = $_REQUEST['jsonp']; + $return['callback'] = $_REQUEST['jsonp']; $format = ( isset( $_REQUEST['format'] ) ? $_REQUEST['format'] : 'xml' ); diff --git a/yourls-go.php b/yourls-go.php index 51968dd..fd26075 100644 --- a/yourls-go.php +++ b/yourls-go.php @@ -4,8 +4,8 @@ // Variables should be defined in yourls-loader.php if( !isset( $keyword ) ) { - yourls_do_action( 'redirect_no_keyword' ); - yourls_redirect( YOURLS_SITE, 301 ); + yourls_do_action( 'redirect_no_keyword' ); + yourls_redirect( YOURLS_SITE, 301 ); } $keyword = yourls_sanitize_keyword($keyword); diff --git a/yourls-infos.php b/yourls-infos.php index 2cba4d2..a90c860 100644 --- a/yourls-infos.php +++ b/yourls-infos.php @@ -6,9 +6,9 @@ // Variables should be defined in yourls-loader.php if ( !isset( $keyword ) ) { - yourls_do_action( 'infos_no_keyword' ); - yourls_redirect( YOURLS_SITE, 302 ); - exit; + yourls_do_action( 'infos_no_keyword' ); + yourls_redirect( YOURLS_SITE, 302 ); + exit; } // Get basic infos for this shortened URL @@ -20,13 +20,13 @@ // Update title if it hasn't been stored yet if( $title == '' ) { - $title = yourls_get_remote_title( $longurl ); - yourls_edit_link_title( $keyword, $title ); + $title = yourls_get_remote_title( $longurl ); + yourls_edit_link_title( $keyword, $title ); } if ( $longurl === false ) { - yourls_do_action( 'infos_keyword_not_found' ); - yourls_redirect( YOURLS_SITE, 302 ); + yourls_do_action( 'infos_keyword_not_found' ); + yourls_redirect( YOURLS_SITE, 302 ); exit; } @@ -35,180 +35,184 @@ if( yourls_do_log_redirect() ) { - $table = YOURLS_DB_TABLE_LOG; - $referrers = array(); - $direct = $notdirect = 0; - $countries = array(); - $dates = array(); - $list_of_days = array(); - $list_of_months = array(); - $list_of_years = array(); - $last_24h = array(); - - if( yourls_allow_duplicate_longurls() ) - $keyword_list = yourls_get_longurl_keywords( $longurl ); - // Define keyword query range : either a single keyword or a list of keywords - if( $aggregate ) { - $keyword_range = 'IN ( :list )'; + $table = YOURLS_DB_TABLE_LOG; + $referrers = array(); + $direct = $notdirect = 0; + $countries = array(); + $dates = array(); + $list_of_days = array(); + $list_of_months = array(); + $list_of_years = array(); + $last_24h = array(); + + if( yourls_allow_duplicate_longurls() ) + $keyword_list = yourls_get_longurl_keywords( $longurl ); + // Define keyword query range : either a single keyword or a list of keywords + if( $aggregate ) { + $keyword_range = 'IN ( :list )'; $keyword_binds = array('list' => $keyword_list); - } else { - $keyword_range = '= :keyword'; + } else { + $keyword_range = '= :keyword'; $keyword_binds = array('keyword' => $keyword); - } + } - // *** Referrers *** + // *** Referrers *** $sql = "SELECT `referrer`, COUNT(*) AS `count` FROM `$table` WHERE `shorturl` $keyword_range GROUP BY `referrer`;"; $sql = yourls_apply_filter('stat_query_referrer', $sql); - $rows = $ydb->fetchObjects($sql, $keyword_binds); - - // Loop through all results and build list of referrers, countries and hits per day - foreach( (array)$rows as $row ) { - if ( $row->referrer == 'direct' ) { - $direct = $row->count; - continue; - } - - $host = yourls_get_domain( $row->referrer ); - if( !array_key_exists( $host, $referrers ) ) - $referrers[$host] = array( ); - if( !array_key_exists( $row->referrer, $referrers[$host] ) ) { - $referrers[$host][$row->referrer] = $row->count; - $notdirect += $row->count; - } else { - $referrers[$host][$row->referrer] += $row->count; - $notdirect += $row->count; - } - } - - // Sort referrers. $referrer_sort is a array of most frequent domains - arsort( $referrers ); - $referrer_sort = array(); - $number_of_sites = count( array_keys( $referrers ) ); - foreach( $referrers as $site => $urls ) { - if( count($urls) > 1 || $number_of_sites == 1 ) - $referrer_sort[$site] = array_sum( $urls ); - } - arsort($referrer_sort); - - - // *** Countries *** - $sql = "SELECT `country_code`, COUNT(*) AS `count` FROM `$table` WHERE `shorturl` $keyword_range GROUP BY `country_code`;"; + $rows = $ydb->fetchObjects($sql, $keyword_binds); + + // Loop through all results and build list of referrers, countries and hits per day + foreach( (array)$rows as $row ) { + if ( $row->referrer == 'direct' ) { + $direct = $row->count; + continue; + } + + $host = yourls_get_domain( $row->referrer ); + if( !array_key_exists( $host, $referrers ) ) + $referrers[$host] = array( ); + if( !array_key_exists( $row->referrer, $referrers[$host] ) ) { + $referrers[$host][$row->referrer] = $row->count; + $notdirect += $row->count; + } else { + $referrers[$host][$row->referrer] += $row->count; + $notdirect += $row->count; + } + } + + // Sort referrers. $referrer_sort is a array of most frequent domains + arsort( $referrers ); + $referrer_sort = array(); + $number_of_sites = count( array_keys( $referrers ) ); + foreach( $referrers as $site => $urls ) { + if( count($urls) > 1 || $number_of_sites == 1 ) + $referrer_sort[$site] = array_sum( $urls ); + } + arsort($referrer_sort); + + + // *** Countries *** + $sql = "SELECT `country_code`, COUNT(*) AS `count` FROM `$table` WHERE `shorturl` $keyword_range GROUP BY `country_code`;"; $sql = yourls_apply_filter('stat_query_country', $sql); - $rows = $ydb->fetchObjects($sql, $keyword_binds); - - // Loop through all results and build list of countries and hits - foreach( (array)$rows as $row ) { - if ("$row->country_code") - $countries["$row->country_code"] = $row->count; - } - - // Sort countries, most frequent first - if ( $countries ) - arsort( $countries ); - - - // *** Dates : array of $dates[$year][$month][$day] = number of clicks *** - $sql = "SELECT - DATE_FORMAT(`click_time`, '%Y') AS `year`, - DATE_FORMAT(`click_time`, '%m') AS `month`, - DATE_FORMAT(`click_time`, '%d') AS `day`, - COUNT(*) AS `count` - FROM `$table` - WHERE `shorturl` $keyword_range - GROUP BY `year`, `month`, `day`;"; + $rows = $ydb->fetchObjects($sql, $keyword_binds); + + // Loop through all results and build list of countries and hits + foreach( (array)$rows as $row ) { + if ("$row->country_code") + $countries["$row->country_code"] = $row->count; + } + + // Sort countries, most frequent first + if ( $countries ) + arsort( $countries ); + + + // *** Dates : array of $dates[$year][$month][$day] = number of clicks *** + $sql = "SELECT + DATE_FORMAT(`click_time`, '%Y') AS `year`, + DATE_FORMAT(`click_time`, '%m') AS `month`, + DATE_FORMAT(`click_time`, '%d') AS `day`, + COUNT(*) AS `count` + FROM `$table` + WHERE `shorturl` $keyword_range + GROUP BY `year`, `month`, `day`;"; $sql = yourls_apply_filter('stat_query_dates', $sql); - $rows = $ydb->fetchObjects($sql, $keyword_binds); - - // Loop through all results and fill blanks - foreach( (array)$rows as $row ) { - if( !array_key_exists($row->year, $dates ) ) - $dates[$row->year] = array(); - if( !array_key_exists( $row->month, $dates[$row->year] ) ) - $dates[$row->year][$row->month] = array(); - if( !array_key_exists( $row->day, $dates[$row->year][$row->month] ) ) - $dates[$row->year][$row->month][$row->day] = $row->count; - else - $dates[$row->year][$row->month][$row->day] += $row->count; - } - - // Sort dates, chronologically from [2007][12][24] to [2009][02][19] - ksort( $dates ); - foreach( $dates as $year=>$months ) { - ksort( $dates[$year] ); - foreach( $months as $month=>$day ) { - ksort( $dates[$year][$month] ); - } - } - - // Get $list_of_days, $list_of_months, $list_of_years - reset( $dates ); - if( $dates ) { + $rows = $ydb->fetchObjects($sql, $keyword_binds); + + // Loop through all results and fill blanks + foreach( (array)$rows as $row ) { + if( !array_key_exists($row->year, $dates ) ) + $dates[$row->year] = array(); + if( !array_key_exists( $row->month, $dates[$row->year] ) ) + $dates[$row->year][$row->month] = array(); + if( !array_key_exists( $row->day, $dates[$row->year][$row->month] ) ) + $dates[$row->year][$row->month][$row->day] = $row->count; + else + $dates[$row->year][$row->month][$row->day] += $row->count; + } + + // Sort dates, chronologically from [2007][12][24] to [2009][02][19] + ksort( $dates ); + foreach( $dates as $year=>$months ) { + ksort( $dates[$year] ); + foreach( $months as $month=>$day ) { + ksort( $dates[$year][$month] ); + } + } + + // Get $list_of_days, $list_of_months, $list_of_years + reset( $dates ); + if( $dates ) { $_lists = yourls_build_list_of_days( $dates ); $list_of_days = $_lists['list_of_days']; $list_of_months = $_lists['list_of_months']; $list_of_years = $_lists['list_of_years']; unset($_lists); - } + } - $offset = yourls_get_time_offset(); + $offset = yourls_get_time_offset(); - // *** Last 24 hours : array of $last_24h[ $hour ] = number of click *** - $sql = "SELECT - DATE_FORMAT(DATE_ADD(`click_time`, INTERVAL " . $offset . " HOUR), '%H %p') AS `time`, - COUNT(*) AS `count` - FROM `$table` - WHERE `shorturl` $keyword_range AND DATE_ADD(`click_time`, INTERVAL " . $offset . " HOUR) > (DATE_ADD(CURRENT_TIMESTAMP, INTERVAL " . $offset . " HOUR) - INTERVAL 1 DAY) - GROUP BY `time`;"; + // *** Last 24 hours : array of $last_24h[ $hour ] = number of click *** + $sql = "SELECT + DATE_FORMAT(DATE_ADD(`click_time`, INTERVAL " . $offset . " HOUR), '%H %p') AS `time`, + COUNT(*) AS `count` + FROM `$table` + WHERE `shorturl` $keyword_range AND DATE_ADD(`click_time`, INTERVAL " . $offset . " HOUR) > (DATE_ADD(CURRENT_TIMESTAMP, INTERVAL " . $offset . " HOUR) - INTERVAL 1 DAY) + GROUP BY `time`;"; $sql = yourls_apply_filter('stat_query_last24h', $sql); - $rows = $ydb->fetchObjects($sql, $keyword_binds); - - $_last_24h = array(); - foreach( (array)$rows as $row ) { - if ( isset( $row->time ) ) - $_last_24h[ "$row->time" ] = $row->count; - } - - $now = intval( date('U') ); - for ($i = 23; $i >= 0; $i--) { - $h = date('H A', ($now - ($i * 60 * 60) + ($offset * 60 * 60)) ); - // If the $last_24h doesn't have all the hours, insert missing hours with value 0 - $last_24h[ $h ] = array_key_exists( $h, $_last_24h ) ? $_last_24h[ $h ] : 0 ; - } - unset( $_last_24h ); - - // *** Queries all done, phew *** - - // Filter all this junk if applicable. Be warned, some are possibly huge datasets. - $referrers = yourls_apply_filter( 'pre_yourls_info_referrers', $referrers ); - $referrer_sort = yourls_apply_filter( 'pre_yourls_info_referrer_sort', $referrer_sort ); - $direct = yourls_apply_filter( 'pre_yourls_info_direct', $direct ); - $notdirect = yourls_apply_filter( 'pre_yourls_info_notdirect', $notdirect ); - $dates = yourls_apply_filter( 'pre_yourls_info_dates', $dates ); - $list_of_days = yourls_apply_filter( 'pre_yourls_info_list_of_days', $list_of_days ); - $list_of_months = yourls_apply_filter( 'pre_yourls_info_list_of_months', $list_of_months ); - $list_of_years = yourls_apply_filter( 'pre_yourls_info_list_of_years', $list_of_years ); - $last_24h = yourls_apply_filter( 'pre_yourls_info_last_24h', $last_24h ); - $countries = yourls_apply_filter( 'pre_yourls_info_countries', $countries ); - - // I can haz debug data - /** - echo "
    ";
    -	echo "referrers: "; print_r( $referrers );
    -	echo "referrer sort: "; print_r( $referrer_sort );
    -	echo "direct: $direct\n";
    -	echo "notdirect: $notdirect\n";
    -	echo "dates: "; print_r( $dates );
    -	echo "list of days: "; print_r( $list_of_days );
    -	echo "list_of_months: "; print_r( $list_of_months );
    -	echo "list_of_years: "; print_r( $list_of_years );
    -	echo "last_24h: "; print_r( $last_24h );
    -	echo "countries: "; print_r( $countries );
    -	die();
    -	**/
    +    $rows = $ydb->fetchObjects($sql, $keyword_binds);
    +
    +    $_last_24h = array();
    +    foreach( (array)$rows as $row ) {
    +        if ( isset( $row->time ) )
    +            $_last_24h[ "$row->time" ] = $row->count;
    +    }
    +
    +    $now = intval( date('U') );
    +    for ($i = 23; $i >= 0; $i--) {
    +        $h = date('H A', ($now - ($i * 60 * 60) + ($offset * 60 * 60)) );
    +        // If the $last_24h doesn't have all the hours, insert missing hours with value 0
    +        $last_24h[ $h ] = array_key_exists( $h, $_last_24h ) ? $_last_24h[ $h ] : 0 ;
    +    }
    +    unset( $_last_24h );
    +
    +    // *** Queries all done, phew ***
    +
    +    // Filter all this junk if applicable. Be warned, some are possibly huge datasets.
    +    $referrers      = yourls_apply_filter( 'pre_yourls_info_referrers', $referrers );
    +    $referrer_sort  = yourls_apply_filter( 'pre_yourls_info_referrer_sort', $referrer_sort );
    +    $direct         = yourls_apply_filter( 'pre_yourls_info_direct', $direct );
    +    $notdirect      = yourls_apply_filter( 'pre_yourls_info_notdirect', $notdirect );
    +    $dates          = yourls_apply_filter( 'pre_yourls_info_dates', $dates );
    +    $list_of_days   = yourls_apply_filter( 'pre_yourls_info_list_of_days', $list_of_days );
    +    $list_of_months = yourls_apply_filter( 'pre_yourls_info_list_of_months', $list_of_months );
    +    $list_of_years  = yourls_apply_filter( 'pre_yourls_info_list_of_years', $list_of_years );
    +    $last_24h       = yourls_apply_filter( 'pre_yourls_info_last_24h', $last_24h );
    +    $countries      = yourls_apply_filter( 'pre_yourls_info_countries', $countries );
    +
    +    // I can haz debug data
    +    /**
    +    echo "
    ";
    +    echo "referrers: "; print_r( $referrers );
    +    echo "referrer sort: "; print_r( $referrer_sort );
    +    echo "direct: $direct\n";
    +    echo "notdirect: $notdirect\n";
    +    echo "dates: "; print_r( $dates );
    +    echo "list of days: "; print_r( $list_of_days );
    +    echo "list_of_months: "; print_r( $list_of_months );
    +    echo "list_of_years: "; print_r( $list_of_years );
    +    echo "last_24h: "; print_r( $last_24h );
    +    echo "countries: "; print_r( $countries );
    +    die();
    +    **/
     
     }
     
    +// Whether to show referrers on the statistics page
    +// Default: show only on private installs; hide on public installs to prevent referrer spam (filterable)
    +$show_referrers = yourls_apply_filter( 'statistics_show_referrers', yourls_is_private() );
    +
     yourls_html_head( 'infos', yourls_s( 'Statistics for %s', YOURLS_SITE.'/'.$keyword ) );
     yourls_html_logo();
     yourls_html_menu();
    @@ -218,338 +222,341 @@
     
     

    : 1 ) - echo ' '; + yourls_html_link( yourls_link($keyword) ); + if( isset( $keyword_list ) && count( $keyword_list ) > 1 ) + echo ' '; } ?>

    :

    -
    -
      - -
    • -
    • -
    • - -
    • -
    -
    +
    +
      + +
    • +
    • + +
    • + + +
    • +
    +
    -
    -

    - - - - - - yourls__( 'Last 24 hours' ), - '7' => yourls__( 'Last 7 days' ), - '30' => yourls__( 'Last 30 days' ), - 'all'=> yourls__( 'All time' ), - ); - - // Which graph to generate ? - $do_all = $do_30 = $do_7 = $do_24 = false; - $hits_all = array_sum( $list_of_days ); - $hits_30 = array_sum( array_slice( $list_of_days, -30 ) ); - $hits_7 = array_sum( array_slice( $list_of_days, -7 ) ); - $hits_24 = array_sum( $last_24h ); - if( $hits_all > 0 ) - $do_all = true; // graph for all days range - if( $hits_30 > 0 && count( array_slice( $list_of_days, -30 ) ) == 30 ) - $do_30 = true; // graph for last 30 days - if( $hits_7 > 0 && count( array_slice( $list_of_days, -7 ) ) == 7 ) - $do_7 = true; // graph for last 7 days - if( $hits_24 > 0 ) - $do_24 = true; // graph for last 24 hours - - // Which graph to display ? - $display_all = $display_30 = $display_7 = $display_24 = false; - if( $do_24 ) { - $display_24 = true; - } elseif ( $do_7 ) { - $display_7 = true; - } elseif ( $do_30 ) { - $display_30 = true; - } elseif ( $do_all ) { - $display_all = true; - } - ?> - - - - - - - -
    - - $graphtitle ) { - if( ${'do_'.$graph} == true ) { - $display = ( ${'display_'.$graph} === true ? 'display:block' : 'display:none' ); - echo "
    "; - echo '

    ' . yourls_s( 'Number of hits : %s' , $graphtitle ) . '

    '; - switch( $graph ) { - case '24': - yourls_stats_line( $last_24h, "stat_line_$graph" ); - break; - - case '7': - case '30': - $slice = array_slice( $list_of_days, intval( $graph ) * -1 ); - yourls_stats_line( $slice, "stat_line_$graph" ); - unset( $slice ); - break; - - case 'all': - yourls_stats_line( $list_of_days, "stat_line_$graph" ); - break; - } - echo "
    \n"; - } - } ?> - -
    -

    - -

    -
    -
      - $graphtitle ) { - if ( ${'do_'.$graph} ) { - $link = "$graphtitle"; - } else { - $link = $graphtitle; - } - $stat = ''; - if( ${'do_'.$graph} ) { - switch( $graph ) { - case '7': - case '30': - $stat = yourls_s( '%s per day', round( ( ${'hits_'.$graph} / intval( $graph ) ) * 100 ) / 100 ); - break; - case '24': - $stat = yourls_s( '%s per hour', round( ( ${'hits_'.$graph} / 24 ) * 100 ) / 100 ); - break; - case 'all': - if( $ago > 0 ) - $stat = yourls_s( '%s per day', round( ( ${'hits_'.$graph} / $ago ) * 100 ) / 100 ); - } - } - $hits = sprintf( yourls_n( '%s hit', '%s hits', ${'hits_'.$graph} ), ${'hits_'.$graph} ); - echo "
    • $link $hits $stat
    • \n"; - } - ?> -
    -
    - -

    - -

    %1$s hit on %2$s', '%1$s hits on %2$s', $best['max'] ), $best['max'], yourls_date_i18n( yourls_get_date_format("F j, Y"), strtotime( $best['day'] ) ) ); ?>. -

    - - -
    - - - - ' . yourls__( 'No traffic yet. Get some clicks first!' ) . '

    '; - } ?> -
    - - -
    -

    - - - - - - - - - - -
    -

    - -

    - - -
    -

    - -
    - - - - ' . yourls__( 'No country data.' ) . '

    '; - } ?> -
    - - -
    -

    - - - - - - - - - - - -
    -

    - 1 ) - $referrer_sort[ yourls__( 'Others' ) ] = count( $referrers ); - yourls_stats_pie( $referrer_sort, 5, '440x220', 'stat_tab_source_ref' ); - unset( $referrer_sort[yourls__('Others')] ); - ?> -

    -
      - $count ) { - $i++; - $favicon = yourls_get_favicon_url( $site ); - echo "
    • $site: $count " . yourls__( '(details)' ) . "
    • \n"; - echo "\n"; - unset( $referrers[$site] ); - } - // Any referrer left? Group in "various" - if ( $referrers ) { - echo "
    • " . yourls__( 'Various:' ) . " ". count( $referrers ). " " . yourls__( '(details)' ) . "
    • \n"; - echo "\n"; - } - ?> - -
    - -
    -

    - $direct, yourls__( 'Referrers' ) => $notdirect ), 5, '440x220', 'stat_tab_source_direct' ); - ?> -

    %s hit', '%s hits', $direct ), $direct ); ?>

    -

    %s hit', '%s hits', $notdirect ), $notdirect ); ?>

    - -
    - - - - ' . yourls__( 'No referrer data.' ) . '

    '; - } ?> - -
    +
    +

    + + + + + + yourls__( 'Last 24 hours' ), + '7' => yourls__( 'Last 7 days' ), + '30' => yourls__( 'Last 30 days' ), + 'all'=> yourls__( 'All time' ), + ); + + // Which graph to generate ? + $do_all = $do_30 = $do_7 = $do_24 = false; + $hits_all = array_sum( $list_of_days ); + $hits_30 = array_sum( array_slice( $list_of_days, -30 ) ); + $hits_7 = array_sum( array_slice( $list_of_days, -7 ) ); + $hits_24 = array_sum( $last_24h ); + if( $hits_all > 0 ) + $do_all = true; // graph for all days range + if( $hits_30 > 0 && count( array_slice( $list_of_days, -30 ) ) == 30 ) + $do_30 = true; // graph for last 30 days + if( $hits_7 > 0 && count( array_slice( $list_of_days, -7 ) ) == 7 ) + $do_7 = true; // graph for last 7 days + if( $hits_24 > 0 ) + $do_24 = true; // graph for last 24 hours + + // Which graph to display ? + $display_all = $display_30 = $display_7 = $display_24 = false; + if( $do_24 ) { + $display_24 = true; + } elseif ( $do_7 ) { + $display_7 = true; + } elseif ( $do_30 ) { + $display_30 = true; + } elseif ( $do_all ) { + $display_all = true; + } + ?> + + + + + + + +
    + + $graphtitle ) { + if( ${'do_'.$graph} == true ) { + $display = ( ${'display_'.$graph} === true ? 'display:block' : 'display:none' ); + echo "
    "; + echo '

    ' . yourls_s( 'Number of hits : %s' , $graphtitle ) . '

    '; + switch( $graph ) { + case '24': + yourls_stats_line( $last_24h, "stat_line_$graph" ); + break; + + case '7': + case '30': + $slice = array_slice( $list_of_days, intval( $graph ) * -1 ); + yourls_stats_line( $slice, "stat_line_$graph" ); + unset( $slice ); + break; + + case 'all': + yourls_stats_line( $list_of_days, "stat_line_$graph" ); + break; + } + echo "
    \n"; + } + } ?> + +
    +

    + +

    +
    +
      + $graphtitle ) { + if ( ${'do_'.$graph} ) { + $link = "$graphtitle"; + } else { + $link = $graphtitle; + } + $stat = ''; + if( ${'do_'.$graph} ) { + switch( $graph ) { + case '7': + case '30': + $stat = yourls_s( '%s per day', round( ( ${'hits_'.$graph} / intval( $graph ) ) * 100 ) / 100 ); + break; + case '24': + $stat = yourls_s( '%s per hour', round( ( ${'hits_'.$graph} / 24 ) * 100 ) / 100 ); + break; + case 'all': + if( $ago > 0 ) + $stat = yourls_s( '%s per day', round( ( ${'hits_'.$graph} / $ago ) * 100 ) / 100 ); + } + } + $hits = sprintf( yourls_n( '%s hit', '%s hits', ${'hits_'.$graph} ), ${'hits_'.$graph} ); + echo "
    • $link $hits $stat
    • \n"; + } + ?> +
    +
    + +

    + +

    %1$s hit on %2$s', '%1$s hits on %2$s', $best['max'] ), $best['max'], yourls_date_i18n( yourls_get_date_format("F j, Y"), strtotime( $best['day'] ) ) ); ?>. +

    + + +
    + + + + ' . yourls__( 'No traffic yet. Get some clicks first!' ) . '

    '; + } ?> +
    + + +
    +

    + + + + + + + + + + +
    +

    + +

    + + +
    +

    + +
    + + + + ' . yourls__( 'No country data.' ) . '

    '; + } ?> +
    + + +
    +

    + + + + + + + + + + + +
    +

    + 1 ) + $referrer_sort[ yourls__( 'Others' ) ] = count( $referrers ); + yourls_stats_pie( $referrer_sort, 5, '440x220', 'stat_tab_source_ref' ); + unset( $referrer_sort[yourls__('Others')] ); + ?> +

    +
      + $count ) { + $i++; + $favicon = yourls_get_favicon_url( $site ); + echo "
    • $site: $count " . yourls__( '(details)' ) . "
    • \n"; + echo "\n"; + unset( $referrers[$site] ); + } + // Any referrer left? Group in "various" + if ( $referrers ) { + echo "
    • " . yourls__( 'Various:' ) . " ". count( $referrers ). " " . yourls__( '(details)' ) . "
    • \n"; + echo "\n"; + } + ?> + +
    + +
    +

    + $direct, yourls__( 'Referrers' ) => $notdirect ), 5, '440x220', 'stat_tab_source_direct' ); + ?> +

    %s hit', '%s hits', $direct ), $direct ); ?>

    +

    %s hit', '%s hits', $notdirect ), $notdirect ); ?>

    + +
    + + + + ' . yourls__( 'No referrer data.' ) . '

    '; + } ?> + +
    + -
    -

    +
    +

    - ' . yourls__( 'Short link' ) . '', '

    ' . yourls__( 'Quick Share' ) . '

    '); ?> + ' . yourls__( 'Short link' ) . '', '

    ' . yourls__( 'Quick Share' ) . '

    '); ?> -
    +
    diff --git a/yourls-loader.php b/yourls-loader.php index cd9d2db..12fb67b 100644 --- a/yourls-loader.php +++ b/yourls-loader.php @@ -1,17 +1,17 @@