diff --git a/admin/admin-ajax.php b/admin/admin-ajax.php new file mode 100644 index 0000000..77f68ac --- /dev/null +++ b/admin/admin-ajax.php @@ -0,0 +1,53 @@ + $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; + + case 'logout': + // unused for the moment + yourls_logout(); + break; + + default: + yourls_do_action( 'yourls_ajax_'.$action ); + +} + +die(); diff --git a/admin/index.php b/admin/index.php new file mode 100644 index 0000000..9a6d688 --- /dev/null +++ b/admin/index.php @@ -0,0 +1,324 @@ + '', 'binds' => array()); +/** + * $where will collect additional SQL arguments: + * - $where['sql'] will concatenate SQL clauses: $where['sql'] .= ' AND something = :value '; + * - $where['binds'] will hold the (name => value) placeholder pairs: $where['binds']['value'] = $value; + */ + +// SQL behavior (sorting, searching...) +$view_params = new YOURLS\Views\AdminParams(); +/** + * This class gets all the parameters from the query string. It contains a lot of filters : if you need to modify + * something with a plugin, head to this file instead. + */ + +// Pagination +$page = $view_params->get_page(); +$perpage = $view_params->get_per_page(15); + +// Searching +$search = $view_params->get_search(); +$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 . '*' ); + 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 + } else { + $where['sql'] .= " AND `$search_in` LIKE (:search)"; + } + $where['binds']['search'] = $search; +} + +// Time span +$date_params = $view_params->get_date_params(); +$date_filter = $date_params['date_filter']; +$date_first = $date_params['date_first']; +$date_second = $date_params['date_second']; +switch( $date_filter ) { + case 'before': + if( $date_first ) { + $date_first_sql = yourls_sanitize_date_for_sql( $date_first ); + $where['sql'] .= ' AND `timestamp` < :date_first_sql'; + $where['binds']['date_first_sql'] = $date_first_sql; + } + break; + case 'after': + if( $date_first ) { + $date_first_sql = yourls_sanitize_date_for_sql( $date_first ); + $where['sql'] .= ' AND `timestamp` > :date_first_sql'; + $where['binds']['date_first_sql'] = $date_first_sql; + } + break; + case 'between': + if( $date_first && $date_second ) { + $date_first_sql = yourls_sanitize_date_for_sql( $date_first ); + $date_second_sql = yourls_sanitize_date_for_sql( $date_second ); + $where['sql'] .= ' AND `timestamp` BETWEEN :date_first_sql AND :date_second_sql'; + $where['binds']['date_first_sql'] = $date_first_sql; + $where['binds']['date_second_sql'] = $date_second_sql; + } + break; +} + +// Sorting +$sort_by = $view_params->get_sort_by(); +$sort_order = $view_params->get_sort_order(); +$sort_by_text = $view_params->get_param_long_name($sort_by); + +// Click filtering +$click_limit = $view_params->get_click_limit(); +if ( $click_limit !== '' ) { + $click_filter = $view_params->get_click_filter(); + $click_moreless = ($click_filter == 'more' ? '>' : '<'); + $where['sql'] .= " AND clicks $click_moreless :click_limit"; + $where['binds']['click_limit'] = $click_limit; +} else { + $click_filter = ''; +} + + +// 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 ) ); +} else { + $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 = urldecode( $_GET['u'] ); + } else { + // New style bookmarklet: ?up=&us=&ur= + $url = urldecode( $_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; + } + } + +// 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 ); + } + + // Determing Total Amount Of Pages + $total_pages = ceil( $total_items / $perpage ); +} + + +// Begin output of the page +$context = ( $is_bookmark ? 'bookmark' : 'index' ); +yourls_html_head( $context ); +yourls_html_logo(); +yourls_html_menu() ; + +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 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(); + });'; +} + +yourls_do_action( 'admin_page_before_table' ); + +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 ); +} + +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'] ); +$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 ); + } +} + +$display = $found_rows ? 'display:none' : ''; +echo '' . yourls__('No URL') . ''; + +yourls_table_tbody_end(); + +yourls_table_end(); + +yourls_do_action( 'admin_page_after_table' ); + +if ( $is_bookmark ) + yourls_share_box( $url, $return['shorturl'], $title, $text ); +?> + + diff --git a/admin/plugins.php b/admin/plugins.php new file mode 100644 index 0000000..123f630 --- /dev/null +++ b/admin/plugins.php @@ -0,0 +1,165 @@ + + +
+

+ + + +

%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.' ); ?>

+
+ + diff --git a/admin/tools.php b/admin/tools.php new file mode 100644 index 0000000..accb8c1 --- /dev/null +++ b/admin/tools.php @@ -0,0 +1,340 @@ + + +
+ +

+ +

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.' ); ?>
  • + +
  • 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.' ); ?>
  • + +
  • 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" ); + ?>

+ +

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()) . '/' ); ?>

+ +

.

+ + + + +

+ +

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() ); ?> +

+ +

+ +
    +
  • +

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

    +

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

    +
  • + +
  • +
    <?php
    +$timestamp = time();
    +//  $time = 
    +$signature = md5( $timestamp . '' );
    +//  $signature = ""
    +?>
    +
    +

    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' ); ?>

+ +
+ + + + diff --git a/admin/upgrade.php b/admin/upgrade.php new file mode 100644 index 0000000..8133324 --- /dev/null +++ b/admin/upgrade.php @@ -0,0 +1,85 @@ + +

+' . 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! + */ + + // 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; + + // Verbose & ugly details + yourls_debug_mode(true); + + // 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 :)' ); ?>

+

+ + + + + + + + "; + + 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') ) . '

'; + } + +} + +?> + +