diff --git a/.editorconfig b/.editorconfig
index c72ce250..ff94fd9b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -13,7 +13,7 @@ insert_final_newline = true
trim_trailing_whitespace = false
[*.js]
-indent_size = 2
+indent_size = 4
[*.yml]
indent_size = 2
diff --git a/admin/admin-ajax.php b/admin/admin-ajax.php
index a89912ed..8dbc0b27 100644
--- a/admin/admin-ajax.php
+++ b/admin/admin-ajax.php
@@ -6,6 +6,7 @@ yourls_maybe_require_auth();
// This file will output a JSON string
yourls_content_type_header( 'application/json' );
+yourls_no_cache_headers();
if( !isset( $_REQUEST['action'] ) )
die();
@@ -19,7 +20,7 @@ switch( $action ) {
$return = yourls_add_new_link( $_REQUEST['url'], $_REQUEST['keyword'] );
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'] );
@@ -31,18 +32,18 @@ switch( $action ) {
$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;
-
+
case 'logout':
// unused for the moment
yourls_logout();
break;
-
+
default:
yourls_do_action( 'yourls_ajax_'.$action );
diff --git a/admin/index.php b/admin/index.php
index baa0bfe2..4e21d05b 100644
--- a/admin/index.php
+++ b/admin/index.php
@@ -164,10 +164,10 @@ if ( isset( $_GET['u'] ) or isset( $_GET['up'] ) ) {
// No sanitization needed here: everything happens in yourls_add_new_link()
if( isset( $_GET['u'] ) ) {
// Old school bookmarklet: ?u=
Important Note: bookmarklets may fail on websites with https, especially the "Instant" bookrmarklets. There is nothing you can do about this.'); ?>
+ @@ -278,8 +280,6 @@ TUMBLR; -Note: depending on server settings, bookmarklets might fail on websites with https.'); ?>
- diff --git a/admin/upgrade.php b/admin/upgrade.php index de463693..cf011b9b 100644 --- a/admin/upgrade.php +++ b/admin/upgrade.php @@ -28,8 +28,8 @@ if ( !yourls_upgrade_is_needed() ) { // From what are we upgrading? if ( isset( $_GET['oldver'] ) && isset( $_GET['oldsql'] ) ) { - $oldver = yourls_sanitize_version( $_GET['oldver'] ); - $oldsql = yourls_sanitize_version( $_GET['oldsql'] ); + $oldver = (string)( $_GET['oldver'] ); + $oldsql = (string)( $_GET['oldsql'] ); } else { list( $oldver, $oldsql ) = yourls_get_current_version_from_sql(); } @@ -80,7 +80,6 @@ if ( !yourls_upgrade_is_needed() ) { } - ?> diff --git a/composer.json b/composer.json index 01b0f72a..be52586b 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "geoip2/geoip2" : "2.10.0", "aura/sql": "~2.", "jakeasmith/http_build_url": "1.0.1", - "symfony/polyfill-mbstring": "1.15.0" + "symfony/polyfill-mbstring": "1.15.0", + "symfony/polyfill-intl-idn": "^1.17" }, "config": { "vendor-dir": "includes/vendor" diff --git a/composer.lock b/composer.lock index ea3f34cd..fa50e597 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": "6d9b3e4fa1ffc661d944dd5caf5e6da0", + "content-hash": "b0f6e0ea19d5be86af9c8f4ddc92622e", "packages": [ { "name": "aura/sql", @@ -501,6 +501,68 @@ ], "time": "2016-10-13T00:11:37+00:00" }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "3bff59ea7047e925be6b7f2059d60af31bb46d6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/3bff59ea7047e925be6b7f2059d60af31bb46d6a", + "reference": "3bff59ea7047e925be6b7f2059d60af31bb46d6a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2020-05-12T16:47:27+00:00" + }, { "name": "symfony/polyfill-mbstring", "version": "v1.15.0", @@ -559,6 +621,61 @@ "shim" ], "time": "2020-03-09T19:04:49+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "f048e612a3905f34931127360bdd2def19a5e582" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/f048e612a3905f34931127360bdd2def19a5e582", + "reference": "f048e612a3905f34931127360bdd2def19a5e582", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-05-12T16:47:27+00:00" } ], "packages-dev": [], diff --git a/includes/Config/Init.php b/includes/Config/Init.php index 07db1f95..dce118d0 100644 --- a/includes/Config/Init.php +++ b/includes/Config/Init.php @@ -85,14 +85,16 @@ class Init { // Check if need to redirect to install procedure if ($actions->redirect_to_install === true) { if (!yourls_is_installed() && !yourls_is_installing()) { - yourls_redirect( yourls_admin_url('install.php'), 302 ); + yourls_no_cache_headers(); + yourls_redirect( yourls_admin_url('install.php'), 307 ); } } // Check if upgrade is needed (bypassed if upgrading or installing) if ($actions->check_if_upgrade_needed === true) { if (!yourls_is_upgrading() && !yourls_is_installing() && yourls_upgrade_is_needed()) { - yourls_redirect( yourls_admin_url('upgrade.php'), 302 ); + yourls_no_cache_headers(); + yourls_redirect( yourls_admin_url('upgrade.php'), 307 ); } } diff --git a/includes/class-mysql.php b/includes/class-mysql.php index 54f4e8d2..2366e925 100644 --- a/includes/class-mysql.php +++ b/includes/class-mysql.php @@ -30,7 +30,7 @@ function yourls_db_connect() { $dbhost = sprintf( '%1$s;port=%2$d', $dbhost, $dbport ); } - $charset = yourls_apply_filter( 'db_connect_charset', 'utf8' ); + $charset = yourls_apply_filter( 'db_connect_charset', 'utf8mb4' ); /** * Data Source Name (dsn) used to connect the DB diff --git a/includes/functions-api.php b/includes/functions-api.php index 87493dc3..baf3cb10 100644 --- a/includes/functions-api.php +++ b/includes/functions-api.php @@ -212,7 +212,7 @@ function yourls_api_expand( $shorturl ) { if( $longurl ) { $return = array( 'keyword' => $keyword, - 'shorturl' => yourls_get_yourls_site() . "/$keyword", + 'shorturl' => yourls_link($keyword), 'longurl' => $longurl, 'title' => yourls_get_keyword_title( $keyword ), 'simple' => $longurl, diff --git a/includes/functions-deprecated.php b/includes/functions-deprecated.php index a8097954..a2ef80a7 100644 --- a/includes/functions-deprecated.php +++ b/includes/functions-deprecated.php @@ -35,6 +35,20 @@ function yourls_current_time( $type, $gmt = 0 ) { } } +/** + * Lowercase scheme and domain of an URI - see issues 591, 1630, 1889 + * + * Renamed to yourls_normalize_uri() in 1.7.10 because the function now does more than just + * lowercasing the scheme and domain. + * + * @deprecated 1.7.10 + * + */ +function yourls_lowercase_scheme_domain( $url ) { + yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_normalize_uri' ); + return yourls_normalize_uri( $url ); +} + /** * The original string sanitize function * diff --git a/includes/functions-formatting.php b/includes/functions-formatting.php index 89b47662..cb826b74 100644 --- a/includes/functions-formatting.php +++ b/includes/functions-formatting.php @@ -56,7 +56,7 @@ function yourls_string2htmlid( $string ) { * If we are ADDING or EDITING a short URL, the keyword must comply to the short URL charset: every * character that doesn't belong to it will be removed. * But otherwise we must have a more conservative approach: we could be checking for a keyword that - * was once valid but now the short URL charset. In such a case, we are treating the keyword for what + * was once valid but now the short URL charset has changed. In such a case, we are treating the keyword for what * it is: just a part of a URL, hence sanitize it as a URL. * * @param string $keyword short URL keyword @@ -495,7 +495,7 @@ function yourls_esc_url( $url, $context = 'display', $protocols = array() ) { $original_url = $url; // force scheme and domain to lowercase - see issues 591 and 1630 - $url = yourls_lowercase_scheme_domain( $url ); + $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' @@ -534,7 +534,10 @@ function yourls_esc_url( $url, $context = 'display', $protocols = array() ) { /** - * Lowercase scheme and domain of an URI - see issues 591, 1630, 1889 + * Normalize a URI : lowercase scheme and domain, convert IDN to UTF8 + * + * All in one example: 'HTTP://XN--mgbuq0c.Com/AbCd' -> 'http://طارق.com/AbCd' + * See issues 591, 1630, 1889, 2691 * * This function is trickier than what seems to be needed at first * @@ -543,13 +546,13 @@ function yourls_esc_url( $url, $context = 'display', $protocols = array() ) { * The general rule is that the scheme ("stuff://" or "stuff:") is case insensitive and should be lowercase. But then, depending on the * scheme, parts of what follows the scheme may or may not be case sensitive. * - * Second, simply using parse_url() and its opposite http_build_url() (see functions-compat.php) is a pretty unsafe process: + * Second, simply using parse_url() and its opposite http_build_url() is a pretty unsafe process: * - parse_url() can easily trip up on malformed or weird URLs * - exploding a URL with parse_url(), lowercasing some stuff, and glueing things back with http_build_url() does not handle well * "stuff:"-like URI [1] and can result in URLs ending modified [2][3]. We don't want to *validate* URI, we just want to lowercase * what is supposed to be lowercased. * - * So, to be conservative, this functions: + * So, to be conservative, this function: * - lowercases the scheme * - does not lowercase anything else on "stuff:" URI * - tries to lowercase only scheme and domain of "stuff://" URI @@ -562,7 +565,7 @@ function yourls_esc_url( $url, $context = 'display', $protocols = array() ) { * @param string $url URL * @return string URL with lowercase scheme and protocol */ -function yourls_lowercase_scheme_domain( $url ) { +function yourls_normalize_uri( $url ) { $scheme = yourls_get_protocol( $url ); if ('' == $scheme) { @@ -596,9 +599,14 @@ function yourls_lowercase_scheme_domain( $url ) { $lower = array(); $lower['scheme'] = strtolower( $parts['scheme'] ); if( isset( $parts['host'] ) ) { - $lower['host'] = strtolower( $parts['host'] ); - } else { - $parts['host'] = '***'; + // Convert domain to lowercase, with mb_ to preserve UTF8 + $lower['host'] = mb_strtolower($parts['host']); + /** + * Convert IDN domains to their UTF8 form so that طارق.net and xn--mgbuq0c.net + * are considered the same. Explicitely mention option and variant to avoid notice + * on PHP 7.2 and 7.3 + */ + $lower['host'] = idn_to_utf8($lower['host'], IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46); } $url = http_build_url($url, $lower); diff --git a/includes/functions-html.php b/includes/functions-html.php index 225f45dd..a57f61a6 100644 --- a/includes/functions-html.php +++ b/includes/functions-html.php @@ -58,10 +58,7 @@ function yourls_html_head( $context = 'index', $title = '' ) { // Force no cache for all admin pages if( yourls_is_admin() && !headers_sent() ) { - header( 'Expires: Thu, 23 Mar 1972 07:00:00 GMT' ); - header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); - header( 'Cache-Control: no-cache, must-revalidate, max-age=0' ); - header( 'Pragma: no-cache' ); + yourls_no_cache_headers(); yourls_content_type_header( yourls_apply_filter( 'html_head_content-type', 'text/html' ) ); yourls_do_action( 'admin_headers', $context, $title ); } @@ -88,7 +85,7 @@ function yourls_html_head( $context = 'index', $title = '' ) { - + @@ -399,6 +396,9 @@ function yourls_share_box( $longurl, $shorturl, $title = '', $text='', $shortlin if ( false !== $pre ) return $pre; + // Make sure IDN domains are in their UTF8 form + $shorturl = yourls_normalize_uri($shorturl); + $text = ( $text ? '"'.$text.'" ' : '' ); $title = ( $title ? "$title " : '' ); $share = yourls_esc_textarea( $title.$text.$shorturl ); @@ -488,7 +488,7 @@ function yourls_table_edit_row( $keyword ) { $id = yourls_string2htmlid( $keyword ); // used as HTML #id $url = yourls_get_keyword_longurl( $keyword ); $title = htmlspecialchars( yourls_get_keyword_title( $keyword ) ); - $safe_url = yourls_esc_attr( rawurldecode( $url ) ); + $safe_url = yourls_esc_attr( $url ); $safe_title = yourls_esc_attr( $title ); $safe_keyword = yourls_esc_attr( $keyword ); @@ -595,7 +595,7 @@ function yourls_table_add_row( $keyword, $url, $title = '', $ip, $clicks, $times 'long_url' => yourls_esc_url( $url ), 'title_attr' => yourls_esc_attr( $title ), 'title_html' => yourls_esc_html( yourls_trim_long_string( $title ) ), - 'long_url_html' => yourls_esc_html( yourls_trim_long_string( $url ) ), + 'long_url_html' => yourls_esc_html( yourls_trim_long_string( urldecode( $url ) ) ), 'warning' => $protocol_warning, ), 'timestamp' => array( @@ -920,23 +920,6 @@ function yourls_new_core_version_notice() { } } -/** - * Send a filerable content type header - * - * @since 1.7 - * @param string $type content type ('text/html', 'application/json', ...) - * @return bool whether header was sent - */ -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; -} - /** * Get search text from query string variables search_protocol, search_slashes and search * diff --git a/includes/functions-install.php b/includes/functions-install.php index a601c735..2d1a95f7 100644 --- a/includes/functions-install.php +++ b/includes/functions-install.php @@ -208,39 +208,39 @@ function yourls_create_sql_tables() { // Create Table Query $create_tables = array(); $create_tables[YOURLS_DB_TABLE_URL] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_URL.'` ('. - '`keyword` varchar(200) BINARY NOT NULL,'. - '`url` text BINARY NOT NULL,'. - '`title` text CHARACTER SET utf8,'. - '`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,'. - '`ip` VARCHAR(41) NOT NULL,'. - '`clicks` INT(10) UNSIGNED NOT NULL,'. - ' PRIMARY KEY (`keyword`),'. - ' KEY `timestamp` (`timestamp`),'. - ' KEY `ip` (`ip`)'. - ');'; + '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,'. + '`title` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,'. + '`timestamp` timestamp NOT NULL DEFAULT current_timestamp(),'. + '`ip` varchar(41) COLLATE utf8mb4_unicode_ci NOT NULL,'. + '`clicks` int(10) unsigned NOT NULL,'. + 'PRIMARY KEY (`keyword`),'. + 'KEY `ip` (`ip`),'. + 'KEY `timestamp` (`timestamp`)'. + ') DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; $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) NOT NULL default "",'. - '`option_value` longtext NOT NULL,'. + '`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 ;'; + ') 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(200) BINARY 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 ;'; + ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; $create_table_count = 0; diff --git a/includes/functions-links.php b/includes/functions-links.php index 32e8b462..092f62b2 100644 --- a/includes/functions-links.php +++ b/includes/functions-links.php @@ -119,14 +119,26 @@ function yourls_remove_query_arg( $key, $query = false ) { } /** - * Converts keyword into short link (prepend with YOURLS base URL) + * Converts keyword into short link (prepend with YOURLS base URL) or stat link (sho.rt/abc+) * - * This function does not check for a valid keyword + * This function does not check for a valid keyword. + * The resulting link is normalized to allow for IDN translation to UTF8 * + * @param string $keyword Short URL keyword + * @param bool $stats Optional, true to return a stat link (eg sho.rt/abc+) + * @return string Short URL, or keyword stat URL */ -function yourls_link( $keyword = '' ) { +function yourls_link( $keyword = '', $stats = false ) { $keyword = yourls_sanitize_keyword($keyword); - $link = yourls_get_yourls_site() . '/' . $keyword; + if( $stats === true ) { + $keyword = $keyword . '+'; + } + $link = yourls_normalize_uri( yourls_get_yourls_site() . '/' . $keyword ); + + if( yourls_is_ssl() ) { + $link = yourls_set_url_scheme( $link, 'https' ); + } + return yourls_apply_filter( 'yourls_link', $link, $keyword ); } @@ -137,13 +149,7 @@ function yourls_link( $keyword = '' ) { * */ function yourls_statlink( $keyword = '' ) { - $keyword = yourls_sanitize_keyword($keyword); - $link = yourls_get_yourls_site() . '/' . $keyword . '+'; - - if( yourls_is_ssl() ) { - $link = yourls_set_url_scheme( $link, 'https' ); - } - + $link = yourls_link( $keyword, true ); return yourls_apply_filter( 'yourls_statlink', $link, $keyword ); } diff --git a/includes/functions-shorturls.php b/includes/functions-shorturls.php index 26e0704a..efe0723d 100644 --- a/includes/functions-shorturls.php +++ b/includes/functions-shorturls.php @@ -31,7 +31,6 @@ function yourls_add_new_link( $url, $keyword = '', $title = '' ) { if ( false !== $pre ) return $pre; - $url = yourls_encodeURI( $url ); $url = yourls_sanitize_url( $url ); if ( !$url || $url == 'http://' || $url == 'https://' ) { $return['status'] = 'fail'; @@ -58,7 +57,6 @@ function yourls_add_new_link( $url, $keyword = '', $title = '' ) { yourls_do_action( 'pre_add_new_link', $url, $keyword, $title ); - $strip_url = stripslashes( $url ); $return = array(); // duplicates allowed or new URL => store it @@ -87,12 +85,12 @@ function yourls_add_new_link( $url, $keyword = '', $title = '' ) { } else { // all clear, store ! yourls_insert_link_in_db( $url, $keyword, $title ); - $return['url'] = array('keyword' => $keyword, 'url' => $strip_url, 'title' => $title, 'date' => date('Y-m-d H:i:s'), 'ip' => $ip ); + $return['url'] = array('keyword' => $keyword, 'url' => $url, 'title' => $title, 'date' => date('Y-m-d H:i:s'), 'ip' => $ip ); $return['status'] = 'success'; - $return['message'] = /* //translators: eg "http://someurl/ added to DB" */ yourls_s( '%s added to database', yourls_trim_long_string( $strip_url ) ); + $return['message'] = /* //translators: eg "http://someurl/ added to DB" */ yourls_s( '%s added to database', yourls_trim_long_string( $url ) ); $return['title'] = $title; $return['html'] = yourls_table_add_row( $keyword, $url, $title, $ip, 0, time() ); - $return['shorturl'] = yourls_get_yourls_site() .'/'. $keyword; + $return['shorturl'] = yourls_link($keyword); } // Create random keyword @@ -109,12 +107,12 @@ function yourls_add_new_link( $url, $keyword = '', $title = '' ) { if ( yourls_keyword_is_free($keyword) ) { if (yourls_insert_link_in_db( $url, $keyword, $title )){ // everything ok, populate needed vars - $return['url'] = array('keyword' => $keyword, 'url' => $strip_url, 'title' => $title, 'date' => $timestamp, 'ip' => $ip ); + $return['url'] = array('keyword' => $keyword, 'url' => $url, 'title' => $title, 'date' => $timestamp, 'ip' => $ip ); $return['status'] = 'success'; - $return['message'] = /* //translators: eg "http://someurl/ added to DB" */ yourls_s( '%s added to database', yourls_trim_long_string( $strip_url ) ); + $return['message'] = /* //translators: eg "http://someurl/ added to DB" */ yourls_s( '%s added to database', yourls_trim_long_string( $url ) ); $return['title'] = $title; $return['html'] = yourls_table_add_row( $keyword, $url, $title, $ip, 0, time() ); - $return['shorturl'] = yourls_get_yourls_site() .'/'. $keyword; + $return['shorturl'] = yourls_link($keyword); } else { // database error, couldnt store result $return['status'] = 'fail'; @@ -135,10 +133,10 @@ function yourls_add_new_link( $url, $keyword = '', $title = '' ) { $return['status'] = 'fail'; $return['code'] = 'error:url'; - $return['url'] = array( 'keyword' => $url_exists->keyword, 'url' => $strip_url, 'title' => $url_exists->title, 'date' => $url_exists->timestamp, 'ip' => $url_exists->ip, 'clicks' => $url_exists->clicks ); - $return['message'] = /* //translators: eg "http://someurl/ already exists" */ yourls_s( '%s already exists in database', yourls_trim_long_string( $strip_url ) ); + $return['url'] = array( 'keyword' => $url_exists->keyword, 'url' => $url, 'title' => $url_exists->title, 'date' => $url_exists->timestamp, 'ip' => $url_exists->ip, 'clicks' => $url_exists->clicks ); + $return['message'] = /* //translators: eg "http://someurl/ already exists" */ yourls_s( '%s already exists in database', yourls_trim_long_string( $url ) ); $return['title'] = $url_exists->title; - $return['shorturl'] = yourls_get_yourls_site() .'/'. $url_exists->keyword; + $return['shorturl'] = yourls_link($url_exists->keyword); } yourls_do_action( 'post_add_new_link', $url, $keyword, $title, $return ); @@ -339,7 +337,7 @@ function yourls_edit_link( $url, $keyword, $newkeyword='', $title='' ) { $binds = array('url' => $url, 'newkeyword' => $newkeyword, 'title' => $title, 'keyword' => $keyword); $update_url = $ydb->fetchAffected($sql, $binds); if( $update_url ) { - $return['url'] = array( 'keyword' => $newkeyword, 'shorturl' => yourls_get_yourls_site().'/'.$newkeyword, 'url' => $strip_url, 'display_url' => yourls_trim_long_string( $strip_url ), 'title' => $strip_title, 'display_title' => yourls_trim_long_string( $strip_title ) ); + $return['url'] = array( 'keyword' => $newkeyword, 'shorturl' => yourls_link($newkeyword), 'url' => $strip_url, 'display_url' => yourls_trim_long_string( $strip_url ), 'title' => $strip_title, 'display_title' => yourls_trim_long_string( $strip_title ) ); $return['status'] = 'success'; $return['message'] = yourls__( 'Link updated in database' ); } else { @@ -563,7 +561,7 @@ function yourls_get_keyword_stats( $shorturl ) { 'statusCode' => 200, 'message' => 'success', 'link' => array( - 'shorturl' => yourls_get_yourls_site() .'/'. $res->keyword, + 'shorturl' => yourls_link($res->keyword), 'url' => $res->url, 'title' => $res->title, 'timestamp'=> $res->timestamp, diff --git a/includes/functions-upgrade.php b/includes/functions-upgrade.php index cec0c463..eb254cdd 100644 --- a/includes/functions-upgrade.php +++ b/includes/functions-upgrade.php @@ -5,7 +5,10 @@ * */ function yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ) { - // special case for 1.3: the upgrade is a multi step procedure + + yourls_maintenance_mode(true); + + // special case for 1.3: the upgrade is a multi step procedure if( $oldsql == 100 ) { yourls_upgrade_to_14( $step ); } @@ -25,7 +28,10 @@ function yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ) { yourls_upgrade_to_15(); if( $oldsql < 482 ) - yourls_upgrade_482(); + yourls_upgrade_482(); // that was somewhere 1.5 and 1.5.1 ... + + if( $oldsql < 505 ) + yourls_upgrade_to_18(); yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3" ) ); @@ -35,10 +41,57 @@ function yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ) { // 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; } } +/************************** 1.6 -> 1.8 **************************/ + +function yourls_upgrade_to_18() { + $ydb = yourls_get_db(); + $error_msg = []; + + echo "Updating DB. Please wait...
"; + + $ydb->beginTransaction(); + + $queries = array( + 'database charset' => sprintf('ALTER DATABASE %s CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;', YOURLS_DB_NAME), + 'options charset' => sprintf('ALTER TABLE %s CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', YOURLS_DB_TABLE_OPTIONS), + 'short URL charset' => sprintf('ALTER TABLE %s CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', YOURLS_DB_TABLE_URL), + 'short URL varchar' => sprintf("ALTER TABLE %s CHANGE `keyword` `keyword` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '';", YOURLS_DB_TABLE_URL), + 'short URL type' => sprintf("ALTER TABLE %s CHANGE `url` `url` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;", YOURLS_DB_TABLE_URL), + 'short URL type' => sprintf("ALTER TABLE %s CHANGE `title` `title` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci", YOURLS_DB_TABLE_URL), + ); + + foreach($queries as $what => $query) { + try { + $ydb->perform($query); + } catch (\Exception $e) { + $error_msg[] = $e ->getMessage(); + } + } + + $result = $ydb->commit(); + + if( $error_msg or $result === false ) { + echo "Unable to update the DB.
"; + echo "You will have to manually fix things, sorry for the inconvenience :(
"; + echo "The errors were: +
"; + foreach( $error_msg as $error ) { + echo "$error\n"; + } + echo ""; + die(); + } + + echo "
OK!
"; +} + +/************************** 1.5 -> 1.6 **************************/ + /** * Upgrade r482 * @@ -48,7 +101,7 @@ function yourls_upgrade_482() { global $ydb; $table_url = YOURLS_DB_TABLE_URL; $sql = "ALTER TABLE `$table_url` CHANGE `title` `title` TEXT CHARACTER SET utf8;"; - $ydb->query( $sql ); + $ydb->perform( $sql ); echo "Updating table structure. Please wait...
"; } @@ -65,10 +118,9 @@ function yourls_upgrade_to_15( ) { echo "Enabling the plugin API. Please wait...
"; // Alter URL table to store titles - global $ydb; $table_url = YOURLS_DB_TABLE_URL; $sql = "ALTER TABLE `$table_url` ADD `title` TEXT AFTER `url`;"; - $ydb->query( $sql ); + yourls_get_db()->perform( $sql ); echo "Updating table structure. Please wait...
"; // Update .htaccess @@ -84,7 +136,7 @@ function yourls_upgrade_to_15( ) { */ function yourls_upgrade_to_143( ) { // Check if we have 'keyword' (borked install) or 'shorturl' (ok install) - global $ydb; + $ydb = yourls_get_db(); $table_log = YOURLS_DB_TABLE_LOG; $sql = "SHOW COLUMNS FROM `$table_log`"; $cols = $ydb->fetchObjects( $sql ); @@ -116,10 +168,9 @@ function yourls_upgrade_to_141( ) { * */ function yourls_alter_url_table_to_141() { - global $ydb; $table_url = YOURLS_DB_TABLE_URL; $alter = "ALTER TABLE `$table_url` CHANGE `keyword` `keyword` VARCHAR( 200 ) BINARY, CHANGE `url` `url` TEXT BINARY "; - $ydb->query( $alter ); + yourls_get_db()->perform( $alter ); echo "Structure of existing tables updated. Please wait...
"; } @@ -172,11 +223,10 @@ function yourls_update_options_to_14() { yourls_update_option( 'db_version', '200' ); if( defined('YOURLS_DB_TABLE_NEXTDEC') ) { - global $ydb; $table = YOURLS_DB_TABLE_NEXTDEC; - $next_id = $ydb->fetchValue("SELECT `next_id` FROM `$table`"); + $next_id = yourls_get_db()->fetchValue("SELECT `next_id` FROM `$table`"); yourls_update_option( 'next_id', $next_id ); - @$ydb->query( "DROP TABLE `$table`" ); + 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 } @@ -187,7 +237,7 @@ function yourls_update_options_to_14() { * */ function yourls_create_tables_for_14() { - global $ydb; + $ydb = yourls_get_db(); $queries = array(); @@ -214,7 +264,7 @@ function yourls_create_tables_for_14() { ');'; foreach( $queries as $query ) { - $ydb->query( $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) + $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...
"; @@ -226,7 +276,7 @@ function yourls_create_tables_for_14() { * */ function yourls_alter_url_table_to_14() { - global $ydb; + $ydb = yourls_get_db(); $table = YOURLS_DB_TABLE_URL; $alters = array(); @@ -236,7 +286,7 @@ function yourls_alter_url_table_to_14() { $alters[] = "ALTER TABLE `$table` DROP PRIMARY KEY"; foreach ( $alters as $query ) { - $ydb->query( $query ); + $ydb->perform( $query ); } echo "Structure of existing tables updated. Please wait...
"; @@ -247,7 +297,7 @@ function yourls_alter_url_table_to_14() { * */ function yourls_alter_url_table_to_14_part_two() { - global $ydb; + $ydb = yourls_get_db(); $table = YOURLS_DB_TABLE_URL; $alters = array(); @@ -256,7 +306,7 @@ function yourls_alter_url_table_to_14_part_two() { $alters[] = "ALTER TABLE `$table` ADD INDEX ( `timestamp` )"; foreach ( $alters as $query ) { - $ydb->query( $query ); + $ydb->perform( $query ); } echo "New table index created
"; @@ -267,7 +317,7 @@ function yourls_alter_url_table_to_14_part_two() { * */ function yourls_update_table_to_14() { - global $ydb; + $ydb = yourls_get_db(); $table = YOURLS_DB_TABLE_URL; // Modify each link to reflect new structure @@ -286,14 +336,7 @@ function yourls_update_table_to_14() { $keyword = $row->keyword; $url = $row->url; $newkeyword = yourls_int2string( $keyword ); - $ydb->query("UPDATE `$table` SET `keyword` = '$newkeyword' WHERE `url` = '$url';"); - - /** - * @todo: As of 1.7.3+ when ezSQL is replaced, $ydb->result will no longer exist. This will fail and - * should be replaced with a check for the number of affected rows. This said, - * chances are no one still needs this. Leave it unfixed until someone complains. - */ - if( $ydb->result === true ) { + 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 :/ diff --git a/includes/functions.php b/includes/functions.php index 0fea7903..740c58a9 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -143,7 +143,7 @@ function yourls_get_stats( $filter = 'top', $limit = 10, $start = 0 ) { foreach ( (array)$results as $res ) { $return['links']['link_'.$i++] = [ - 'shorturl' => yourls_get_yourls_site() .'/'. $res->keyword, + 'shorturl' => yourls_link($res->keyword), 'url' => $res->url, 'title' => $res->title, 'timestamp'=> $res->timestamp, @@ -275,6 +275,38 @@ function yourls_redirect_shorturl($url, $keyword) { yourls_redirect( $url, 301 ); } +/** + * Send headers to explicitely tell browser not to cache content or redirection + * + * @since 1.7.10 + * @return void + */ +function yourls_no_cache_headers() { + if( !headers_sent() ) { + header( 'Expires: Thu, 23 Mar 1972 07:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-cache, must-revalidate, max-age=0' ); + header( 'Pragma: no-cache' ); + } +} + +/** + * Send a filerable content type header + * + * @since 1.7 + * @param string $type content type ('text/html', 'application/json', ...) + * @return bool whether header was sent + */ +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; +} + /** * Set HTTP status header * diff --git a/includes/vendor/composer/autoload_files.php b/includes/vendor/composer/autoload_files.php index 889bcd21..2a32a791 100644 --- a/includes/vendor/composer/autoload_files.php +++ b/includes/vendor/composer/autoload_files.php @@ -6,6 +6,8 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname(dirname($vendorDir)); return array( - 'b45b351e6b6f7487d819961fef2fda77' => $vendorDir . '/jakeasmith/http_build_url/src/http_build_url.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', + 'b45b351e6b6f7487d819961fef2fda77' => $vendorDir . '/jakeasmith/http_build_url/src/http_build_url.php', + 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', ); diff --git a/includes/vendor/composer/autoload_psr4.php b/includes/vendor/composer/autoload_psr4.php index 1942fdd0..79815d29 100644 --- a/includes/vendor/composer/autoload_psr4.php +++ b/includes/vendor/composer/autoload_psr4.php @@ -7,7 +7,9 @@ $baseDir = dirname(dirname($vendorDir)); return array( 'YOURLS\\' => array($baseDir . '/includes'), + 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), 'POMO\\' => array($vendorDir . '/pomo/pomo/src'), 'MaxMind\\WebService\\' => array($vendorDir . '/maxmind/web-service-common/src/WebService'), 'MaxMind\\Exception\\' => array($vendorDir . '/maxmind/web-service-common/src/Exception'), diff --git a/includes/vendor/composer/autoload_static.php b/includes/vendor/composer/autoload_static.php index a5ba01b4..74e42142 100644 --- a/includes/vendor/composer/autoload_static.php +++ b/includes/vendor/composer/autoload_static.php @@ -7,8 +7,10 @@ namespace Composer\Autoload; class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 { public static $files = array ( - 'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', + 'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php', + 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', ); public static $prefixLengthsPsr4 = array ( @@ -18,7 +20,9 @@ class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 ), 'S' => array ( + 'Symfony\\Polyfill\\Php72\\' => 23, 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, ), 'P' => array ( @@ -49,10 +53,18 @@ class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 array ( 0 => __DIR__ . '/../../..' . '/includes', ), + 'Symfony\\Polyfill\\Php72\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', + ), 'Symfony\\Polyfill\\Mbstring\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', ), + 'Symfony\\Polyfill\\Intl\\Idn\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn', + ), 'POMO\\' => array ( 0 => __DIR__ . '/..' . '/pomo/pomo/src', diff --git a/includes/vendor/composer/installed.json b/includes/vendor/composer/installed.json index 9d39b11b..c7af33cd 100644 --- a/includes/vendor/composer/installed.json +++ b/includes/vendor/composer/installed.json @@ -514,6 +514,70 @@ "sockets" ] }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.17.0", + "version_normalized": "1.17.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "3bff59ea7047e925be6b7f2059d60af31bb46d6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/3bff59ea7047e925be6b7f2059d60af31bb46d6a", + "reference": "3bff59ea7047e925be6b7f2059d60af31bb46d6a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2020-05-12T16:47:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ] + }, { "name": "symfony/polyfill-mbstring", "version": "v1.15.0", @@ -574,5 +638,62 @@ "portable", "shim" ] + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.17.0", + "version_normalized": "1.17.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "f048e612a3905f34931127360bdd2def19a5e582" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/f048e612a3905f34931127360bdd2def19a5e582", + "reference": "f048e612a3905f34931127360bdd2def19a5e582", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2020-05-12T16:47:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ] } ] diff --git a/includes/vendor/symfony/polyfill-intl-idn/Idn.php b/includes/vendor/symfony/polyfill-intl-idn/Idn.php new file mode 100644 index 00000000..f54ffd53 --- /dev/null +++ b/includes/vendor/symfony/polyfill-intl-idn/Idn.php @@ -0,0 +1,287 @@ + + * @author Sebastian Kroczek
+ * @author Dariusz Rumiński
' + data.url.display_url + '';
} else {
@@ -155,6 +156,7 @@ function edit_link_save(id) {
$("#url-" + id).html(display_link);
$("#keyword-" + id).html('' + data.url.keyword + '');
$("#edit-" + id).fadeOut(200, function(){
+ $("#edit-" + id).remove();
$('#main_table tbody').trigger("update");
});
$('#keyword_'+id).val( newkeyword );
@@ -212,7 +214,7 @@ function toggle_share(id) {
var longurl = link.attr('href');
var title = link.attr('title');
var shorturl = $('#keyword-'+id+' a:first').attr('href');
-
+
toggle_share_fill_boxes( longurl, shorturl, title );
}
diff --git a/js/jquery-1.3.2.min.js b/js/jquery-1.3.2.min.js
deleted file mode 100644
index b1ae21d8..00000000
--- a/js/jquery-1.3.2.min.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * jQuery JavaScript Library v1.3.2
- * http://jquery.com/
- *
- * Copyright (c) 2009 John Resig
- * Dual licensed under the MIT and GPL licenses.
- * http://docs.jquery.com/License
- *
- * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
- * Revision: 6246
- */
-(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F","
"]||!O.indexOf("",""]||(!O.indexOf(" "," "]||!O.indexOf("a';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("").append(M.responseText.replace(/