diff --git a/includes/class-mysql.php b/includes/class-mysql.php index d2ca295..c25c183 100644 --- a/includes/class-mysql.php +++ b/includes/class-mysql.php @@ -4,6 +4,7 @@ * Connect to DB * * @since 1.0 + * @return \YOURLS\Database\YDB */ function yourls_db_connect() { global $ydb; @@ -101,6 +102,7 @@ function yourls_get_db() { * * @since 1.7.10 * @param mixed $db Either a \YOURLS\Database\YDB instance, or anything. If null, the function will unset $ydb + * @return void */ function yourls_set_db($db) { global $ydb; diff --git a/includes/functions-api.php b/includes/functions-api.php index baf3cb1..45395ac 100644 --- a/includes/functions-api.php +++ b/includes/functions-api.php @@ -163,8 +163,12 @@ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) /** * Return array for API stat requests * + * @param string $filter either "top", "bottom" , "rand" or "last" + * @param int $limit maximum number of links to return + * @param int $start offset + * @return array */ -function yourls_api_stats( $filter = 'top', $limit = 10, $start = 0 ) { +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'; @@ -174,6 +178,7 @@ function yourls_api_stats( $filter = 'top', $limit = 10, $start = 0 ) { /** * Return array for counts of shorturls and clicks * + * @return array */ function yourls_api_db_stats() { $return = array( @@ -189,6 +194,8 @@ function yourls_api_db_stats() { /** * Return array for API stat requests * + * @param string $shorturl Short URL to check + * @return array */ function yourls_api_url_stats( $shorturl ) { $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' @@ -202,6 +209,8 @@ function yourls_api_url_stats( $shorturl ) { /** * Expand short url to long url * + * @param string $shorturl Short URL to expand + * @return array */ function yourls_api_expand( $shorturl ) { $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' diff --git a/includes/functions-auth.php b/includes/functions-auth.php index 52a677a..2fd76d9 100644 --- a/includes/functions-auth.php +++ b/includes/functions-auth.php @@ -7,6 +7,7 @@ /** * Show login form if required * + * @return void */ function yourls_maybe_require_auth() { if( yourls_is_private() ) { @@ -37,7 +38,7 @@ function yourls_is_valid_user() { // 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( null ); + yourls_store_cookie( '' ); return yourls__( 'Logged out successfully' ); } @@ -124,6 +125,7 @@ function yourls_is_valid_user() { /** * Check auth against list of login=>pwd. Sets user if applicable, returns bool * + * @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; @@ -143,8 +145,11 @@ function yourls_check_username_password() { /** * Check a submitted password sent in plain text against stored password which can be a salted hash * + * @param string $user + * @param string $submitted_password + * @return bool */ -function yourls_check_password_hash( $user, $submitted_password ) { +function yourls_check_password_hash($user, $submitted_password ) { global $yourls_user_passwords; if( !isset( $yourls_user_passwords[ $user ] ) ) @@ -173,11 +178,15 @@ 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 ) ) - return 'cannot read file'; // not sure that can actually happen... + 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'; + } $yourls_user_passwords = []; // Include file to read value of $yourls_user_passwords @@ -188,11 +197,16 @@ function yourls_hash_passwords_now( $config_file ) { error_reporting( $errlevel ); $configdata = file_get_contents( $config_file ); - if( $configdata == false ) - return 'could not read 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 ) { + // 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 ); @@ -211,8 +225,10 @@ function yourls_hash_passwords_now( $config_file ) { } } - if( $to_hash == 0 ) - return 0; // There was no password to encrypt + 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 ) { @@ -320,6 +336,7 @@ function yourls_has_phpass_password( $user ) { /** * Check auth against encrypted COOKIE data. Sets user if applicable, returns bool * + * @return bool true if authenticated, false otherwise */ function yourls_check_auth_cookie() { global $yourls_user_passwords; @@ -406,6 +423,8 @@ function yourls_check_signature() { /** * Generate secret signature hash * + * @param false|string $username Username to generate signature for, or false to use current user + * @return string Signature */ function yourls_auth_signature( $username = false ) { if( !$username && defined('YOURLS_USER') ) { @@ -417,6 +436,8 @@ function yourls_auth_signature( $username = false ) { /** * Check if timestamp is not too old * + * @param int $time Timestamp to check + * @return bool True if timestamp is valid */ function yourls_check_timestamp( $time ) { $now = time(); @@ -427,9 +448,10 @@ function yourls_check_timestamp( $time ) { /** * Store new cookie. No $user will delete the cookie. * - * @param mixed $user String, user login, or null to delete cookie + * @param string $user User login, or empty string to delete cookie + * @return void */ -function yourls_store_cookie( $user = null ) { +function yourls_store_cookie( $user = '' ) { // No user will delete the cookie with a cookie time from the past if( !$user ) { @@ -463,7 +485,6 @@ function yourls_store_cookie( $user = null ) { * * @see https://github.com/GoogleChromeLabs/samesite-examples/blob/master/php.md * @see https://stackoverflow.com/a/59654832/36850 - * @see https://3v4l.org/uKEtH for compat tests * @see https://www.php.net/manual/en/function.setcookie.php * * @since 1.7.7 @@ -479,24 +500,21 @@ function yourls_store_cookie( $user = null ) { function yourls_setcookie($name, $value, $expire, $path, $domain, $secure, $httponly) { $samesite = yourls_apply_filter('setcookie_samesite', 'Lax' ); - if (PHP_VERSION_ID < 70300) { - return(setcookie($name, $value, $expire, "$path; samesite=$samesite", $domain, $secure, $httponly)); - } - else { - return(setcookie($name, $value, array( - 'expires' => $expire, - 'path' => $path, - 'domain' => $domain, - 'samesite' => $samesite, - 'secure' => $secure, - 'httponly' => $httponly, - ))); - } + return(setcookie($name, $value, array( + 'expires' => $expire, + 'path' => $path, + 'domain' => $domain, + 'samesite' => $samesite, + 'secure' => $secure, + 'httponly' => $httponly, + ))); } /** * Set user name * + * @param string $user Username + * @return void */ function yourls_set_user( $user ) { if( !defined( 'YOURLS_USER' ) ) @@ -554,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 ); } /** @@ -562,6 +580,7 @@ function yourls_cookie_value( $user ) { * * Actually, this returns a float: ceil rounds up a value but is of type float, see https://www.php.net/ceil * + * @return float */ function yourls_tick() { return ceil( time() / yourls_get_nonce_life() ); @@ -598,8 +617,11 @@ function yourls_hmac_algo() { /** * Create a time limited, action limited and user limited token * + * @param string $action Action to create nonce for + * @param false|string $user Optional user string, false for current user + * @return string Nonce token */ -function yourls_create_nonce( $action, $user = false ) { +function yourls_create_nonce($action, $user = false ) { if( false === $user ) { $user = defined('YOURLS_USER') ? YOURLS_USER : '-1'; } @@ -610,10 +632,15 @@ function yourls_create_nonce( $action, $user = false ) { } /** - * Create a nonce field for inclusion into a form + * Echoes or returns a nonce field for inclusion into a form * + * @param string $action Action to create nonce for + * @param string $name Optional name of nonce field -- defaults to 'nonce' + * @param false|string $user Optional user string, false if unspecified + * @param bool $echo True to echo, false to return nonce field + * @return string Nonce field */ -function yourls_nonce_field( $action, $name = 'nonce', $user = false, $echo = true ) { +function yourls_nonce_field($action, $name = 'nonce', $user = false, $echo = true ) { $field = ''; if( $echo ) echo $field."\n"; @@ -623,8 +650,13 @@ function yourls_nonce_field( $action, $name = 'nonce', $user = false, $echo = tr /** * Add a nonce to a URL. If URL omitted, adds nonce to current URL * + * @param string $action Action to create nonce for + * @param string $url Optional URL to add nonce to -- defaults to current URL + * @param string $name Optional name of nonce field -- defaults to 'nonce' + * @param false|string $user Optional user string, false if unspecified + * @return string URL with nonce added */ -function yourls_nonce_url( $action, $url = false, $name = 'nonce', $user = false ) { +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 ); } @@ -632,11 +664,16 @@ function yourls_nonce_url( $action, $url = false, $name = 'nonce', $user = false /** * Check validity of a nonce (ie time span, user and action match). * - * Returns true if valid, dies otherwise (yourls_die() or die($return) if defined) - * if $nonce is false or unspecified, it will use $_REQUEST['nonce'] + * Returns true if valid, dies otherwise (yourls_die() or die($return) if defined). + * If $nonce is false or unspecified, it will use $_REQUEST['nonce'] * + * @param string $action + * @param false|string $nonce Optional, string: nonce value, or false to use $_REQUEST['nonce'] + * @param false|string $user Optional, string user, false for current user + * @param string $return Optional, string: message to die with if nonce is invalid + * @return bool|void True if valid, dies otherwise */ -function yourls_verify_nonce( $action, $nonce = false, $user = false, $return = '' ) { +function yourls_verify_nonce($action, $nonce = false, $user = false, $return = '' ) { // Get user if( false === $user ) { $user = defined('YOURLS_USER') ? YOURLS_USER : '-1'; @@ -668,7 +705,7 @@ function yourls_verify_nonce( $action, $nonce = false, $user = false, $return = * Check if YOURLS_USER comes from environment variables * * @since 1.8.2 - * @return bool true if YOURLS_USER and YOURLS_PASSWORD are defined as environment variables + * @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')); diff --git a/includes/functions-debug.php b/includes/functions-debug.php index 85b4f0b..1aeee65 100644 --- a/includes/functions-debug.php +++ b/includes/functions-debug.php @@ -34,6 +34,7 @@ function yourls_get_debug_log() { /** * Get number of SQL queries performed * + * @return int */ function yourls_get_num_queries() { return yourls_apply_filter( 'get_num_queries', yourls_get_db()->get_num_queries() ); @@ -44,6 +45,7 @@ function yourls_get_num_queries() { * * @since 1.7.3 * @param bool $bool Debug on or off + * @return void */ function yourls_debug_mode( $bool ) { // log queries if true diff --git a/includes/functions-deprecated.php b/includes/functions-deprecated.php index a481f77..bbc4f3c 100644 --- a/includes/functions-deprecated.php +++ b/includes/functions-deprecated.php @@ -5,10 +5,61 @@ * * Note to devs: when deprecating a function, move it here. Then check all the places * in core that might be using it, including core plugins. + * + * Usage : yourls_deprecated_function( 'function_name', 'version', 'replacement' ); + * Output: "{function_name} is deprecated since version {version}! Use {replacement} instead." + * + * Usage : yourls_deprecated_function( 'function_name', 'version' ); + * Output: "{function_name} is deprecated since version {version} with no alternative available." + * + * @see yourls_deprecated_function() */ // @codeCoverageIgnoreStart +/** + * Return current admin page, or null if not an admin page. Was not used anywhere. + * + * @return mixed string if admin page, null if not an admin page + * @since 1.6 + * @deprecated 1.9.1 + */ +function yourls_current_admin_page() { + yourls_deprecated_function( __FUNCTION__, '1.9.1' ); + if( yourls_is_admin() ) { + $current = substr( yourls_get_request(), 6 ); + if( $current === false ) + $current = 'index.php'; // if current page is http://sho.rt/admin/ instead of http://sho.rt/admin/index.php + + return $current; + } + return null; +} + +/** + * PHP emulation of JS's encodeURI + * + * @link https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURI + * @deprecated 1.9.1 + * @param string $url + * @return string + */ +function yourls_encodeURI($url) { + yourls_deprecated_function( __FUNCTION__, '1.9.1', '' ); + // Decode URL all the way + $result = yourls_rawurldecode_while_encoded( $url ); + // Encode once + $result = strtr( rawurlencode( $result ), array ( + '%3B' => ';', '%2C' => ',', '%2F' => '/', '%3F' => '?', '%3A' => ':', '%40' => '@', + '%26' => '&', '%3D' => '=', '%2B' => '+', '%24' => '$', '%21' => '!', '%2A' => '*', + '%27' => '\'', '%28' => '(', '%29' => ')', '%23' => '#', + ) ); + // @TODO: + // Known limit: this will most likely break IDN URLs such as http://www.académie-française.fr/ + // To fully support IDN URLs, advocate use of a plugin. + return yourls_apply_filter( 'encodeURI', $result, $url ); +} + /** * Check if a file is a plugin file * diff --git a/includes/functions-formatting.php b/includes/functions-formatting.php index 08ac8d9..83fc396 100644 --- a/includes/functions-formatting.php +++ b/includes/functions-formatting.php @@ -7,15 +7,18 @@ /** * Convert an integer (1337) to a string (3jk). * + * @param int $num Number to convert + * @param string $chars Characters to use for conversion + * @return string Converted number */ -function yourls_int2string( $num, $chars = null ) { +function yourls_int2string($num, $chars = null) { if( $chars == null ) $chars = yourls_get_shorturl_charset(); $string = ''; $len = strlen( $chars ); while( $num >= $len ) { - $mod = bcmod( $num, $len ); - $num = bcdiv( $num, $len ); + $mod = bcmod( (string)$num, (string)$len ); + $num = bcdiv( (string)$num, (string)$len ); $string = $chars[ $mod ] . $string; } $string = $chars[ intval( $num ) ] . $string; @@ -26,8 +29,11 @@ function yourls_int2string( $num, $chars = null ) { /** * Convert a string (3jk) to an integer (1337) * + * @param string $string String to convert + * @param string $chars Characters to use for conversion + * @return string Number (as a string) */ -function yourls_string2int( $string, $chars = null ) { +function yourls_string2int($string, $chars = null) { if( $chars == null ) $chars = yourls_get_shorturl_charset(); $integer = 0; @@ -36,7 +42,7 @@ function yourls_string2int( $string, $chars = null ) { $inputlen = strlen( $string ); for ($i = 0; $i < $inputlen; $i++) { $index = strpos( $chars, $string[$i] ); - $integer = bcadd( $integer, bcmul( $index, bcpow( $baselen, $i ) ) ); + $integer = bcadd( (string)$integer, bcmul( (string)$index, bcpow( (string)$baselen, (string)$i ) ) ); } return yourls_apply_filter( 'string2int', $integer, $string, $chars ); @@ -48,7 +54,6 @@ function yourls_string2int( $string, $chars = null ) { * @since 1.8.3 * @param string $prefix Optional prefix * @return string The unique string - * */ function yourls_unique_element_id($prefix = 'yid') { static $id_counter = 0; @@ -139,8 +144,11 @@ function yourls_sanitize_url_safe( $unsafe_url, $protocols = array() ) { * * Stolen from WP's _deep_replace * + * @param string|array $search Needle, or array of needles. + * @param string $subject Haystack. + * @return string The string with the replaced values. */ -function yourls_deep_replace( $search, $subject ){ +function yourls_deep_replace($search, $subject ){ $found = true; while($found) { $found = false; @@ -158,24 +166,31 @@ function yourls_deep_replace( $search, $subject ){ /** * Make sure an integer is a valid integer (PHP's intval() limits to too small numbers) * + * @param int $int Integer to check + * @return string Integer as a string */ -function yourls_sanitize_int( $int ) { +function yourls_sanitize_int($int ) { return ( substr( preg_replace( '/[^0-9]/', '', strval( $int ) ), 0, 20 ) ); } /** * Sanitize an IP address + * No check on validity, just return a sanitized string * + * @param string $ip IP address + * @return string IP address */ -function yourls_sanitize_ip( $ip ) { +function yourls_sanitize_ip($ip ) { return preg_replace( '/[^0-9a-fA-F:., ]/', '', $ip ); } /** * Make sure a date is m(m)/d(d)/yyyy, return false otherwise * + * @param string $date Date to check + * @return false|mixed Date in format m(m)/d(d)/yyyy or false if invalid */ -function yourls_sanitize_date( $date ) { +function yourls_sanitize_date($date ) { if( !preg_match( '!^\d{1,2}/\d{1,2}/\d{4}$!' , $date ) ) { return false; } @@ -185,18 +200,24 @@ function yourls_sanitize_date( $date ) { /** * Sanitize a date for SQL search. Return false if malformed input. * + * @param string $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 ) { +function yourls_sanitize_date_for_sql($date) { if( !yourls_sanitize_date( $date ) ) return false; return date( 'Y-m-d', strtotime( $date ) ); } /** - * Return trimmed string + * Return trimmed string, optionally append '[...]' if string is too long * + * @param string $string String to trim + * @param int $length Maximum length of string + * @param string $append String to append if trimmed + * @return string Trimmed string */ -function yourls_trim_long_string( $string, $length = 60, $append = '[...]' ) { +function yourls_trim_long_string($string, $length = 60, $append = '[...]') { $newstring = $string; if ( mb_strlen( $newstring ) > $length ) { $newstring = mb_substr( $newstring, 0, $length - mb_strlen( $append ), 'UTF-8' ) . $append; @@ -225,8 +246,10 @@ function yourls_sanitize_version( $version ) { /** * Sanitize a filename (no Win32 stuff) * + * @param string $file File name + * @return string|null Sanitized file name (or null if it's just backslashes, ok...) */ -function yourls_sanitize_filename( $file ) { +function yourls_sanitize_filename($file) { $file = str_replace( '\\', '/', $file ); // sanitize for Win32 installs $file = preg_replace( '|/+|' ,'/', $file ); // remove any duplicate slash return $file; @@ -235,8 +258,10 @@ function yourls_sanitize_filename( $file ) { /** * Check if a string seems to be UTF-8. Stolen from WP. * + * @param string $str String to check + * @return bool Whether string seems valid UTF-8 */ -function yourls_seems_utf8( $str ) { +function yourls_seems_utf8($str) { $length = strlen( $str ); for ( $i=0; $i < $length; $i++ ) { $c = ord( $str[ $i ] ); @@ -417,6 +442,8 @@ function yourls_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) { $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 ); @@ -654,40 +681,16 @@ function yourls_esc_textarea( $text ) { return yourls_apply_filter( 'esc_textarea', $safe_text, $text ); } - -/** -* PHP emulation of JS's encodeURI -* -* @link https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURI -* @param $url -* @return string -*/ -function yourls_encodeURI( $url ) { - // Decode URL all the way - $result = yourls_rawurldecode_while_encoded( $url ); - // Encode once - $result = strtr( rawurlencode( $result ), array ( - '%3B' => ';', '%2C' => ',', '%2F' => '/', '%3F' => '?', '%3A' => ':', '%40' => '@', - '%26' => '&', '%3D' => '=', '%2B' => '+', '%24' => '$', '%21' => '!', '%2A' => '*', - '%27' => '\'', '%28' => '(', '%29' => ')', '%23' => '#', - ) ); - // @TODO: - // Known limit: this will most likely break IDN URLs such as http://www.académie-française.fr/ - // To fully support IDN URLs, advocate use of a plugin. - return yourls_apply_filter( 'encodeURI', $result, $url ); -} - /** * Adds backslashes before letters and before a number at the start of a string. Stolen from WP. * * @since 1.6 - * * @param string $string Value to which backslashes will be added. * @return string String with backslashes inserted. */ function yourls_backslashit($string) { - $string = preg_replace('/^([0-9])/', '\\\\\\\\\1', $string); - $string = preg_replace('/([a-z])/i', '\\\\\1', $string); + $string = preg_replace('/^([0-9])/', '\\\\\\\\\1', (string)$string); + $string = preg_replace('/([a-z])/i', '\\\\\1', (string)$string); return $string; } @@ -745,7 +748,7 @@ function yourls_make_bookmarklet( $code ) { */ function yourls_get_timestamp( $timestamp ) { $offset = yourls_get_time_offset(); - $timestamp_offset = $timestamp + ($offset * 3600); + $timestamp_offset = (int)$timestamp + ($offset * 3600); return yourls_apply_filter( 'get_timestamp', $timestamp_offset, $timestamp, $offset ); } @@ -793,4 +796,3 @@ function yourls_get_date_format( $format ) { function yourls_get_time_format( $format ) { return yourls_apply_filter( 'get_time_format', (string)$format ); } - diff --git a/includes/functions-html.php b/includes/functions-html.php index 2ae620f..a619ffd 100644 --- a/includes/functions-html.php +++ b/includes/functions-html.php @@ -3,6 +3,7 @@ /** * Display

header and logo * + * @return void */ function yourls_html_logo() { yourls_do_action( 'pre_html_logo' ); @@ -22,6 +23,7 @@ function yourls_html_logo() { * * @param string $context Context of the page (stats, index, infos, ...) * @param string $title HTML title of the page + * @return void */ function yourls_html_head( $context = 'index', $title = '' ) { @@ -172,6 +174,7 @@ function yourls_html_footer($can_query = true) { * * @param string $url URL to prefill the input with * @param string $keyword Keyword to prefill the input with + * @return void */ function yourls_html_addnew( $url = '', $keyword = '' ) { $pre = yourls_apply_filter( 'shunt_html_addnew', false, $url, $keyword ); @@ -205,7 +208,7 @@ function yourls_html_addnew( $url = '', $keyword = '' ) { * The $param array is defined in /admin/index.php, check the yourls_html_tfooter() call * * @param array $params Array of all required parameters - * @return string Result + * @return void */ function yourls_html_tfooter( $params = array() ) { // Manually extract all parameters from the array. We prefer doing it this way, over using extract(), @@ -310,7 +313,7 @@ function yourls_html_tfooter( $params = array() ) { array( 'template' => '%clicks%', - 'clicks' => yourls_number_format_i18n( $clicks, 0, '', '' ), + 'clicks' => yourls_number_format_i18n( $clicks, 0 ), ), 'actions' => array( 'template' => '%actions% ', @@ -641,6 +664,7 @@ function yourls_table_add_row( $keyword, $url, $title, $ip, $clicks, $timestamp /** * Echo the main table head * + * @return void */ function yourls_table_head() { $start = ''."\n"; @@ -665,6 +689,7 @@ function yourls_table_head() { /** * Echo the tbody start tag * + * @return void */ function yourls_table_tbody_start() { echo yourls_apply_filter( 'table_tbody_start', '' ); @@ -673,6 +698,7 @@ function yourls_table_tbody_start() { /** * Echo the tbody end tag * + * @return void */ function yourls_table_tbody_end() { echo yourls_apply_filter( 'table_tbody_end', '' ); @@ -681,27 +707,36 @@ function yourls_table_tbody_end() { /** * Echo the table start tag * + * @return void */ function yourls_table_end() { echo yourls_apply_filter( 'table_end', '
' ); } + + /** * Echo HTML tag for a link * - */ -function yourls_html_link( $href, $title = '', $element = '' ) { - if( !$title ) - $title = $href; + * @param string $href URL to link to + * @param string $anchor Anchor text + * @param string $element Element id + * @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( $title ) ); + $link = sprintf( '%s', yourls_esc_url( $href ), $element, yourls_esc_html( $anchor ) ); echo yourls_apply_filter( 'html_link', $link ); } /** * Display the login screen. Nothing past this point. * + * @param string $error_msg Optional error message to display + * @return void */ function yourls_login_screen( $error_msg = '' ) { yourls_html_head( 'login' ); @@ -744,12 +779,13 @@ function yourls_login_screen( $error_msg = '' ) { die(); } + /** * Display the admin menu * + * @return void */ function yourls_html_menu() { - // 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 @@ -828,6 +864,9 @@ function yourls_html_menu() { /** * Wrapper function to display admin notices * + * @param string $message Message to display + * @param string $style Message style (default: 'notice') + * @return void */ function yourls_add_notice( $message, $style = 'notice' ) { // Escape single quotes in $message to avoid breaking the anonymous function @@ -838,6 +877,9 @@ function yourls_add_notice( $message, $style = 'notice' ) { /** * Return a formatted notice * + * @param string $message Message to display + * @param string $style CSS class to use for the notice + * @return string HTML of the notice */ function yourls_notice_box( $message, $style = 'notice' ) { return <<\n"; @@ -919,8 +964,9 @@ function yourls_l10n_calendar_strings() { * * @since 1.7 * @param string $compare_with Optional, YOURLS version to compare to + * @return void */ -function yourls_new_core_version_notice($compare_with = false) { +function yourls_new_core_version_notice($compare_with = null) { $compare_with = $compare_with ?: YOURLS_VERSION; $checks = yourls_get_option( 'core_version_checks' ); @@ -971,7 +1017,7 @@ function yourls_set_html_context($context) { * @return string */ function yourls_get_html_context() { - yourls_get_db()->get_html_context(); + return yourls_get_db()->get_html_context(); } /** diff --git a/includes/functions-http.php b/includes/functions-http.php index 16d7e71..db60abc 100644 --- a/includes/functions-http.php +++ b/includes/functions-http.php @@ -24,6 +24,10 @@ use WpOrg\Requests\Requests; * * @since 1.7 * @see yourls_http_request + * @param string $url URL to request + * @param array $headers HTTP headers to send + * @param array $data GET data + * @param array $options Options to pass to Requests * @return mixed Response object, or error string */ function yourls_http_get( $url, $headers = array(), $data = array(), $options = array() ) { @@ -35,6 +39,10 @@ function yourls_http_get( $url, $headers = array(), $data = array(), $options = * * @since 1.7 * @see yourls_http_request + * @param string $url URL to request + * @param array $headers HTTP headers to send + * @param array $data GET data + * @param array $options Options to pass to Requests * @return mixed String (page body) or null if error */ function yourls_http_get_body( $url, $headers = array(), $data = array(), $options = array() ) { @@ -49,6 +57,10 @@ function yourls_http_get_body( $url, $headers = array(), $data = array(), $optio * * @since 1.7 * @see yourls_http_request + * @param string $url URL to request + * @param array $headers HTTP headers to send + * @param array $data POST data + * @param array $options Options to pass to Requests * @return mixed Response object, or error string */ function yourls_http_post( $url, $headers = array(), $data = array(), $options = array() ) { @@ -62,6 +74,10 @@ function yourls_http_post( $url, $headers = array(), $data = array(), $options = * * @since 1.7 * @see yourls_http_request + * @param string $url URL to request + * @param array $headers HTTP headers to send + * @param array $data POST data + * @param array $options Options to pass to Requests * @return mixed String (page body) or null if error */ function yourls_http_post_body( $url, $headers = array(), $data = array(), $options = array() ) { @@ -360,8 +376,8 @@ function yourls_check_core_version() { * 3) the object should not contain any other key * * @since 1.7.7 - * @param $json JSON object to check - * @return bool true if seems legit, false otherwise + * @param object $json JSON object to check + * @return bool true if seems legit, false otherwise */ function yourls_validate_core_version_response($json) { return ( @@ -375,13 +391,14 @@ function yourls_validate_core_version_response($json) { /** * Get version number from Github zipball URL (last part of URL, really) + * * @since 1.8.3 * @param string $zipurl eg 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3' * @return string */ function yourls_get_version_from_zipball_url($zipurl) { $version = ''; - $parts = explode('/', parse_url(yourls_sanitize_url($zipurl), PHP_URL_PATH)); + $parts = explode('/', parse_url(yourls_sanitize_url($zipurl), PHP_URL_PATH) ?? ''); // expect at least 1 slash in path, return last part if( count($parts) > 1 ) { $version = end($parts); @@ -391,11 +408,15 @@ function yourls_get_version_from_zipball_url($zipurl) { /** * Check if URL is from YOURLS/YOURLS repo on github + * + * @since 1.8.3 + * @param string $url URL to check + * @return bool */ function yourls_is_valid_github_repo_url($url) { $url = yourls_sanitize_url($url); return ( - join('.',array_slice(explode('.',parse_url($url, PHP_URL_HOST)), -2, 2)) === 'github.com' + join('.',array_slice(explode('.', parse_url($url, PHP_URL_HOST) ?? ''), -2, 2)) === 'github.com' // explodes on '.' (['api','github','com']) and keeps the last two elements // to make sure domain is either github.com or one of its subdomain (api.github.com for instance) // TODO: keep an eye on Github API to make sure it doesn't change some day to another domain (githubapi.com, ...) @@ -406,6 +427,7 @@ function yourls_is_valid_github_repo_url($url) { /** * Check if object has only expected keys 'latest' and 'zipurl' containing strings + * * @since 1.8.3 * @param object $json * @return bool diff --git a/includes/functions-infos.php b/includes/functions-infos.php index 8c10fd9..ed97203 100644 --- a/includes/functions-infos.php +++ b/includes/functions-infos.php @@ -3,8 +3,11 @@ /** * Echoes an image tag of Google Charts map from sorted array of 'country_code' => 'number of visits' (sort by DESC) * + * @param array $countries Array of 'country_code' => 'number of visits' + * @param string $id Optional HTML element ID + * @return void */ -function yourls_stats_countries_map( $countries, $id = null ) { +function yourls_stats_countries_map($countries, $id = null) { yourls_do_action( 'pre_stats_countries_map' ); @@ -29,11 +32,17 @@ function yourls_stats_countries_map( $countries, $id = null ) { echo yourls_apply_filter( 'stats_countries_map', $map, $countries, $options, $id ); } + /** * Echoes an image tag of Google Charts pie from sorted array of 'data' => 'value' (sort by DESC). Optional $limit = (integer) limit list of X first countries, sorted by most visits * + * @param array $data Array of 'data' => 'value' + * @param int $limit Optional limit list of X first countries + * @param $size Optional size of the image + * @param $id Optional HTML element ID + * @return void */ -function yourls_stats_pie( $data, $limit = 10, $size = '340x220', $id = null ) { +function yourls_stats_pie($data, $limit = 10, $size = '340x220', $id = null) { yourls_do_action( 'pre_stats_pie' ); @@ -80,11 +89,14 @@ function yourls_stats_pie( $data, $limit = 10, $size = '340x220', $id = null ) { echo yourls_apply_filter( 'stats_pie', $pie, $data, $limit, $size, $options, $id ); } + /** * Build a list of all daily values between d1/m1/y1 to d2/m2/y2. * + * @param array $dates + * @return array[] Array of arrays of days, months, years */ -function yourls_build_list_of_days( $dates ) { +function yourls_build_list_of_days($dates) { /* Say we have an array like: $dates = array ( 2009 => array ( @@ -153,13 +165,17 @@ function yourls_build_list_of_days( $dates ) { ); } + /** * Echoes an image tag of Google Charts line graph from array of values (eg 'number of clicks'). * * $legend1_list & legend2_list are values used for the 2 x-axis labels. $id is an HTML/JS id * + * @param array $values Array of values (eg 'number of clicks') + * @param string $id HTML element id + * @return void */ -function yourls_stats_line( $values, $id = null ) { +function yourls_stats_line($values, $id = null) { yourls_do_action( 'pre_stats_line' ); @@ -195,20 +211,27 @@ function yourls_stats_line( $values, $id = null ) { echo yourls_apply_filter( 'stats_line', $lineChart, $values, $options, $id ); } + /** - * Return the number of days in a month. From php.net, used if PHP built without calendar functions + * Return the number of days in a month. From php.net. * + * @param int $month + * @param int $year + * @return int */ -function yourls_days_in_month( $month, $year ) { +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 ); } + /** * Get max value from date array of 'Aug 12, 2012' = '1337' * + * @param array $list_of_days + * @return array */ -function yourls_stats_get_best_day( $list_of_days ) { +function yourls_stats_get_best_day($list_of_days) { $max = max( $list_of_days ); foreach( $list_of_days as $k=>$v ) { if ( $v == $max ) @@ -219,8 +242,11 @@ function yourls_stats_get_best_day( $list_of_days ) { /** * Return domain of a URL * + * @param string $url + * @param bool $include_scheme + * @return string */ -function yourls_get_domain( $url, $include_scheme = false ) { +function yourls_get_domain($url, $include_scheme = false) { $parse = @parse_url( $url ); // Hiding ugly stuff coming from malformed referrer URLs // Get host & scheme. Fall back to path if not found. @@ -236,19 +262,24 @@ function yourls_get_domain( $url, $include_scheme = false ) { return $host; } + /** * Return favicon URL * + * @param string $url + * @return string */ -function yourls_get_favicon_url( $url ) { +function yourls_get_favicon_url($url) { return yourls_match_current_protocol( '//www.google.com/s2/favicons?domain=' . yourls_get_domain( $url, false ) ); } /** * Scale array of data from 0 to 100 max * + * @param array $data + * @return array */ -function yourls_scale_data( $data ) { +function yourls_scale_data($data ) { $max = max( $data ); if( $max > 100 ) { foreach( $data as $k=>$v ) { @@ -258,11 +289,19 @@ function yourls_scale_data( $data ) { return $data; } + /** - * Tweak granularity of array $array: keep only $grain values. This make less accurate but less messy graphs when too much values. See http://code.google.com/apis/chart/formats.html#granularity + * Tweak granularity of array $array: keep only $grain values. * + * This make less accurate but less messy graphs when too much values. + * See https://developers.google.com/chart/image/docs/gallery/line_charts?hl=en#data-granularity + * + * @param array $array + * @param int $grain + * @param bool $preserve_max + * @return array */ -function yourls_array_granularity( $array, $grain = 100, $preserve_max = true ) { +function yourls_array_granularity($array, $grain = 100, $preserve_max = true) { if ( count( $array ) > $grain ) { $max = max( $array ); $step = intval( count( $array ) / $grain ); @@ -286,8 +325,10 @@ function yourls_array_granularity( $array, $grain = 100, $preserve_max = true ) /** * Transform data array to data table for Google API * + * @param array $data + * @return string */ -function yourls_google_array_to_data_table( $data ){ +function yourls_google_array_to_data_table($data){ $str = "var data = google.visualization.arrayToDataTable([\n"; foreach( $data as $label => $values ){ if( !is_array( $values ) ) { @@ -310,8 +351,13 @@ function yourls_google_array_to_data_table( $data ){ /** * Return javascript code that will display the Google Chart * + * @param string $graph_type + * @param string $data + * @param var $options + * @param string $id + * @return string */ -function yourls_google_viz_code( $graph_type, $data, $options, $id ) { +function yourls_google_viz_code($graph_type, $data, $options, $id ) { $function_name = 'yourls_graph' . $id; $code = "\n