init
1
install
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#!/bin/bash
|
114
source/CHANGELOG.md
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
YOURLS Changelog
|
||||||
|
================
|
||||||
|
|
||||||
|
_This file lists the main changes through all versions of YOURLS.
|
||||||
|
For a much more detailed list, simply refer to [commit messages](https://github.com/YOURLS/YOURLS/commits/master)._
|
||||||
|
|
||||||
|
1.7
|
||||||
|
---
|
||||||
|
- added: support for PDO and MySQLi
|
||||||
|
- added: social bookmarklets - share on Twitter, Facebook or Tumblr in a click
|
||||||
|
- added: check api.yourls.org if a new version of YOURLS is available
|
||||||
|
- added: proxy support - install YOURLS behind a firewall!
|
||||||
|
- improved: security regarding SQL injections
|
||||||
|
- improved: security regarding your credentials - now auto-encrypted
|
||||||
|
- improved: external HTTP request handling
|
||||||
|
- improved: ƒυηкƴ UTF-8 titles handling
|
||||||
|
- fixed: compatibility with Apache mod_security blocking bookmarklets
|
||||||
|
- fixed: lots of bugs
|
||||||
|
|
||||||
|
1.6
|
||||||
|
---
|
||||||
|
- added: مرحبا العالم! Hej verden! 你好世界! Kumusta mundo! Ciao mondo! Hello world! Translation API.
|
||||||
|
- added: custom API actions
|
||||||
|
- added: support for URLs with common protocols
|
||||||
|
- fixed: search and pagination in the admin interface
|
||||||
|
- updated: third party libs jQuery, ezSQL, GeoIP
|
||||||
|
- improved: sanitizing and escaping functions
|
||||||
|
|
||||||
|
1.5.1
|
||||||
|
-----
|
||||||
|
- added: full jsonp support
|
||||||
|
- added: ability to use encrypted passwords in the config file
|
||||||
|
- fixed: support for http://www.sho.rt/bleh and http://sho.rt/bleh
|
||||||
|
- added: support for any favicon dropped in the /user directory
|
||||||
|
- updated: Google Visualization API instead of deprecated Google Charts
|
||||||
|
- fixed: bugs, bugs, bugs
|
||||||
|
- added: hooks, hooks, hooks
|
||||||
|
- improved: things, things, things
|
||||||
|
|
||||||
|
1.5
|
||||||
|
---
|
||||||
|
- added: plugin architecture! OMG plugins!!1!!1!
|
||||||
|
- added: directory /user, config.php can be moved there
|
||||||
|
- added: new "instant bookmarklets"
|
||||||
|
- added: 1 click copy-to-clipboard a la bitly
|
||||||
|
- change in logic: now all request are handled by PHP and don't rely on .htaccess
|
||||||
|
- added: saving URL titles
|
||||||
|
- added: support for prefix-n-shorten: sho.rt/http://example.com/
|
||||||
|
- added: core plugin to allow hyphens in URLs
|
||||||
|
- added: core sample plugin to wrap redirected URLs in a social toolbar
|
||||||
|
- added: core sample plugin to show how to create administration page in plugins
|
||||||
|
- added: core plugin to display a random pretty background
|
||||||
|
- changed: layout now using a more consistent palette, see http://yourls.org/palette
|
||||||
|
- added: anti XSS and anti CSRF measures
|
||||||
|
- added: interactive map if possible in stat traffic by countries
|
||||||
|
- fixed: lots of bugs
|
||||||
|
|
||||||
|
1.4.3
|
||||||
|
-----
|
||||||
|
- fixed bug no-stats-showing-ffs due to inconsistency in DB schema
|
||||||
|
- improve error reporting with API method url-stat
|
||||||
|
|
||||||
|
1.4.2
|
||||||
|
-----
|
||||||
|
- fixed: bug in auth function
|
||||||
|
- added: sample public API file
|
||||||
|
- added: check in API requests for WordPress plugin when adding a new short URL
|
||||||
|
- prettier sample public interface
|
||||||
|
|
||||||
|
1.4.1
|
||||||
|
-----
|
||||||
|
- fixed: base 62 URLs (keywords with MiXeD CaSe)
|
||||||
|
- new & secure auth method for API calls, with no need to use login & password combo
|
||||||
|
- allow SSL enforcement for admin pages
|
||||||
|
- new API method: stats for individual URL.
|
||||||
|
- prevent internal redirection loops
|
||||||
|
- filter and search URLs & short URLs by date
|
||||||
|
|
||||||
|
1.4
|
||||||
|
---
|
||||||
|
- added: an upgrader from 1.3 to 1.4
|
||||||
|
- change in logic: now using a global object $ydb for everything related to DB and other globally needed stuff
|
||||||
|
- change in logic: include "load-yourls.php" instead of "config.php" to start engine
|
||||||
|
- change in DB schema: now storing URLs with their keyword as used in shorturl, allowing for any keyword length
|
||||||
|
- change in DB schema: new table for storing various options including next_id, dropping table of the same name
|
||||||
|
- change in DB schema: new table for storing hits (for stats)
|
||||||
|
- improved the installer, with .htaccess file creation
|
||||||
|
- layout tweak: now prettier, isn't it?
|
||||||
|
- stats! OMG stats!
|
||||||
|
|
||||||
|
1.3-RC1
|
||||||
|
-------
|
||||||
|
- added bookmarklet and tools page
|
||||||
|
- improved XSS filter when adding new URL
|
||||||
|
- code cleanup in admin/index.php to separate code and display
|
||||||
|
- added favicon
|
||||||
|
- stricter coding to prevent notices with undefined indexes
|
||||||
|
- hide PHP notices & SQL errors & warnings, unless YOURLS_DEBUG constant set to true
|
||||||
|
|
||||||
|
1.2
|
||||||
|
---
|
||||||
|
- don't remember. A few tiny stuff for sure.
|
||||||
|
|
||||||
|
1.1
|
||||||
|
---
|
||||||
|
- don't remember. Some little bugs I guess.
|
||||||
|
|
||||||
|
1.0.1
|
||||||
|
-----
|
||||||
|
- don't remember. Trivial stuff probably.
|
||||||
|
|
||||||
|
1.0
|
||||||
|
---
|
||||||
|
- initial release
|
47
source/CONTRIBUTING.md
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
Contributing to YOURLS
|
||||||
|
======================
|
||||||
|
|
||||||
|
Please take a moment to review this document, or see your issue / pull request closed with *harsh comments* :-)
|
||||||
|
|
||||||
|
Following these guidelines helps to communicate that you respect the time of
|
||||||
|
the developers managing and developing for free this open source project during their free time.
|
||||||
|
Thank you for this, and in return we will reciprocate that respect in addressing your issue
|
||||||
|
or assessing patches with goodwill.
|
||||||
|
|
||||||
|
Search before
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The issue tracker is the preferred channel for bug reports, features requests and submitting pull
|
||||||
|
requests, but please respect the following restrictions:
|
||||||
|
|
||||||
|
* Please **do not** use the issue tracker for personal support requests. Use sites such as
|
||||||
|
[Stack Overflow](http://stackoverflow.com) instead.
|
||||||
|
* Please, please, please, **SEARCH** before you file a new issue or request.
|
||||||
|
|
||||||
|
Guidelines
|
||||||
|
----------
|
||||||
|
|
||||||
|
Before using the issue tracker, we require you read the specific guidelines, depending on the topic:
|
||||||
|
a bug report, a feature request or a pull request.
|
||||||
|
|
||||||
|
### Bug Report
|
||||||
|
|
||||||
|
Good bug reports are extremely helpful - thank you! Good bug reports are also quite rare.
|
||||||
|
To help and raise the bug report quality, **you _must_ read the wiki document about [Bug Reports](https://github.com/YOURLS/YOURLS/wiki/Bug-Report).**
|
||||||
|
|
||||||
|
### Feature Request
|
||||||
|
|
||||||
|
Feature requests are welcome. But take a moment to find out whether your idea fits the scope and
|
||||||
|
goals of the project. Check also the [Roadmap](https://github.com/YOURLS/YOURLS/wiki/Road-Map),
|
||||||
|
maybe your idea is already planned.
|
||||||
|
|
||||||
|
It's up to you to make a strong case to convince the project's developers of the merits of this feature.
|
||||||
|
Please provide as much detail and context as possible and get in touch. Feel free to detail how you envision
|
||||||
|
things, be they about (pseudo)code, interface, mockup, etc...
|
||||||
|
|
||||||
|
### Pull Request
|
||||||
|
|
||||||
|
Good pull requests are a fantastic help. But please get in touch before you start working,
|
||||||
|
it's always a sad moment to dismiss a patch for which a coder has spent a lot of time because
|
||||||
|
it simply does not fit the project. Please read the wiki
|
||||||
|
document about [Pull requests](https://github.com/YOURLS/YOURLS/wiki/Pull-Request).
|
45
source/LICENSE.md
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
__ ______ _ _ _____ _ _____
|
||||||
|
\ \ / / __ \| | | | __ \| | / ____|
|
||||||
|
\ \_/ / | | | | | | |__) | | | (___
|
||||||
|
\ /| | | | | | | _ /| | \___ \
|
||||||
|
| | | |__| | |__| | | \ \| |____ ____) |
|
||||||
|
|_| \____/ \____/|_| \_\______|_____/
|
||||||
|
|
||||||
|
|
||||||
|
YOURLS - Your Own URL Shortener
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Copyright (c) 2009-2013 by the contributors
|
||||||
|
|
||||||
|
This program is free software. Do whatever the hell you want with it.
|
||||||
|
|
||||||
|
This program is distributed under the terms of the MIT license, in the
|
||||||
|
hope that it will be useful and/or fun to use. There is absolutely no
|
||||||
|
guarantee of any kind about anything.
|
||||||
|
|
||||||
|
Wherever third party code has been used, credit has been given in the
|
||||||
|
code comments.
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Copyright (c) 2009-2013 by the contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
40
source/README.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
![yourls](images/yourls-logo.png)
|
||||||
|
[YOURLS](http://yourls.org) — [![Build Status](https://travis-ci.org/YOURLS/YOURLS.png?branch=master)](https://travis-ci.org/YOURLS/YOURLS)
|
||||||
|
========
|
||||||
|
**YOURLS** is a set of PHP scripts that will allow you to run Your Own URL Shortener. You'll have full control over your data, detailed stats and analytics, plugins, and more. It's free.
|
||||||
|
|
||||||
|
Quick Start
|
||||||
|
-----------
|
||||||
|
To get started, check [yourls.org](http://yourls.org)!
|
||||||
|
Learn more tweaks in the [Wiki documentation](https://github.com/YOURLS/YOURLS/wiki/).
|
||||||
|
|
||||||
|
News
|
||||||
|
----
|
||||||
|
Keep track of development and community news.
|
||||||
|
|
||||||
|
* Follow [@yourls on Twitter](http://twitter.com/yourls).
|
||||||
|
* Read and subscribe to the [The Official YOURLS Blog](http://blog.yourls.org).
|
||||||
|
* Check [commit messages](https://github.com/YOURLS/YOURLS/commits/master).
|
||||||
|
|
||||||
|
Versioning
|
||||||
|
----------
|
||||||
|
For transparency and insight into our release cycle, and for striving to maintain backward compatibility, YOURLS will be maintained under the [Semantic Versioning](http://semver.org) guidelines as much as possible.
|
||||||
|
|
||||||
|
Releases will be numbered with the following format: `<major>.<minor>.<patch>`
|
||||||
|
|
||||||
|
And constructed with the following guidelines:
|
||||||
|
* Breaking backward compatibility bumps the major (and resets the minor and patch)
|
||||||
|
* New additions without breaking backward compatibility bumps the minor (and resets the patch)
|
||||||
|
* Bug fixes and misc changes bumps the patch
|
||||||
|
|
||||||
|
*[Release Archive](https://github.com/YOURLS/YOURLS/releases)*
|
||||||
|
|
||||||
|
Bug Tracker
|
||||||
|
-----------
|
||||||
|
Have a bug or a feature request? [Please open a new issue](https://github.com/YOURLS/YOURLS/issues).
|
||||||
|
__Before opening any issue, please search for existing issues and read the [Issue Guidelines](https://github.com/YOURLS/YOURLS/wiki/Bug-Report).__
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
Free software. Do whatever the hell you want with it.
|
||||||
|
The [license](LICENSE.md) under which YOURLS is released is the MIT license.
|
51
source/admin/admin-ajax.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
define( 'YOURLS_ADMIN', true );
|
||||||
|
define( 'YOURLS_AJAX', true );
|
||||||
|
require_once( dirname( dirname( __FILE__ ) ) .'/includes/load-yourls.php' );
|
||||||
|
yourls_maybe_require_auth();
|
||||||
|
|
||||||
|
// This file will output a JSON string
|
||||||
|
yourls_content_type_header( 'application/json' );
|
||||||
|
|
||||||
|
if( !isset( $_REQUEST['action'] ) )
|
||||||
|
die();
|
||||||
|
|
||||||
|
// Pick action
|
||||||
|
$action = $_REQUEST['action'];
|
||||||
|
switch( $action ) {
|
||||||
|
|
||||||
|
case 'add':
|
||||||
|
yourls_verify_nonce( 'add_url', $_REQUEST['nonce'], false, 'omg error' );
|
||||||
|
$return = yourls_add_new_link( $_REQUEST['url'], $_REQUEST['keyword'] );
|
||||||
|
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'] );
|
||||||
|
echo json_encode( array('html' => $row) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'edit_save':
|
||||||
|
yourls_verify_nonce( 'edit-save_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' );
|
||||||
|
$return = yourls_edit_link( $_REQUEST['url'], $_REQUEST['keyword'], $_REQUEST['newkeyword'], $_REQUEST['title'] );
|
||||||
|
echo json_encode($return);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'delete':
|
||||||
|
yourls_verify_nonce( 'delete-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' );
|
||||||
|
$query = yourls_delete_link_by_keyword( $_REQUEST['keyword'] );
|
||||||
|
echo json_encode(array('success'=>$query));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'logout':
|
||||||
|
// unused for the moment
|
||||||
|
yourls_logout();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
yourls_do_action( 'yourls_ajax_'.$action );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
die();
|
349
source/admin/index.php
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
<?php
|
||||||
|
define( 'YOURLS_ADMIN', true );
|
||||||
|
require_once( dirname( dirname( __FILE__ ) ).'/includes/load-yourls.php' );
|
||||||
|
yourls_maybe_require_auth();
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
$table_url = YOURLS_DB_TABLE_URL;
|
||||||
|
$where = $search_sentence = $search_text = $url = $keyword = '';
|
||||||
|
$date_filter = $date_first = $date_second = '';
|
||||||
|
$base_page = yourls_admin_url( 'index.php' );
|
||||||
|
|
||||||
|
// Default SQL behavior
|
||||||
|
$search_in_text = yourls__( 'URL' );
|
||||||
|
$search_in = 'url';
|
||||||
|
$sort_by_text = yourls__( 'Short URL' );
|
||||||
|
$sort_by = 'timestamp';
|
||||||
|
$sort_order = 'desc';
|
||||||
|
$page = ( isset( $_GET['page'] ) ? intval($_GET['page']) : 1 );
|
||||||
|
$search = yourls_get_search_text();
|
||||||
|
$perpage = ( isset( $_GET['perpage'] ) && intval( $_GET['perpage'] ) ? intval($_GET['perpage']) : 15 );
|
||||||
|
$click_limit = ( isset( $_GET['click_limit'] ) && $_GET['click_limit'] !== '' ) ? intval( $_GET['click_limit'] ) : '' ;
|
||||||
|
if ( $click_limit !== '' ) {
|
||||||
|
$click_filter = ( isset( $_GET['click_filter'] ) && $_GET['click_filter'] == 'more' ? 'more' : 'less' ) ;
|
||||||
|
$click_moreless = ( $click_filter == 'more' ? '>' : '<' );
|
||||||
|
$where = " AND clicks $click_moreless $click_limit";
|
||||||
|
} else {
|
||||||
|
$click_filter = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searching
|
||||||
|
if( !empty( $search ) && !empty( $_GET['search_in'] ) ) {
|
||||||
|
switch( $_GET['search_in'] ) {
|
||||||
|
case 'keyword':
|
||||||
|
$search_in_text = yourls__( 'Short URL' );
|
||||||
|
$search_in = 'keyword';
|
||||||
|
break;
|
||||||
|
case 'url':
|
||||||
|
$search_in_text = yourls__( 'URL' );
|
||||||
|
$search_in = 'url';
|
||||||
|
break;
|
||||||
|
case 'title':
|
||||||
|
$search_in_text = yourls__( 'Title' );
|
||||||
|
$search_in = 'title';
|
||||||
|
break;
|
||||||
|
case 'ip':
|
||||||
|
$search_in_text = yourls__( 'IP Address' );
|
||||||
|
$search_in = 'ip';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$search_sentence = yourls_s( 'Searching for <strong>%1$s</strong> in <strong>%2$s</strong>.', yourls_esc_html( $search ), yourls_esc_html( $search_in_text ) );
|
||||||
|
$search_url = yourls_sanitize_url( "&search=$search&search_in=$search_in" );
|
||||||
|
$search_text = $search;
|
||||||
|
$search = str_replace( '*', '%', '*' . yourls_escape( $search ) . '*' );
|
||||||
|
$where .= " AND `$search_in` LIKE ('$search')";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time span
|
||||||
|
if( !empty( $_GET['date_filter'] ) ) {
|
||||||
|
switch( $_GET['date_filter'] ) {
|
||||||
|
case 'before':
|
||||||
|
$date_filter = 'before';
|
||||||
|
if( isset( $_GET['date_first'] ) && yourls_sanitize_date( $_GET['date_first'] ) ) {
|
||||||
|
$date_first = yourls_sanitize_date( $_GET['date_first'] );
|
||||||
|
$date_first_sql = yourls_sanitize_date_for_sql( $_GET['date_first'] );
|
||||||
|
$where .= " AND `timestamp` < '$date_first_sql'";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'after':
|
||||||
|
$date_filter = 'after';
|
||||||
|
if( isset( $_GET['date_first'] ) && yourls_sanitize_date( $_GET['date_first'] ) ) {
|
||||||
|
$date_first_sql = yourls_sanitize_date_for_sql( $_GET['date_first'] );
|
||||||
|
$date_first = yourls_sanitize_date( $_GET['date_first'] );
|
||||||
|
$where .= " AND `timestamp` > '$date_first_sql'";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'between':
|
||||||
|
$date_filter = 'between';
|
||||||
|
if( isset( $_GET['date_first'] ) && isset( $_GET['date_second'] ) && yourls_sanitize_date( $_GET['date_first'] ) && yourls_sanitize_date( $_GET['date_second'] ) ) {
|
||||||
|
$date_first_sql = yourls_sanitize_date_for_sql( $_GET['date_first'] );
|
||||||
|
$date_second_sql = yourls_sanitize_date_for_sql( $_GET['date_second'] );
|
||||||
|
$date_first = yourls_sanitize_date( $_GET['date_first'] );
|
||||||
|
$date_second = yourls_sanitize_date( $_GET['date_second'] );
|
||||||
|
$where .= " AND `timestamp` BETWEEN '$date_first_sql' AND '$date_second_sql'";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sorting
|
||||||
|
if( !empty( $_GET['sort_by'] ) || !empty( $_GET['sort_order'] ) ) {
|
||||||
|
switch( $_GET['sort_by'] ) {
|
||||||
|
case 'keyword':
|
||||||
|
$sort_by_text = yourls__( 'Short URL' );
|
||||||
|
$sort_by = 'keyword';
|
||||||
|
break;
|
||||||
|
case 'url':
|
||||||
|
$sort_by_text = yourls__( 'URL' );
|
||||||
|
$sort_by = 'url';
|
||||||
|
break;
|
||||||
|
case 'timestamp':
|
||||||
|
$sort_by_text = yourls__( 'Date' );
|
||||||
|
$sort_by = 'timestamp';
|
||||||
|
break;
|
||||||
|
case 'ip':
|
||||||
|
$sort_by_text = yourls__( 'IP Address' );
|
||||||
|
$sort_by = 'ip';
|
||||||
|
break;
|
||||||
|
case 'clicks':
|
||||||
|
$sort_by_text = yourls__( 'Clicks' );
|
||||||
|
$sort_by = 'clicks';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch( $_GET['sort_order'] ) {
|
||||||
|
case 'asc':
|
||||||
|
$sort_order = 'asc';
|
||||||
|
break;
|
||||||
|
case 'desc':
|
||||||
|
$sort_order = 'desc';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get URLs Count for current filter, total links in DB & total clicks
|
||||||
|
list( $total_urls, $total_clicks ) = array_values( yourls_get_db_stats() );
|
||||||
|
if ( $where ) {
|
||||||
|
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>
|
||||||
|
$url = rawurldecode( $_GET['u'] );
|
||||||
|
} else {
|
||||||
|
// New style bookmarklet: ?up=<url protocol>&us=<url slashes>&ur=<url rest>
|
||||||
|
$url = rawurldecode( $_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, '', $ydb );
|
||||||
|
$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 = sprintf( " AND `url` LIKE '%s' ", yourls_escape( $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( "http://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 ) { ?>
|
||||||
|
<p><?php echo $search_sentence; ?></p>
|
||||||
|
<p><?php
|
||||||
|
printf( yourls__( 'Display <strong>%1$s</strong> to <strong class="increment">%2$s</strong> of <strong class="increment">%3$s</strong> URLs' ), $display_on_page, $max_on_page, $total_items );
|
||||||
|
if( $total_items_clicks !== false )
|
||||||
|
echo ", " . sprintf( yourls_n( 'counting <strong>1</strong> click', 'counting <strong>%s</strong> clicks', $total_items_clicks ), yourls_number_format_i18n( $total_items_clicks ) );
|
||||||
|
?>.</p>
|
||||||
|
<?php } ?>
|
||||||
|
<p><?php printf( yourls__( 'Overall, tracking <strong class="increment">%1$s</strong> links, <strong>%2$s</strong> clicks, and counting!' ), yourls_number_format_i18n( $total_urls ), yourls_number_format_i18n( $total_clicks ) ); ?></p>
|
||||||
|
<?php yourls_do_action( 'admin_page_before_form' ); ?>
|
||||||
|
|
||||||
|
<?php yourls_html_addnew(); ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// If bookmarklet, add message. Otherwise, hide hidden share box.
|
||||||
|
if ( !$is_bookmark ) {
|
||||||
|
yourls_share_box( '', '', '', '', '', '', true );
|
||||||
|
} else {
|
||||||
|
echo '<script type="text/javascript">$(document).ready(function(){
|
||||||
|
feedback( "' . $return['message'] . '", "'. $return['status'] .'");
|
||||||
|
init_clipboard();
|
||||||
|
});</script>';
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = $ydb->get_results( "SELECT * FROM `$table_url` WHERE 1=1 $where ORDER BY `$sort_by` $sort_order LIMIT $offset, $perpage;" );
|
||||||
|
$found_rows = false;
|
||||||
|
if( $url_results ) {
|
||||||
|
$found_rows = true;
|
||||||
|
foreach( $url_results as $url_result ) {
|
||||||
|
$keyword = yourls_sanitize_string( $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 '<tr id="nourl_found" style="'.$display.'"><td colspan="6">' . yourls__('No URL') . '</td></tr>';
|
||||||
|
|
||||||
|
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 );
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php yourls_html_footer( ); ?>
|
79
source/admin/install.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
define( 'YOURLS_ADMIN', true );
|
||||||
|
define( 'YOURLS_INSTALLING', true );
|
||||||
|
require_once( dirname(dirname(__FILE__)).'/includes/load-yourls.php' );
|
||||||
|
require_once( YOURLS_INC.'/functions-install.php' );
|
||||||
|
|
||||||
|
$error = array();
|
||||||
|
$warning = array();
|
||||||
|
$success = array();
|
||||||
|
|
||||||
|
// Check pre-requisites
|
||||||
|
if ( !yourls_check_database_version() ) {
|
||||||
|
$error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'MySQL' );
|
||||||
|
yourls_debug_log( 'MySQL version: ' . yourls_get_database_version() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !yourls_check_php_version() ) {
|
||||||
|
$error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'PHP' );
|
||||||
|
yourls_debug_log( 'PHP version: ' . phpversion() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is YOURLS already installed ?
|
||||||
|
if ( yourls_is_installed() ) {
|
||||||
|
$error[] = yourls__( 'YOURLS already installed.' );
|
||||||
|
// check if .htaccess exists, recreate otherwise. No error checking.
|
||||||
|
if( !file_exists( YOURLS_ABSPATH.'/.htaccess' ) ) {
|
||||||
|
yourls_create_htaccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start install if possible and needed
|
||||||
|
if ( isset($_REQUEST['install']) && count( $error ) == 0 ) {
|
||||||
|
// Create/update .htaccess file
|
||||||
|
if ( yourls_create_htaccess() ) {
|
||||||
|
$success[] = yourls__( 'File <tt>.htaccess</tt> successfully created/updated.' );
|
||||||
|
} else {
|
||||||
|
$warning[] = yourls__( 'Could not write file <tt>.htaccess</tt> in YOURLS root directory. You will have to do it manually. See <a href="http://yourls.org/htaccess">how</a>.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SQL tables
|
||||||
|
$install = yourls_create_sql_tables();
|
||||||
|
if ( isset( $install['error'] ) )
|
||||||
|
$error = array_merge( $error, $install['error'] );
|
||||||
|
if ( isset( $install['success'] ) )
|
||||||
|
$success = array_merge( $success, $install['success'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Start output
|
||||||
|
yourls_html_head( 'install', yourls__( 'Install YOURLS' ) );
|
||||||
|
?>
|
||||||
|
<div id="login">
|
||||||
|
<form method="post" action="?"><?php // reset any QUERY parameters ?>
|
||||||
|
<p>
|
||||||
|
<img src="<?php yourls_site_url(); ?>/images/yourls-logo.png" alt="YOURLS" title="YOURLS" />
|
||||||
|
</p>
|
||||||
|
<?php
|
||||||
|
// Print errors, warnings and success messages
|
||||||
|
foreach ( array ('error', 'warning', 'success') as $info ) {
|
||||||
|
if ( count( $$info ) > 0 ) {
|
||||||
|
echo "<ul class='$info'>";
|
||||||
|
foreach( $$info as $msg ) {
|
||||||
|
echo '<li>'.$msg."</li>\n";
|
||||||
|
}
|
||||||
|
echo '</ul>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display install button or link to admin area if applicable
|
||||||
|
if( !yourls_is_installed() && !isset($_REQUEST['install']) ) {
|
||||||
|
echo '<p style="text-align: center;"><input type="submit" name="install" value="' . yourls__( 'Install YOURLS') .'" class="button" /></p>';
|
||||||
|
} else {
|
||||||
|
if( count($error) == 0 )
|
||||||
|
echo '<p style="text-align: center;">» <a href="'.yourls_admin_url().'" title="' . yourls__( 'YOURLS Administration Page') . '">' . yourls__( 'YOURLS Administration Page') . '</a></p>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<?php yourls_html_footer(); ?>
|
164
source/admin/plugins.php
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
<?php
|
||||||
|
define( 'YOURLS_ADMIN', true );
|
||||||
|
require_once( dirname( dirname( __FILE__ ) ).'/includes/load-yourls.php' );
|
||||||
|
yourls_maybe_require_auth();
|
||||||
|
|
||||||
|
// Handle plugin administration pages
|
||||||
|
if( isset( $_GET['page'] ) && !empty( $_GET['page'] ) ) {
|
||||||
|
yourls_plugin_admin_page( $_GET['page'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle activation/deactivation of plugins
|
||||||
|
if( isset( $_GET['action'] ) ) {
|
||||||
|
|
||||||
|
// Check nonce
|
||||||
|
yourls_verify_nonce( 'manage_plugins', $_REQUEST['nonce'] );
|
||||||
|
|
||||||
|
// Check plugin file is valid
|
||||||
|
if( isset( $_GET['plugin'] ) && yourls_validate_plugin_file( YOURLS_PLUGINDIR.'/'.$_GET['plugin'].'/plugin.php') ) {
|
||||||
|
|
||||||
|
global $ydb;
|
||||||
|
// Activate / Deactive
|
||||||
|
switch( $_GET['action'] ) {
|
||||||
|
case 'activate':
|
||||||
|
$result = yourls_activate_plugin( $_GET['plugin'].'/plugin.php' );
|
||||||
|
if( $result === true )
|
||||||
|
yourls_redirect( yourls_admin_url( 'plugins.php?success=activated' ), 302 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'deactivate':
|
||||||
|
$result = yourls_deactivate_plugin( $_GET['plugin'].'/plugin.php' );
|
||||||
|
if( $result === true )
|
||||||
|
yourls_redirect( yourls_admin_url( 'plugins.php?success=deactivated' ), 302 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$result = yourls__( 'Unsupported action' );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result = yourls__( 'No plugin specified, or not a valid plugin' );
|
||||||
|
}
|
||||||
|
|
||||||
|
yourls_add_notice( $result );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle message upon succesfull (de)activation
|
||||||
|
if( isset( $_GET['success'] ) && ( ( $_GET['success'] == 'activated' ) OR ( $_GET['success'] == 'deactivated' ) ) ) {
|
||||||
|
if( $_GET['success'] == 'activated' ) {
|
||||||
|
$message = yourls__( 'Plugin has been activated' );
|
||||||
|
} elseif ( $_GET['success'] == 'deactivated' ) {
|
||||||
|
$message = yourls__( 'Plugin has been deactivated' );
|
||||||
|
}
|
||||||
|
yourls_add_notice( $message );
|
||||||
|
}
|
||||||
|
|
||||||
|
yourls_html_head( 'plugins', yourls__( 'Manage Plugins' ) );
|
||||||
|
yourls_html_logo();
|
||||||
|
yourls_html_menu();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<h2><?php yourls_e( 'Plugins' ); ?></h2>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$plugins = (array)yourls_get_plugins();
|
||||||
|
uasort( $plugins, 'yourls_plugins_sort_callback' );
|
||||||
|
|
||||||
|
$count = count( $plugins );
|
||||||
|
$plugins_count = sprintf( yourls_n( '%s plugin', '%s plugins', $count ), $count );
|
||||||
|
$count_active = yourls_has_active_plugins();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<p id="plugin_summary"><?php /* //translators: "you have '3 plugins' installed and '1' activated" */ yourls_se( 'You currently have <strong>%1$s</strong> installed, and <strong>%2$s</strong> activated', $plugins_count, $count_active ); ?></p>
|
||||||
|
|
||||||
|
<table id="main_table" class="tblSorter" cellpadding="0" cellspacing="1">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><?php yourls_e( 'Plugin Name' ); ?></th>
|
||||||
|
<th><?php yourls_e( 'Version' ); ?></th>
|
||||||
|
<th><?php yourls_e( 'Description' ); ?></th>
|
||||||
|
<th><?php yourls_e( 'Author' ); ?></th>
|
||||||
|
<th><?php yourls_e( 'Action' ); ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$nonce = yourls_create_nonce( 'manage_plugins' );
|
||||||
|
|
||||||
|
foreach( $plugins as $file=>$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 ] = '(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 ) ) );
|
||||||
|
$action_anchor = yourls__( 'Deactivate' );
|
||||||
|
} else {
|
||||||
|
$class = 'inactive';
|
||||||
|
$action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'activate', 'plugin' => $plugindir ) ) );
|
||||||
|
$action_anchor = yourls__( 'Activate' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other "Fields: Value" in the header? Get them too
|
||||||
|
if( $plugin ) {
|
||||||
|
foreach( $plugin as $extra_field=>$extra_value ) {
|
||||||
|
$data['desc'] .= "<br/>\n<em>$extra_field</em>: $extra_value";
|
||||||
|
unset( $plugin[$extra_value] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['desc'] .= '<br/><small>' . yourls_s( 'plugin file location: %s', $file) . '</small>';
|
||||||
|
|
||||||
|
printf( "<tr class='plugin %s'><td class='plugin_name'><a href='%s'>%s</a></td><td class='plugin_version'>%s</td><td class='plugin_desc'>%s</td><td class='plugin_author'><a href='%s'>%s</a></td><td class='plugin_actions actions'><a href='%s'>%s</a></td></tr>",
|
||||||
|
$class, $data['uri'], $data['name'], $data['version'], $data['desc'], $data['author_uri'], $data['author'], $action_url, $action_anchor
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
yourls_defaultsort = 0;
|
||||||
|
yourls_defaultorder = 0;
|
||||||
|
<?php if ($count_active) { ?>
|
||||||
|
$('#plugin_summary').append('<span id="toggle_plugins">filter</span>');
|
||||||
|
$('#toggle_plugins').css({'background':'transparent url("../images/filter.gif") top left no-repeat','display':'inline-block','text-indent':'-9999px','width':'16px','height':'16px','margin-left':'3px','cursor':'pointer'})
|
||||||
|
.attr('title', '<?php echo yourls_esc_attr__( 'Toggle active/inactive plugins' ); ?>')
|
||||||
|
.click(function(){
|
||||||
|
$('#main_table tr.inactive').toggle();
|
||||||
|
});
|
||||||
|
<?php } ?>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p><?php yourls_e( 'If something goes wrong after you activate a plugin and you cannot use YOURLS or access this page, simply rename or delete its directory, or rename the plugin file to something different than <code>plugin.php</code>.' ); ?></p>
|
||||||
|
|
||||||
|
<h3><?php yourls_e( 'More plugins' ); ?></h3>
|
||||||
|
|
||||||
|
<p><?php yourls_e( 'For more plugins, head to the official <a href="http://yourls.org/pluginlist">Plugin list</a>.' ); ?></p>
|
||||||
|
|
||||||
|
|
||||||
|
<?php yourls_html_footer(); ?>
|
136
source/admin/tools.php
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
define( 'YOURLS_ADMIN', true );
|
||||||
|
require_once( dirname( dirname( __FILE__ ) ).'/includes/load-yourls.php' );
|
||||||
|
yourls_maybe_require_auth();
|
||||||
|
|
||||||
|
yourls_html_head( 'tools', yourls__( 'Cool YOURLS Tools' ) );
|
||||||
|
yourls_html_logo();
|
||||||
|
yourls_html_menu();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="sub_wrap">
|
||||||
|
|
||||||
|
<h2><?php yourls_e( 'Bookmarklets' ); ?></h2>
|
||||||
|
|
||||||
|
<p><?php yourls_e( 'YOURLS comes with handy <span>bookmarklets</span> for easier link shortening and sharing.' ); ?></p>
|
||||||
|
|
||||||
|
<h3><?php yourls_e( 'Standard or Instant, Simple or Custom' ); ?></h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><?php yourls_e( 'The <span>Standard Bookmarklets</span> will take you to a page where you can easily edit or delete your brand new short URL.' ); ?></li>
|
||||||
|
|
||||||
|
<li><?php yourls_e( 'The <span>Instant Bookmarklets</span> will pop the short URL without leaving the page you are viewing.' ); ?></li>
|
||||||
|
|
||||||
|
<li><?php yourls_e( 'The <span>Simple Bookmarklets</span> will generate a short URL with a random or sequential keyword.' ); ?></li>
|
||||||
|
|
||||||
|
<li><?php yourls_e( 'The <span>Custom Keyword Bookmarklets</span> will prompt you for a custom keyword first.' ); ?></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p><?php
|
||||||
|
yourls_e( "If you want to share a description along with the link you're shortening, simply <span>select text</span> on the page you're viewing before clicking on your bookmarklet link" );
|
||||||
|
?></p>
|
||||||
|
|
||||||
|
<h3><?php yourls_e( 'The Bookmarklets' ); ?></h3>
|
||||||
|
|
||||||
|
<p><?php yourls_e( 'Click and drag links to your toolbar (or right-click and bookmark it)' ); ?></p>
|
||||||
|
|
||||||
|
<table class="tblSorter" cellpadding="0" cellspacing="1">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<th><?php yourls_e( 'Standard (new page)' ); ?></th>
|
||||||
|
<th><?php yourls_e( 'Instant (popup)' ); ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th class="header"><?php yourls_e( 'Simple' ); ?></th>
|
||||||
|
<td><a href="javascript:(function(){var%20d=document,w=window,enc=encodeURIComponent,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),s2=((s.toString()=='')?s:enc(s)),f='<?php echo yourls_admin_url( 'index.php' ); ?>',l=d.location.href,ups=l.match(/^[a-zA-Z0-9\+\.-]+:(\/\/)?/)[0],ur=l.split(new%20RegExp(ups))[1],ups=ups.split(/\:/),p='?up='+enc(ups[0]+':')+'&us='+enc(ups[1])+'&ur='+enc(ur)+'&t='+enc(d.title)+'&s='+s2,u=f+p;try{throw('ozhismygod');}catch(z){a=function(){if(!w.open(u))l.href=u;};if(/Firefox/.test(navigator.userAgent))setTimeout(a,0);else%20a();}void(0);})();" class="bookmarklet" onclick="alert('<?php echo yourls_esc_attr__( 'Drag to your toolbar!' ); ?>');return false;"><?php yourls_e( 'Shorten' ); ?></a></td>
|
||||||
|
<td><a href="javascript:(function(){var%20d=document,w=window,sc=d.createElement('script'),l=d.location.href,enc=encodeURIComponent,ups=l.match(/^[a-zA-Z0-9\+\.-]+:(\/\/)?/)[0],ur=l.split(new%20RegExp(ups))[1],ups=ups.split(/\:/),p='?up='+enc(ups[0]+':')+'&us='+enc(ups[1])+'&ur='+enc(ur)+'&t='+enc(d.title);w.yourls_callback=function(r){if(r.short_url){prompt(r.message,r.short_url);}else{alert('An%20error%20occured:%20'+r.message);}};sc.src='<?php echo yourls_admin_url( 'index.php' ); ?>'+p+'&jsonp=yourls';void(d.body.appendChild(sc));})();" class="bookmarklet" onclick="alert('<?php echo yourls_esc_attr__( 'Drag to your toolbar!' ); ?>');return false;"><?php yourls_e( 'Instant Shorten' ); ?></a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="header"><?php yourls_e( 'Custom Keyword' ); ?></th>
|
||||||
|
<td><a href="javascript:(function(){var%20d=document,enc=encodeURIComponent,e=window.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),s2=((s.toString()=='')?s:enc(s)),f='<?php echo yourls_admin_url( 'index.php' ); ?>',l=d.location.href,ups=l.match(/^[a-zA-Z0-9\+\.-]+:(\/\/)?/)[0],ur=l.split(new%20RegExp(ups))[1],ups=ups.split(/\:/),k=prompt('Custom%20URL'),k2=(k?'&k='+k:''),p='?up='+enc(ups[0]+':')+'&us='+enc(ups[1])+'&ur='+enc(ur)+'&t='+enc(d.title)+'&s='+s2+k2,u=f+p;if(k!=null){try{throw('ozhismygod');}catch(z){a=function(){if(!w.open(u))l=u;};if(/Firefox/.test(navigator.userAgent))setTimeout(a,0);else%20a();}void(0)}})();" class="bookmarklet" onclick="alert('<?php echo yourls_esc_attr__( 'Drag to your toolbar!' ); ?>');return false;"><?php yourls_e( 'Custom shorten' ); ?></a></td>
|
||||||
|
<td><a href="javascript:(function(){var%20d=document,l=d.location.href,k=prompt('Custom%20URL'),enc=encodeURIComponent,ups=l.match(/^[a-zA-Z0-9\+\.-]+:(\/\/)?/)[0],ur=l.split(new%20RegExp(ups))[1],ups=ups.split(/\:/),p='?up='+enc(ups[0]+':')+'&us='+enc(ups[1])+'&ur='+enc(ur)+'&t='+enc(d.title);sc=d.createElement('script');if(k!=null){window.yourls_callback=function(r){if(r.short_url){prompt(r.message,r.short_url);}else{alert('An%20error%20occured:%20'+r.message);}};sc.src='<?php echo yourls_admin_url( 'index.php' ); ?>'+p+'&k='+k+'&jsonp=yourls';void(d.body.appendChild(sc));}})();" class="bookmarklet" onclick="alert('<?php echo yourls_esc_attr__( 'Drag to your toolbar!' ); ?>');return false;"><?php yourls_e( 'Instant Custom Shorten' ); ?></a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3><?php yourls_e( 'Social Bookmarklets' ); ?></h3>
|
||||||
|
|
||||||
|
<p><?php yourls_e( 'Create a short URL and share it on social networks, all in one click!' ); ?>
|
||||||
|
<?php yourls_e( 'Click and drag links to your toolbar (or right-click and bookmark it)' ); ?></p>
|
||||||
|
|
||||||
|
<p><?php yourls_e( 'Shorten and share:' ); ?></p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
<a href="javascript:(function(){var%20d=document,enc=encodeURIComponent,share='facebook',f='<?php echo yourls_admin_url( 'index.php' ); ?>',l=d.location.href,ups=l.match(/^[a-zA-Z0-9\+\.-]+:(\/\/)?/)[0];var%20ur=l.split(new%20RegExp(ups))[1];var%20ups=ups.split(/\:/);p='?up='+enc(ups[0]+':')+'&us='+enc(ups[1])+'&ur='+enc(ur)+'&t='+enc(d.title)+'&share='+share,u=f+p;try{throw('ozhismygod');}catch(z){a=function(){if(!window.open(u,'Share','width=500,height=340,left=100','_blank'))l.href=u;};if(/Firefox/.test(navigator.userAgent))setTimeout(a,0);else%20a();}void(0);})();" class="bookmarklet" onclick="alert('<?php echo yourls_esc_attr__( 'Drag to your toolbar!' ); ?>');return false;"><?php yourls_e( 'YOURLS & Facebook' ); ?></a>
|
||||||
|
|
||||||
|
<a href="javascript:(function(){var%20d=document,w=window,enc=encodeURIComponent,share='twitter',e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),s2=((s.toString()=='')?s:'%20%22'+enc(s)+'%22'),f='<?php echo yourls_admin_url( 'index.php' ); ?>',l=d.location.href,ups=l.match(/^[a-zA-Z0-9\+\.-]+:(\/\/)?/)[0],ur=l.split(new%20RegExp(ups))[1],ups=ups.split(/\:/),p='?up='+enc(ups[0]+':')+'&us='+enc(ups[1])+'&ur='+enc(ur)+'&t='+enc(d.title)+s2+'&share='+share,u=f+p;try{throw('ozhismygod');}catch(z){a=function(){if(!w.open(u,'Share','width=780,height=265,left=100','_blank'))l=u;};if(/Firefox/.test(navigator.userAgent))setTimeout(a,0);else%20a();}void(0);})();" class="bookmarklet" onclick="alert('<?php echo yourls_esc_attr__( 'Drag to your toolbar!' ); ?>');return false;"><?php yourls_e( 'YOURLS & Twitter' ); ?></a>
|
||||||
|
|
||||||
|
<a href="javascript:(function(){var%20d=document,w=window,enc=encodeURIComponent,share='tumblr',e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),s2=((s.toString()=='')?s:'%20%22'+enc(s)+'%22'),f='<?php echo yourls_admin_url( 'index.php' ); ?>',l=d.location.href,ups=l.match(/^[a-zA-Z0-9\+\.-]+:(\/\/)?/)[0],ur=l.split(new%20RegExp(ups))[1],ups=ups.split(/\:/),p='?up='+enc(ups[0]+':')+'&us='+enc(ups[1])+'&ur='+enc(ur)+'&t='+enc(d.title)+'&s='+s2+'&share='+share,u=f+p;try{throw('ozhismygod');}catch(z){a=function(){if(!w.open(u,'Share','width=450,height=450,left=430','_blank'))l=u;};if(/Firefox/.test(navigator.userAgent))setTimeout(a,0);else%20a();}void(0);})();" class="bookmarklet" onclick="alert('<?php echo yourls_esc_attr__( 'Drag to your toolbar!' ); ?>');return false;"><?php yourls_e( 'YOURLS & Tumblr' ); ?></a>
|
||||||
|
|
||||||
|
<?php // Bookmarklets, unformatted for readability: https://gist.github.com/ozh/5495656 ?>
|
||||||
|
|
||||||
|
<?php yourls_do_action( 'social_bookmarklet_buttons_after' ); ?>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2><?php yourls_e( 'Prefix-n-Shorten' ); ?></h2>
|
||||||
|
|
||||||
|
<p><?php yourls_se( "When viewing a page, you can also prefix its full URL: just head to your browser's address bar, add \"<span>%s</span>\" to the beginning of the current URL (right before its 'http://' part) and hit enter.", preg_replace('@https?://@', '', YOURLS_SITE) . '/' ); ?></p>
|
||||||
|
|
||||||
|
<p><?php
|
||||||
|
yourls_e( 'Note: this will probably not work if your web server is running on Windows' );
|
||||||
|
if( yourls_is_windows() )
|
||||||
|
yourls_e( ' (which seems to be the case here)' );
|
||||||
|
?>.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<?php if( yourls_is_private() ) { ?>
|
||||||
|
|
||||||
|
<h2><?php yourls_e( 'Secure passwordless API call' ); ?></h2>
|
||||||
|
|
||||||
|
<p><?php
|
||||||
|
yourls_e( 'YOURLS allows API calls the old fashioned way, using <tt>username</tt> and <tt>password</tt> 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." );
|
||||||
|
?></p>
|
||||||
|
|
||||||
|
<p><?php
|
||||||
|
yourls_se( 'Your secret signature token: <strong><code>%s</code></strong>', yourls_auth_signature() );
|
||||||
|
yourls_e( "(It's a secret. Keep it secret) ");
|
||||||
|
?></p>
|
||||||
|
|
||||||
|
<p><?php yourls_e( 'This signature token can only be used with the API, not with the admin interface.' ); ?></p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><h3><?php yourls_e( 'Usage of the signature token' ); ?></h3>
|
||||||
|
<p><?php yourls_e( 'Simply use parameter <tt>signature</tt> in your API requests. Example:' ); ?></p>
|
||||||
|
<p><code><?php echo YOURLS_SITE; ?>/yourls-api.php?signature=<?php echo yourls_auth_signature(); ?>&action=...</code></p>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><h3><?php yourls_e( 'Usage of a time limited signature token' ); ?></h3>
|
||||||
|
<pre><code><?php
|
||||||
|
$timestamp = time();
|
||||||
|
<tt>// <?php yourls_e( 'actual value:' ); ?> $time = <?php $time = time(); echo $time; ?></tt>
|
||||||
|
$signature = md5( $timestamp . '<?php echo yourls_auth_signature(); ?>' );
|
||||||
|
<tt>// <?php yourls_e( 'actual value:' ); ?> $signature = "<?php $sign = md5( $time. yourls_auth_signature() ); echo $sign; ?>"</tt>
|
||||||
|
?>
|
||||||
|
</code></pre>
|
||||||
|
<p><?php yourls_e( 'Now use parameters <tt>signature</tt> and <tt>timestamp</tt> in your API requests. Example:' ); ?></p>
|
||||||
|
<p><code><?php echo YOURLS_SITE; ?>/yourls-api.php?timestamp=<strong>$timestamp</strong>&signature=<strong>$signature</strong>&action=...</code></p>
|
||||||
|
<p><?php yourls_e( 'Actual values:' ); ?><br/>
|
||||||
|
<tt><?php echo YOURLS_SITE; ?>/yourls-api.php?timestamp=<?php echo $time; ?>&signature=<?php echo $sign; ?>&action=...</tt></p>
|
||||||
|
<p><?php yourls_se( 'This URL would be valid for only %s seconds', YOURLS_NONCE_LIFE ); ?></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p><?php yourls_se( 'See the <a href="%s">API documentation</a> for more', YOURLS_SITE . '/readme.html#API' ); ?></p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php } // end is private ?>
|
||||||
|
|
||||||
|
<?php yourls_html_footer(); ?>
|
86
source/admin/upgrade.php
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
define( 'YOURLS_ADMIN', true );
|
||||||
|
define( 'YOURLS_UPGRADING', true );
|
||||||
|
require_once( dirname( dirname( __FILE__ ) ).'/includes/load-yourls.php' );
|
||||||
|
require_once( YOURLS_INC.'/functions-upgrade.php' );
|
||||||
|
require_once( YOURLS_INC.'/functions-install.php' );
|
||||||
|
yourls_maybe_require_auth();
|
||||||
|
|
||||||
|
yourls_html_head( 'upgrade', yourls__( 'Upgrade YOURLS' ) );
|
||||||
|
yourls_html_logo();
|
||||||
|
yourls_html_menu();
|
||||||
|
?>
|
||||||
|
<h2><?php yourls_e( 'Upgrade YOURLS' ); ?></h2>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Check if upgrade is needed
|
||||||
|
if ( !yourls_upgrade_is_needed() ) {
|
||||||
|
echo '<p>' . yourls_s( 'Upgrade not required. Go <a href="%s">back to play</a>!', yourls_admin_url('index.php') ) . '</p>';
|
||||||
|
|
||||||
|
|
||||||
|
} 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 = yourls_sanitize_version( $_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
|
||||||
|
$ydb->show_errors = true;
|
||||||
|
|
||||||
|
// Let's go
|
||||||
|
$step = ( isset( $_GET['step'] ) ? intval( $_GET['step'] ) : 0 );
|
||||||
|
switch( $step ) {
|
||||||
|
|
||||||
|
default:
|
||||||
|
case 0:
|
||||||
|
?>
|
||||||
|
<p><?php yourls_e( 'Your current installation needs to be upgraded.' ); ?></p>
|
||||||
|
<p><?php yourls_e( 'Please, pretty please, it is recommended that you <strong>backup</strong> your database<br/>(you should do this regularly anyway)' ); ?></p>
|
||||||
|
<p><?php yourls_e( "Nothing awful <em>should</em> happen, but this doesn't mean it <em>won't</em> happen, right? ;)" ); ?></p>
|
||||||
|
<p><?php yourls_e( "On every step, if <span class='error'>something goes wrong</span>, you'll see a message and hopefully a way to fix." ); ?></p>
|
||||||
|
<p><?php yourls_e( 'If everything goes too fast and you cannot read, <span class="success">good for you</span>, let it go :)' ); ?></p>
|
||||||
|
<p><?php yourls_e( 'Once you are ready, press "Upgrade" !' ); ?></p>
|
||||||
|
<?php
|
||||||
|
echo "
|
||||||
|
<form action='upgrade.php?' method='get'>
|
||||||
|
<input type='hidden' name='step' value='1' />
|
||||||
|
<input type='hidden' name='oldver' value='$oldver' />
|
||||||
|
<input type='hidden' name='newver' value='$newver' />
|
||||||
|
<input type='hidden' name='oldsql' value='$oldsql' />
|
||||||
|
<input type='hidden' name='newsql' value='$newsql' />
|
||||||
|
<input type='submit' class='primary' value='" . yourls_esc_attr__( 'Upgrade' ) . "' />
|
||||||
|
</form>";
|
||||||
|
|
||||||
|
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 '<p>' . yourls__( 'Your installation is now up to date ! ' ) . '</p>';
|
||||||
|
echo '<p>' . yourls_s( 'Go back to <a href="%s">the admin interface</a>', yourls_admin_url('index.php') ) . '</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php yourls_html_footer(); ?>
|
14
source/css/cal.css
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/* Calendar */
|
||||||
|
.datepicker { border-collapse: collapse; border: 2px solid #999; position: absolute; width: 215px }
|
||||||
|
.datepicker tr.controls th { height: 22px; font-size: 11px; }
|
||||||
|
.datepicker select { font-size: 11px; }
|
||||||
|
.datepicker tr.days th { height: 18px; }
|
||||||
|
.datepicker tfoot td { height: 18px; text-align: center; text-transform: capitalize; }
|
||||||
|
.datepicker th, .datepicker tfoot td { background: #eee; font: 10px/18px Verdana, Arial, Helvetica, sans-serif; }
|
||||||
|
.datepicker th span, .datepicker tfoot td span { font-weight: bold; }
|
||||||
|
.datepicker tbody td { width: 24px; height: 24px; border: 1px solid #ccc; font: 11px/22px Arial, Helvetica, sans-serif; text-align: center; background: #fff; }
|
||||||
|
.datepicker tbody td.date { cursor: pointer; }
|
||||||
|
.datepicker tbody td.date.over { background-color: #99ffff; }
|
||||||
|
.datepicker tbody td.date.chosen { font-weight: bold; background-color: #ccffcc; }
|
||||||
|
/* Form defaults */
|
||||||
|
#date_and, #date_second {display:none}
|
113
source/css/infos.css
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
h3 span.label {
|
||||||
|
width:100px;
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.toggle_display {
|
||||||
|
display:none;
|
||||||
|
list-style-type:none;
|
||||||
|
margin-left:0;
|
||||||
|
margin-right:23px;
|
||||||
|
padding:12px 5px 3px;
|
||||||
|
border-bottom:1px solid #C7E7FF;
|
||||||
|
}
|
||||||
|
ul.toggle_display li {
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
#tabs ul#headers li, #tabs ul#headers li h2, #stats_lines li{
|
||||||
|
display: inline;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
#tabs ul#headers {
|
||||||
|
border-bottom:1px solid #E3F3FF;
|
||||||
|
padding:12px 5px 3px 5px;
|
||||||
|
float:left;
|
||||||
|
}
|
||||||
|
.wrap_unfloat {
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs ul#headers li a {
|
||||||
|
color:#595441;
|
||||||
|
border:1px solid #C7E7FF;
|
||||||
|
-moz-border-radius:10px 10px 0 0;
|
||||||
|
-webkit-border-radius:10px 10px 0 0;
|
||||||
|
border-radius:10px 10px 0 0;
|
||||||
|
padding:10px 5px 5px 15px;
|
||||||
|
background:#E3F3FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs ul#headers li a:hover {
|
||||||
|
text-decoration:none;
|
||||||
|
background:#88C0EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs ul#headers li a.selected {
|
||||||
|
border-bottom:2px solid #fff;
|
||||||
|
background:#fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs ul#headers li a.selected:hover {
|
||||||
|
background:#fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stats_lines li a {
|
||||||
|
-moz-border-radius:10px 10px 0 0;
|
||||||
|
-webkit-border-radius:10px 10px 0 0;
|
||||||
|
border-radius:10px 10px 0 0;
|
||||||
|
padding:3px 10px;
|
||||||
|
background:#E3F3FF;
|
||||||
|
border:1px solid #C7E7FF;
|
||||||
|
}
|
||||||
|
#stats_lines li a:hover {
|
||||||
|
text-decoration:none;
|
||||||
|
background:#C7E7FF;
|
||||||
|
}
|
||||||
|
#stats_lines li a.selected {
|
||||||
|
background:#fff;
|
||||||
|
border:1px solid #C7E7FF;
|
||||||
|
border-bottom:1px solid white;
|
||||||
|
}
|
||||||
|
#stats_lines li a.selected:hover {
|
||||||
|
background:#fff;
|
||||||
|
}
|
||||||
|
.tab {
|
||||||
|
padding:10px;
|
||||||
|
}
|
||||||
|
li#sites_various { padding-left:22px; padding-top:4px;}
|
||||||
|
|
||||||
|
li.sites_list img, #longurl img {width:16px; height: 16px; display:inline-block;}
|
||||||
|
|
||||||
|
#referrer_cell { min-width: 300px;}
|
||||||
|
|
||||||
|
#details_clicks li.bestday, #details_clicks li span.best_month, #details_clicks li span.best_year {
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.no_bullet {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-left:0;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
ul.no_bullet li {
|
||||||
|
margin-bottom:5px;
|
||||||
|
}
|
||||||
|
#historical_clicks {
|
||||||
|
float:left;
|
||||||
|
margin:0;
|
||||||
|
}
|
||||||
|
#historical_clicks li {
|
||||||
|
padding:2px 10px;
|
||||||
|
margin:0;
|
||||||
|
}
|
||||||
|
#historical_clicks li:hover {
|
||||||
|
background:#C7E7FF !important;
|
||||||
|
}
|
||||||
|
#historical_clicks span.historical_link {
|
||||||
|
min-width:130px;
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
#historical_clicks span.historical_count {
|
||||||
|
min-width:100px;
|
||||||
|
display:inline-block;
|
||||||
|
}
|
BIN
source/css/palette.png
Normal file
After Width: | Height: | Size: 10 KiB |
65
source/css/share.css
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#shareboxes, #tweet {
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#shareboxes{
|
||||||
|
margin-top:15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.share {
|
||||||
|
-moz-border-radius:5px;
|
||||||
|
-webkit-border-radius:5px;
|
||||||
|
border-radius:5px;
|
||||||
|
border:2px solid #88c0eb;
|
||||||
|
background:#fff;
|
||||||
|
margin-right:1em;
|
||||||
|
padding:0 1em;
|
||||||
|
float:left;
|
||||||
|
height:140px;
|
||||||
|
}
|
||||||
|
#origlink{
|
||||||
|
display:inline-block;
|
||||||
|
white-space:pre;
|
||||||
|
width:183px;
|
||||||
|
overflow:hidden;
|
||||||
|
vertical-align:-2px;
|
||||||
|
}
|
||||||
|
#copybox {
|
||||||
|
width:250px;
|
||||||
|
}
|
||||||
|
#sharebox {
|
||||||
|
width:500px;
|
||||||
|
}
|
||||||
|
#tweet_body {
|
||||||
|
float:left;
|
||||||
|
width:450px;
|
||||||
|
height:4em;
|
||||||
|
font-size:12px;
|
||||||
|
}
|
||||||
|
#charcount {
|
||||||
|
padding-left:5px;
|
||||||
|
color:#88c0eb;
|
||||||
|
}
|
||||||
|
#charcount.negative {
|
||||||
|
color:red;
|
||||||
|
}
|
||||||
|
#share_links a {
|
||||||
|
padding:0 12px 0 18px;
|
||||||
|
font-weight:bold
|
||||||
|
}
|
||||||
|
#share_links a:hover {
|
||||||
|
background-position:2px center;
|
||||||
|
}
|
||||||
|
#share_tw {background:transparent url(../images/twitter.png) left center no-repeat;}
|
||||||
|
#share_fb {background:transparent url(../images/facebook.png) left center no-repeat;}
|
||||||
|
#share_ff {background:transparent url(../images/friendfeed.png) left center no-repeat;}
|
||||||
|
|
||||||
|
#copylink{
|
||||||
|
cursor:pointer;
|
||||||
|
background:transparent url(../images/copy.png) 130% center no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#copylink:hover, #copylink.hover {
|
||||||
|
background-position:100% 50%;
|
||||||
|
}
|
||||||
|
|
330
source/css/style.css
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
body {
|
||||||
|
font-family: Verdana, Arial;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #595441;
|
||||||
|
background:#e3f3ff;
|
||||||
|
text-align:center;
|
||||||
|
margin-top:0px;
|
||||||
|
padding-top:10px;
|
||||||
|
}
|
||||||
|
#wrap {
|
||||||
|
max-width:950px;
|
||||||
|
min-height:150px;
|
||||||
|
margin:0 auto;
|
||||||
|
background:white;
|
||||||
|
text-align:left;
|
||||||
|
padding:5px 20px 10px 20px;
|
||||||
|
border-left:3px solid #2a85b3;
|
||||||
|
border-right:3px solid #2a85b3;
|
||||||
|
border-bottom:3px solid #2a85b3;
|
||||||
|
border-top:3px solid #2a85b3;
|
||||||
|
-moz-border-radius:20px;
|
||||||
|
-webkit-border-radius:20px;
|
||||||
|
border-radius:20px;
|
||||||
|
}
|
||||||
|
.hide-if-no-js {display: none;}
|
||||||
|
div, p, td {
|
||||||
|
font-family: Verdana, Arial;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
a, a:link, a:active, a:visited {
|
||||||
|
color: #2a85b3;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
h1 {height:50px;margin:0;float:right;max-width:500px;}
|
||||||
|
h1 a {text-align:right;font-size:20px;float:right;}
|
||||||
|
h1 a, h1 a:link, h1 a:active, h1 a:visited {color:#2a85b3}
|
||||||
|
h1 a:hover{text-decoration:none;}
|
||||||
|
h1 a:hover span{text-decoration:underline;color:#88c0eb}
|
||||||
|
|
||||||
|
ul#admin_menu {
|
||||||
|
min-height:100px;
|
||||||
|
list-style-type:none;
|
||||||
|
padding:0;
|
||||||
|
font-size:105%;
|
||||||
|
}
|
||||||
|
ul#admin_menu li {
|
||||||
|
color:#aaa;
|
||||||
|
padding:1px 0;
|
||||||
|
}
|
||||||
|
ul#admin_menu li:hover {
|
||||||
|
list-style-type:square;
|
||||||
|
color:#000;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background:#eaeaef;
|
||||||
|
padding:0 2px;
|
||||||
|
}
|
||||||
|
tt {
|
||||||
|
background:#ffc;
|
||||||
|
padding:0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, textarea {
|
||||||
|
-moz-border-radius:3px;
|
||||||
|
-webkit-border-radius:3px;
|
||||||
|
border-radius:3px;
|
||||||
|
}
|
||||||
|
Input.text, select, textarea {
|
||||||
|
font-family: Verdana, Arial;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #595441;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border: 1px solid #88c0eb;
|
||||||
|
margin:1px;
|
||||||
|
}
|
||||||
|
input.button {
|
||||||
|
font-family: Verdana, Arial;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #595441;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border: 1px solid #88c0eb;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
input.primary {
|
||||||
|
border:2px solid #2A85B3;
|
||||||
|
background:#fafafe;
|
||||||
|
}
|
||||||
|
input.text:focus, textarea:focus {
|
||||||
|
border:2px solid #2A85B3;
|
||||||
|
margin:0px;
|
||||||
|
}
|
||||||
|
tr.edit-row td {
|
||||||
|
background:#e3f3ff !important;
|
||||||
|
}
|
||||||
|
#new_url {
|
||||||
|
text-align:center;
|
||||||
|
padding:1px;
|
||||||
|
border:1px solid #CDCDCD;
|
||||||
|
background:#fff;
|
||||||
|
clear:both;
|
||||||
|
}
|
||||||
|
#new_url div {
|
||||||
|
background:#C7E7FF;
|
||||||
|
padding:4px;
|
||||||
|
}
|
||||||
|
#new_url_form {
|
||||||
|
padding:4px;
|
||||||
|
}
|
||||||
|
#new_url #feedback {
|
||||||
|
background:#ff8;
|
||||||
|
color:#88c0eb;
|
||||||
|
width:50%;
|
||||||
|
margin:0px 25%;
|
||||||
|
padding:2px;
|
||||||
|
border:1px solid #ff8;
|
||||||
|
}
|
||||||
|
#new_url #feedback .fail {
|
||||||
|
color:#f55;
|
||||||
|
}
|
||||||
|
#add-url {width:400px}
|
||||||
|
td.url small a{
|
||||||
|
color:#bbc;
|
||||||
|
}
|
||||||
|
body.desktop td.actions input,body.desktop td.actions a {
|
||||||
|
visibility:hidden;
|
||||||
|
}
|
||||||
|
td.actions input.disabled, td.actions input.loading {
|
||||||
|
visibility:visible;
|
||||||
|
}
|
||||||
|
tr:hover td.actions input, tr:hover td.actions a {
|
||||||
|
visibility:visible;
|
||||||
|
}
|
||||||
|
td.actions .button {
|
||||||
|
font-family: Verdana, Arial;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #595441;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border: 1px solid #88c0eb;
|
||||||
|
-moz-border-radius:3px;
|
||||||
|
-webkit-border-radius:3px;
|
||||||
|
border-radius:3px;
|
||||||
|
cursor:pointer;
|
||||||
|
height:22px;
|
||||||
|
width:22px;
|
||||||
|
margin-top:0px;
|
||||||
|
margin-right:5px;
|
||||||
|
display:block;
|
||||||
|
float:left;
|
||||||
|
text-indent:-9999px;
|
||||||
|
outline:0px;
|
||||||
|
}
|
||||||
|
td.actions .button:active {
|
||||||
|
border:1px solid #000;
|
||||||
|
}
|
||||||
|
td.actions .button:hover {
|
||||||
|
text-decoration:none;
|
||||||
|
}
|
||||||
|
td.actions .button.disabled, #add-button.disabled {
|
||||||
|
border:1px solid #333;
|
||||||
|
background:#ccc;
|
||||||
|
}
|
||||||
|
td.actions .button.loading, #add-button.loading {
|
||||||
|
background:#cc7 url(../images/loading.gif) center center no-repeat;
|
||||||
|
color:#cc7;
|
||||||
|
}
|
||||||
|
td.actions .button_share {
|
||||||
|
background:transparent url(../images/share.png) 2px center no-repeat;
|
||||||
|
}
|
||||||
|
td.actions .button_edit {
|
||||||
|
background:transparent url(../images/pencil.png) 2px center no-repeat;
|
||||||
|
}
|
||||||
|
td.actions .button_delete {
|
||||||
|
background:transparent url(../images/delete.png) 2px center no-repeat;
|
||||||
|
}
|
||||||
|
td.actions .button_stats {
|
||||||
|
background:transparent url(../images/chart_bar.png) 2px center no-repeat;
|
||||||
|
}
|
||||||
|
#main_table tfoot th, #main_table tfoot th div {
|
||||||
|
font-size:10px;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
background:#fee;
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
color: orange;
|
||||||
|
background:#ffe9bf;
|
||||||
|
}
|
||||||
|
.success {
|
||||||
|
color: green;
|
||||||
|
background:#efe;
|
||||||
|
}
|
||||||
|
#login {
|
||||||
|
width: 300px;
|
||||||
|
margin: 200px auto 0px auto;
|
||||||
|
}
|
||||||
|
#login p{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
#login .text {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#login ul {
|
||||||
|
padding-left:0px;
|
||||||
|
list-style-type:none;
|
||||||
|
text-indent:0;
|
||||||
|
}
|
||||||
|
#login ul li {
|
||||||
|
padding:0 0 5px 20px;
|
||||||
|
}
|
||||||
|
#login ul.error li {
|
||||||
|
background:transparent url(../images/cancel.png) top left no-repeat;
|
||||||
|
}
|
||||||
|
#login ul.warning li {
|
||||||
|
background:transparent url(../images/error.png) top left no-repeat;
|
||||||
|
}
|
||||||
|
#login ul.success li {
|
||||||
|
background:transparent url(../images/accept.png) top left no-repeat;
|
||||||
|
}
|
||||||
|
.sub_wrap {
|
||||||
|
max-width:580px;
|
||||||
|
padding-bottom:30px;
|
||||||
|
text-align:justify;
|
||||||
|
}
|
||||||
|
.sub_wrap span {
|
||||||
|
background:#ffa;
|
||||||
|
padding:0 2px;
|
||||||
|
}
|
||||||
|
a.bookmarklet {
|
||||||
|
border:2px solid #2a85b3;
|
||||||
|
-moz-border-radius:3px;
|
||||||
|
-webkit-border-radius:3px;
|
||||||
|
border-radius:3px;
|
||||||
|
padding:5px 5px 5px 20px;
|
||||||
|
background:#eef url(../images/favicon.gif) 2px center no-repeat;
|
||||||
|
margin:3px;
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
a.bookmarklet:hover {
|
||||||
|
text-decoration:none;
|
||||||
|
background-position:3px center;
|
||||||
|
}
|
||||||
|
#footer {
|
||||||
|
text-align:center;
|
||||||
|
margin-top:20px;
|
||||||
|
}
|
||||||
|
#footer p {
|
||||||
|
padding:10px;
|
||||||
|
background:white;
|
||||||
|
margin:0 auto;
|
||||||
|
max-width:950px;
|
||||||
|
-moz-border-radius:10px;
|
||||||
|
-webkit-border-radius:10px;
|
||||||
|
border-radius:10px;
|
||||||
|
border:2px solid #2a85b3;
|
||||||
|
-moz-border-radius-bottomleft:30px;
|
||||||
|
-moz-border-radius-bottomright:30px;
|
||||||
|
-webkit-border-bottom-left-radius:25px;
|
||||||
|
-webkit-border-bottom-right-radius:25px;
|
||||||
|
border-bottom-left-radius:25px;
|
||||||
|
border-bottom-right-radius:25px;
|
||||||
|
}
|
||||||
|
#footer p a {
|
||||||
|
background:#fff url(../images/favicon.gif) 2px center no-repeat;
|
||||||
|
padding-left:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice {
|
||||||
|
border:1px solid #2a85b3;
|
||||||
|
background: #F3FAFD;
|
||||||
|
-moz-border-radius:6px;
|
||||||
|
-webkit-border-radius:6px;
|
||||||
|
border-radius:6px;
|
||||||
|
width:70%;
|
||||||
|
margin-left:15%;
|
||||||
|
padding-left:10px;
|
||||||
|
margin-bottom:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.jquery-notify-bar {
|
||||||
|
width:100%;
|
||||||
|
position:fixed;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
z-index:32768;
|
||||||
|
background-color:#efefef;
|
||||||
|
font-size:18px;
|
||||||
|
color:#000;
|
||||||
|
text-align:center;
|
||||||
|
font-family: Arial, Verdana, sans-serif;
|
||||||
|
padding:20px 0px;
|
||||||
|
border-bottom:1px solid #bbb;
|
||||||
|
filter:alpha(opacity=95);
|
||||||
|
-moz-opacity:0.95;
|
||||||
|
-khtml-opacity:0.95;
|
||||||
|
opacity:0.95;
|
||||||
|
-moz-box-shadow: 0 1px 5px rgba(0,0,0,0.5);
|
||||||
|
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5);
|
||||||
|
text-shadow: 0 1px 1px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.jquery-notify-bar.error ,.jquery-notify-bar.fail {
|
||||||
|
color:#f00;
|
||||||
|
background-color:#fdd;
|
||||||
|
}
|
||||||
|
.jquery-notify-bar.error span,.jquery-notify-bar.fail span{
|
||||||
|
background:transparent url("../images/error.png") no-repeat left center;
|
||||||
|
padding-left:20px;
|
||||||
|
}.jquery-notify-bar.success span{
|
||||||
|
background:transparent url("../images/accept.png") no-repeat left center;
|
||||||
|
padding-left:20px;
|
||||||
|
}
|
||||||
|
.jquery-notify-bar.success {
|
||||||
|
color:#060;
|
||||||
|
background-color:#aea;
|
||||||
|
}
|
||||||
|
.notify-bar-close {
|
||||||
|
position:absolute;
|
||||||
|
left:95%;
|
||||||
|
font-size:11px;
|
||||||
|
}
|
||||||
|
tr.plugin.active a{ font-weight:bolder;}
|
||||||
|
body.desktop tr.plugin td.plugin_desc small{ visibility:hidden;}
|
||||||
|
tr:hover.plugin td.plugin_desc small{ visibility:visible;}
|
104
source/css/tablesorter.css
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/* jQuery Table Sorter */
|
||||||
|
table.tblSorter {
|
||||||
|
font-family:Verdana, Arial;
|
||||||
|
background-color: #CDCDCD;
|
||||||
|
margin:10px 0px 0px;
|
||||||
|
font-size: 8pt;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
table.tblSorter thead tr th, table.tblSorter tfoot tr th, table.tblSorter th.header {
|
||||||
|
background-color: #C7E7FF;
|
||||||
|
border: 1px solid #FFF;
|
||||||
|
font-size: 8pt;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
table.tblSorter tfoot tr th {
|
||||||
|
background-color: #E3F3FF;
|
||||||
|
}
|
||||||
|
table.tblSorter thead tr .tablesorter-header {
|
||||||
|
background-image: url('../images/bg.gif');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center right;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-right:10px;
|
||||||
|
}
|
||||||
|
table.tblSorter thead tr .sorter-false {
|
||||||
|
background-image: none;
|
||||||
|
cursor:default;
|
||||||
|
}
|
||||||
|
table.tblSorter tbody td {
|
||||||
|
color: #3D3D3D;
|
||||||
|
padding: 4px;
|
||||||
|
background-color: #FFF;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
table.tblSorter tbody tr.normal-row td {
|
||||||
|
background: #F1F9FF;
|
||||||
|
}
|
||||||
|
table.tblSorter tbody tr.alt-row td {
|
||||||
|
|
||||||
|
}
|
||||||
|
table.tblSorter tbody tr.normal-row:hover td {
|
||||||
|
background-color:#F1FFF6;
|
||||||
|
}
|
||||||
|
table.tblSorter tbody tr.alt-row:hover td {
|
||||||
|
background-color:#F1FFF6;
|
||||||
|
}
|
||||||
|
table.tblSorter thead tr .tablesorter-headerDesc {
|
||||||
|
background-image: url('../images/desc.gif');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center right;
|
||||||
|
}
|
||||||
|
table.tblSorter thead tr .tablesorter-headerAsc {
|
||||||
|
background-image: url('../images/asc.gif');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center right;
|
||||||
|
}
|
||||||
|
table.tblSorter thead tr .tablesorter-headerAsc, table.tblSorter thead tr .tablesorter-headerDesc {
|
||||||
|
background-color: #91C7F2;
|
||||||
|
}
|
||||||
|
table.tblSorter tfoot tr {
|
||||||
|
background-color: #BCD9E8;
|
||||||
|
}
|
||||||
|
#filter_form{
|
||||||
|
float:left;
|
||||||
|
text-align:left;
|
||||||
|
max-width:69%;
|
||||||
|
}
|
||||||
|
#filter_buttons{
|
||||||
|
float:right;
|
||||||
|
}
|
||||||
|
#pagination{
|
||||||
|
text-align:right;
|
||||||
|
float:right;
|
||||||
|
width:30%;
|
||||||
|
}
|
||||||
|
.navigation .nav_total{
|
||||||
|
display:block;
|
||||||
|
margin-bottom:10px;
|
||||||
|
}
|
||||||
|
.navigation .nav_link a, .navigation .nav_current {
|
||||||
|
border:1px solid #CDCDCD;
|
||||||
|
margin:0px 2px;
|
||||||
|
padding:2px 1px;
|
||||||
|
background:#fff;
|
||||||
|
text-align:center;
|
||||||
|
min-width:15px;
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
.navigation .nav_current {
|
||||||
|
border:0px;
|
||||||
|
background:none;
|
||||||
|
}
|
||||||
|
.navigation .nav_first a, .navigation .nav_last a {
|
||||||
|
padding:2px 2px;
|
||||||
|
}
|
||||||
|
.navigation .nav_prev:before, .navigation .nav_next:after {
|
||||||
|
content:"...";
|
||||||
|
}
|
||||||
|
.navigation .nav_link a:hover {
|
||||||
|
border:1px solid #BCD9E8;
|
||||||
|
background:#BCD9E8;
|
||||||
|
text-decoration:none;
|
||||||
|
}
|
BIN
source/images/accept.png
Normal file
After Width: | Height: | Size: 781 B |
BIN
source/images/asc.gif
Normal file
After Width: | Height: | Size: 54 B |
BIN
source/images/bg.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
source/images/blank.gif
Normal file
After Width: | Height: | Size: 42 B |
BIN
source/images/cancel.png
Normal file
After Width: | Height: | Size: 587 B |
BIN
source/images/chart_bar.png
Normal file
After Width: | Height: | Size: 541 B |
BIN
source/images/chart_bar_add.png
Normal file
After Width: | Height: | Size: 626 B |
BIN
source/images/copy-large.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
source/images/copy.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
source/images/delete.png
Normal file
After Width: | Height: | Size: 715 B |
BIN
source/images/desc.gif
Normal file
After Width: | Height: | Size: 54 B |
BIN
source/images/error.png
Normal file
After Width: | Height: | Size: 666 B |
BIN
source/images/facebook.png
Normal file
After Width: | Height: | Size: 318 B |
BIN
source/images/favicon.gif
Normal file
After Width: | Height: | Size: 88 B |
BIN
source/images/filter.gif
Normal file
After Width: | Height: | Size: 870 B |
BIN
source/images/friendfeed.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
source/images/loading.gif
Normal file
After Width: | Height: | Size: 771 B |
BIN
source/images/pencil.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
source/images/share.png
Normal file
After Width: | Height: | Size: 1,007 B |
BIN
source/images/twitter.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
source/images/yourls-logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
10
source/includes/Requests/README.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Requests for PHP
|
||||||
|
================
|
||||||
|
|
||||||
|
**Requests** is a HTTP library written in PHP, for human beings. It is roughly
|
||||||
|
based on the API from the excellent [Requests Python
|
||||||
|
library](http://python-requests.org/). **Requests** is [ISC
|
||||||
|
Licensed](https://github.com/rmccue/Requests/blob/master/LICENSE) (similar to
|
||||||
|
the new BSD license) and has no dependencies, except for PHP 5.2+.
|
||||||
|
|
||||||
|
**Requests** can be found here : https://github.com/rmccue/Requests
|
863
source/includes/Requests/Requests.php
Normal file
|
@ -0,0 +1,863 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Requests for PHP
|
||||||
|
*
|
||||||
|
* Inspired by Requests for Python.
|
||||||
|
*
|
||||||
|
* Based on concepts from SimplePie_File, RequestCore and WP_Http.
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests for PHP
|
||||||
|
*
|
||||||
|
* Inspired by Requests for Python.
|
||||||
|
*
|
||||||
|
* Based on concepts from SimplePie_File, RequestCore and WP_Http.
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests {
|
||||||
|
/**
|
||||||
|
* POST method
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const POST = 'POST';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PUT method
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const PUT = 'PUT';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET method
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const GET = 'GET';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HEAD method
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const HEAD = 'HEAD';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DELETE method
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const DELETE = 'DELETE';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PATCH method
|
||||||
|
*
|
||||||
|
* @link http://tools.ietf.org/html/rfc5789
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const PATCH = 'PATCH';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current version of Requests
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const VERSION = '1.6';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registered transport classes
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected static $transports = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selected transport name
|
||||||
|
*
|
||||||
|
* Use {@see get_transport()} instead
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public static $transport = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a static class, do not instantiate it
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
private function __construct() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoloader for Requests
|
||||||
|
*
|
||||||
|
* Register this with {@see register_autoloader()} if you'd like to avoid
|
||||||
|
* having to create your own.
|
||||||
|
*
|
||||||
|
* (You can also use `spl_autoload_register` directly if you'd prefer.)
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*
|
||||||
|
* @param string $class Class name to load
|
||||||
|
*/
|
||||||
|
public static function autoloader($class) {
|
||||||
|
// Check that the class starts with "Requests"
|
||||||
|
if (strpos($class, 'Requests') !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = str_replace('_', '/', $class);
|
||||||
|
if (file_exists(dirname(__FILE__) . '/' . $file . '.php')) {
|
||||||
|
require_once(dirname(__FILE__) . '/' . $file . '.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the built-in autoloader
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
public static function register_autoloader() {
|
||||||
|
spl_autoload_register(array('Requests', 'autoloader'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a transport
|
||||||
|
*
|
||||||
|
* @param string $transport Transport class to add, must support the Requests_Transport interface
|
||||||
|
*/
|
||||||
|
public static function add_transport($transport) {
|
||||||
|
if (empty(self::$transports)) {
|
||||||
|
self::$transports = array(
|
||||||
|
'Requests_Transport_cURL',
|
||||||
|
'Requests_Transport_fsockopen',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$transports = array_merge(self::$transports, array($transport));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a working transport
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception If no valid transport is found (`notransport`)
|
||||||
|
* @return Requests_Transport
|
||||||
|
*/
|
||||||
|
protected static function get_transport() {
|
||||||
|
// Caching code, don't bother testing coverage
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
if (self::$transport !== null) {
|
||||||
|
return new self::$transport();
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
if (empty(self::$transports)) {
|
||||||
|
self::$transports = array(
|
||||||
|
'Requests_Transport_cURL',
|
||||||
|
'Requests_Transport_fsockopen',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find us a working transport
|
||||||
|
foreach (self::$transports as $class) {
|
||||||
|
if (!class_exists($class))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$result = call_user_func(array($class, 'test'));
|
||||||
|
if ($result) {
|
||||||
|
self::$transport = $class;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self::$transport === null) {
|
||||||
|
throw new Requests_Exception('No working transports found', 'notransport', self::$transports);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self::$transport();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**#@+
|
||||||
|
* @see request()
|
||||||
|
* @param string $url
|
||||||
|
* @param array $headers
|
||||||
|
* @param array $options
|
||||||
|
* @return Requests_Response
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Send a GET request
|
||||||
|
*/
|
||||||
|
public static function get($url, $headers = array(), $options = array()) {
|
||||||
|
return self::request($url, $headers, null, self::GET, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a HEAD request
|
||||||
|
*/
|
||||||
|
public static function head($url, $headers = array(), $options = array()) {
|
||||||
|
return self::request($url, $headers, null, self::HEAD, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a DELETE request
|
||||||
|
*/
|
||||||
|
public static function delete($url, $headers = array(), $options = array()) {
|
||||||
|
return self::request($url, $headers, null, self::DELETE, $options);
|
||||||
|
}
|
||||||
|
/**#@-*/
|
||||||
|
|
||||||
|
/**#@+
|
||||||
|
* @see request()
|
||||||
|
* @param string $url
|
||||||
|
* @param array $headers
|
||||||
|
* @param array $data
|
||||||
|
* @param array $options
|
||||||
|
* @return Requests_Response
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Send a POST request
|
||||||
|
*/
|
||||||
|
public static function post($url, $headers = array(), $data = array(), $options = array()) {
|
||||||
|
return self::request($url, $headers, $data, self::POST, $options);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Send a PUT request
|
||||||
|
*/
|
||||||
|
public static function put($url, $headers = array(), $data = array(), $options = array()) {
|
||||||
|
return self::request($url, $headers, $data, self::PUT, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a PATCH request
|
||||||
|
*
|
||||||
|
* Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
|
||||||
|
* specification recommends that should send an ETag
|
||||||
|
*
|
||||||
|
* @link http://tools.ietf.org/html/rfc5789
|
||||||
|
*/
|
||||||
|
public static function patch($url, $headers, $data = array(), $options = array()) {
|
||||||
|
return self::request($url, $headers, $data, self::PATCH, $options);
|
||||||
|
}
|
||||||
|
/**#@-*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main interface for HTTP requests
|
||||||
|
*
|
||||||
|
* This method initiates a request and sends it via a transport before
|
||||||
|
* parsing.
|
||||||
|
*
|
||||||
|
* The `$options` parameter takes an associative array with the following
|
||||||
|
* options:
|
||||||
|
*
|
||||||
|
* - `timeout`: How long should we wait for a response?
|
||||||
|
* (integer, seconds, default: 10)
|
||||||
|
* - `useragent`: Useragent to send to the server
|
||||||
|
* (string, default: php-requests/$version)
|
||||||
|
* - `follow_redirects`: Should we follow 3xx redirects?
|
||||||
|
* (boolean, default: true)
|
||||||
|
* - `redirects`: How many times should we redirect before erroring?
|
||||||
|
* (integer, default: 10)
|
||||||
|
* - `blocking`: Should we block processing on this request?
|
||||||
|
* (boolean, default: true)
|
||||||
|
* - `filename`: File to stream the body to instead.
|
||||||
|
* (string|boolean, default: false)
|
||||||
|
* - `auth`: Authentication handler or array of user/password details to use
|
||||||
|
* for Basic authentication
|
||||||
|
* (Requests_Auth|array|boolean, default: false)
|
||||||
|
* - `proxy`: Proxy details to use for proxy by-passing and authentication
|
||||||
|
* (Requests_Proxy|array|boolean, default: false)
|
||||||
|
* - `idn`: Enable IDN parsing
|
||||||
|
* (boolean, default: true)
|
||||||
|
* - `transport`: Custom transport. Either a class name, or a
|
||||||
|
* transport object. Defaults to the first working transport from
|
||||||
|
* {@see getTransport()}
|
||||||
|
* (string|Requests_Transport, default: {@see getTransport()})
|
||||||
|
* - `hooks`: Hooks handler.
|
||||||
|
* (Requests_Hooker, default: new Requests_Hooks())
|
||||||
|
* - `verify`: Should we verify SSL certificates? Allows passing in a custom
|
||||||
|
* certificate file as a string. (Using true uses the system-wide root
|
||||||
|
* certificate store instead, but this may have different behaviour
|
||||||
|
* across transports.)
|
||||||
|
* (string|boolean, default: library/Requests/Transport/cacert.pem)
|
||||||
|
* - `verifyname`: Should we verify the common name in the SSL certificate?
|
||||||
|
* (boolean: default, true)
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On invalid URLs (`nonhttp`)
|
||||||
|
*
|
||||||
|
* @param string $url URL to request
|
||||||
|
* @param array $headers Extra headers to send with the request
|
||||||
|
* @param array $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
|
||||||
|
* @param string $type HTTP request type (use Requests constants)
|
||||||
|
* @param array $options Options for the request (see description for more information)
|
||||||
|
* @return Requests_Response
|
||||||
|
*/
|
||||||
|
public static function request($url, $headers = array(), $data = array(), $type = self::GET, $options = array()) {
|
||||||
|
if (empty($options['type'])) {
|
||||||
|
$options['type'] = $type;
|
||||||
|
}
|
||||||
|
$options = array_merge(self::get_default_options(), $options);
|
||||||
|
|
||||||
|
self::set_defaults($url, $headers, $data, $type, $options);
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options));
|
||||||
|
|
||||||
|
if (!empty($options['transport'])) {
|
||||||
|
$transport = $options['transport'];
|
||||||
|
|
||||||
|
if (is_string($options['transport'])) {
|
||||||
|
$transport = new $transport();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$transport = self::get_transport();
|
||||||
|
}
|
||||||
|
$response = $transport->request($url, $headers, $data, $options);
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options));
|
||||||
|
|
||||||
|
return self::parse_response($response, $url, $headers, $data, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send multiple HTTP requests simultaneously
|
||||||
|
*
|
||||||
|
* The `$requests` parameter takes an associative or indexed array of
|
||||||
|
* request fields. The key of each request can be used to match up the
|
||||||
|
* request with the returned data, or with the request passed into your
|
||||||
|
* `multiple.request.complete` callback.
|
||||||
|
*
|
||||||
|
* The request fields value is an associative array with the following keys:
|
||||||
|
*
|
||||||
|
* - `url`: Request URL Same as the `$url` parameter to
|
||||||
|
* {@see Requests::request}
|
||||||
|
* (string, required)
|
||||||
|
* - `headers`: Associative array of header fields. Same as the `$headers`
|
||||||
|
* parameter to {@see Requests::request}
|
||||||
|
* (array, default: `array()`)
|
||||||
|
* - `data`: Associative array of data fields or a string. Same as the
|
||||||
|
* `$data` parameter to {@see Requests::request}
|
||||||
|
* (array|string, default: `array()`)
|
||||||
|
* - `type`: HTTP request type (use Requests constants). Same as the `$type`
|
||||||
|
* parameter to {@see Requests::request}
|
||||||
|
* (string, default: `Requests::GET`)
|
||||||
|
* - `data`: Associative array of options. Same as the `$options` parameter
|
||||||
|
* to {@see Requests::request}
|
||||||
|
* (array, default: see {@see Requests::request})
|
||||||
|
* - `cookies`: Associative array of cookie name to value, or cookie jar.
|
||||||
|
* (array|Requests_Cookie_Jar)
|
||||||
|
*
|
||||||
|
* If the `$options` parameter is specified, individual requests will
|
||||||
|
* inherit options from it. This can be used to use a single hooking system,
|
||||||
|
* or set all the types to `Requests::POST`, for example.
|
||||||
|
*
|
||||||
|
* In addition, the `$options` parameter takes the following global options:
|
||||||
|
*
|
||||||
|
* - `complete`: A callback for when a request is complete. Takes two
|
||||||
|
* parameters, a Requests_Response/Requests_Exception reference, and the
|
||||||
|
* ID from the request array (Note: this can also be overridden on a
|
||||||
|
* per-request basis, although that's a little silly)
|
||||||
|
* (callback)
|
||||||
|
*
|
||||||
|
* @param array $requests Requests data (see description for more information)
|
||||||
|
* @param array $options Global and default options (see {@see Requests::request})
|
||||||
|
* @return array Responses (either Requests_Response or a Requests_Exception object)
|
||||||
|
*/
|
||||||
|
public static function request_multiple($requests, $options = array()) {
|
||||||
|
$options = array_merge(self::get_default_options(true), $options);
|
||||||
|
|
||||||
|
if (!empty($options['hooks'])) {
|
||||||
|
$options['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
|
||||||
|
if (!empty($options['complete'])) {
|
||||||
|
$options['hooks']->register('multiple.request.complete', $options['complete']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($requests as $id => &$request) {
|
||||||
|
if (!isset($request['headers'])) {
|
||||||
|
$request['headers'] = array();
|
||||||
|
}
|
||||||
|
if (!isset($request['data'])) {
|
||||||
|
$request['data'] = array();
|
||||||
|
}
|
||||||
|
if (!isset($request['type'])) {
|
||||||
|
$request['type'] = self::GET;
|
||||||
|
}
|
||||||
|
if (!isset($request['options'])) {
|
||||||
|
$request['options'] = $options;
|
||||||
|
$request['options']['type'] = $request['type'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (empty($request['options']['type'])) {
|
||||||
|
$request['options']['type'] = $request['type'];
|
||||||
|
}
|
||||||
|
$request['options'] = array_merge($options, $request['options']);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']);
|
||||||
|
|
||||||
|
// Ensure we only hook in once
|
||||||
|
if ($request['options']['hooks'] !== $options['hooks']) {
|
||||||
|
$request['options']['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
|
||||||
|
if (!empty($request['options']['complete'])) {
|
||||||
|
$request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($request);
|
||||||
|
|
||||||
|
if (!empty($options['transport'])) {
|
||||||
|
$transport = $options['transport'];
|
||||||
|
|
||||||
|
if (is_string($options['transport'])) {
|
||||||
|
$transport = new $transport();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$transport = self::get_transport();
|
||||||
|
}
|
||||||
|
$responses = $transport->request_multiple($requests, $options);
|
||||||
|
|
||||||
|
foreach ($responses as $id => &$response) {
|
||||||
|
// If our hook got messed with somehow, ensure we end up with the
|
||||||
|
// correct response
|
||||||
|
if (is_string($response)) {
|
||||||
|
$request = $requests[$id];
|
||||||
|
self::parse_multiple($response, $request);
|
||||||
|
$request['options']['hooks']->dispatch('multiple.request.complete', array(&$response, $id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default options
|
||||||
|
*
|
||||||
|
* @see Requests::request() for values returned by this method
|
||||||
|
* @param boolean $multirequest Is this a multirequest?
|
||||||
|
* @return array Default option values
|
||||||
|
*/
|
||||||
|
protected static function get_default_options($multirequest = false) {
|
||||||
|
$defaults = array(
|
||||||
|
'timeout' => 10,
|
||||||
|
'useragent' => 'php-requests/' . self::VERSION,
|
||||||
|
'redirected' => 0,
|
||||||
|
'redirects' => 10,
|
||||||
|
'follow_redirects' => true,
|
||||||
|
'blocking' => true,
|
||||||
|
'type' => self::GET,
|
||||||
|
'filename' => false,
|
||||||
|
'auth' => false,
|
||||||
|
'proxy' => false,
|
||||||
|
'cookies' => false,
|
||||||
|
'idn' => true,
|
||||||
|
'hooks' => null,
|
||||||
|
'transport' => null,
|
||||||
|
'verify' => dirname( __FILE__ ) . '/Requests/Transport/cacert.pem',
|
||||||
|
'verifyname' => true,
|
||||||
|
);
|
||||||
|
if ($multirequest !== false) {
|
||||||
|
$defaults['complete'] = null;
|
||||||
|
}
|
||||||
|
return $defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default values
|
||||||
|
*
|
||||||
|
* @param string $url URL to request
|
||||||
|
* @param array $headers Extra headers to send with the request
|
||||||
|
* @param array $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
|
||||||
|
* @param string $type HTTP request type
|
||||||
|
* @param array $options Options for the request
|
||||||
|
* @return array $options
|
||||||
|
*/
|
||||||
|
protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) {
|
||||||
|
if (!preg_match('/^http(s)?:\/\//i', $url)) {
|
||||||
|
throw new Requests_Exception('Only HTTP requests are handled.', 'nonhttp', $url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($options['hooks'])) {
|
||||||
|
$options['hooks'] = new Requests_Hooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($options['auth'])) {
|
||||||
|
$options['auth'] = new Requests_Auth_Basic($options['auth']);
|
||||||
|
}
|
||||||
|
if ($options['auth'] !== false) {
|
||||||
|
$options['auth']->register($options['hooks']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($options['proxy'])) {
|
||||||
|
$options['proxy'] = new Requests_Proxy_HTTP($options['proxy']);
|
||||||
|
}
|
||||||
|
if ($options['proxy'] !== false) {
|
||||||
|
$options['proxy']->register($options['hooks']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($options['cookies'])) {
|
||||||
|
$options['cookies'] = new Requests_Cookie_Jar($options['cookies']);
|
||||||
|
}
|
||||||
|
elseif (empty($options['cookies'])) {
|
||||||
|
$options['cookies'] = new Requests_Cookie_Jar();
|
||||||
|
}
|
||||||
|
if ($options['cookies'] !== false) {
|
||||||
|
$options['cookies']->register($options['hooks']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options['idn'] !== false) {
|
||||||
|
$iri = new Requests_IRI($url);
|
||||||
|
$iri->host = Requests_IDNAEncoder::encode($iri->ihost);
|
||||||
|
$url = $iri->uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP response parser
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On missing head/body separator (`requests.no_crlf_separator`)
|
||||||
|
* @throws Requests_Exception On missing head/body separator (`noversion`)
|
||||||
|
* @throws Requests_Exception On missing head/body separator (`toomanyredirects`)
|
||||||
|
*
|
||||||
|
* @param string $headers Full response text including headers and body
|
||||||
|
* @param string $url Original request URL
|
||||||
|
* @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects
|
||||||
|
* @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects
|
||||||
|
* @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects
|
||||||
|
* @return Requests_Response
|
||||||
|
*/
|
||||||
|
protected static function parse_response($headers, $url, $req_headers, $req_data, $options) {
|
||||||
|
$return = new Requests_Response();
|
||||||
|
if (!$options['blocking']) {
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$return->raw = $headers;
|
||||||
|
$return->url = $url;
|
||||||
|
|
||||||
|
if (!$options['filename']) {
|
||||||
|
if (($pos = strpos($headers, "\r\n\r\n")) === false) {
|
||||||
|
// Crap!
|
||||||
|
throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator');
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = substr($return->raw, 0, $pos);
|
||||||
|
$return->body = substr($return->raw, $pos + strlen("\n\r\n\r"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$return->body = '';
|
||||||
|
}
|
||||||
|
// Pretend CRLF = LF for compatibility (RFC 2616, section 19.3)
|
||||||
|
$headers = str_replace("\r\n", "\n", $headers);
|
||||||
|
// Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2)
|
||||||
|
$headers = preg_replace('/\n[ \t]/', ' ', $headers);
|
||||||
|
$headers = explode("\n", $headers);
|
||||||
|
preg_match('#^HTTP/1\.\d[ \t]+(\d+)#i', array_shift($headers), $matches);
|
||||||
|
if (empty($matches)) {
|
||||||
|
throw new Requests_Exception('Response could not be parsed', 'noversion', $headers);
|
||||||
|
}
|
||||||
|
$return->status_code = (int) $matches[1];
|
||||||
|
if ($return->status_code >= 200 && $return->status_code < 300) {
|
||||||
|
$return->success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($headers as $header) {
|
||||||
|
list($key, $value) = explode(':', $header, 2);
|
||||||
|
$value = trim($value);
|
||||||
|
preg_replace('#(\s+)#i', ' ', $value);
|
||||||
|
$return->headers[$key] = $value;
|
||||||
|
}
|
||||||
|
if (isset($return->headers['transfer-encoding'])) {
|
||||||
|
$return->body = self::decode_chunked($return->body);
|
||||||
|
unset($return->headers['transfer-encoding']);
|
||||||
|
}
|
||||||
|
if (isset($return->headers['content-encoding'])) {
|
||||||
|
$return->body = self::decompress($return->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
//fsockopen and cURL compatibility
|
||||||
|
if (isset($return->headers['connection'])) {
|
||||||
|
unset($return->headers['connection']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('requests.before_redirect_check', array(&$return, $req_headers, $req_data, $options));
|
||||||
|
|
||||||
|
if ((in_array($return->status_code, array(300, 301, 302, 303, 307)) || $return->status_code > 307 && $return->status_code < 400) && $options['follow_redirects'] === true) {
|
||||||
|
if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) {
|
||||||
|
if ($return->status_code === 303) {
|
||||||
|
$options['type'] = Requests::GET;
|
||||||
|
}
|
||||||
|
$options['redirected']++;
|
||||||
|
$location = $return->headers['location'];
|
||||||
|
if (strpos ($location, '/') === 0) {
|
||||||
|
// relative redirect, for compatibility make it absolute
|
||||||
|
$location = Requests_IRI::absolutize($url, $location);
|
||||||
|
$location = $location->uri;
|
||||||
|
}
|
||||||
|
$redirected = self::request($location, $req_headers, $req_data, false, $options);
|
||||||
|
$redirected->history[] = $return;
|
||||||
|
return $redirected;
|
||||||
|
}
|
||||||
|
elseif ($options['redirected'] >= $options['redirects']) {
|
||||||
|
throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$return->redirects = $options['redirected'];
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options));
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for `transport.internal.parse_response`
|
||||||
|
*
|
||||||
|
* Internal use only. Converts a raw HTTP response to a Requests_Response
|
||||||
|
* while still executing a multiple request.
|
||||||
|
*
|
||||||
|
* @param string $headers Full response text including headers and body
|
||||||
|
* @param array $request Request data as passed into {@see Requests::request_multiple()}
|
||||||
|
* @return null `$response` is either set to a Requests_Response instance, or a Requests_Exception object
|
||||||
|
*/
|
||||||
|
public static function parse_multiple(&$response, $request) {
|
||||||
|
try {
|
||||||
|
$response = self::parse_response($response, $request['url'], $request['headers'], $request['data'], $request['options']);
|
||||||
|
}
|
||||||
|
catch (Requests_Exception $e) {
|
||||||
|
$response = $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decoded a chunked body as per RFC 2616
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc2616#section-3.6.1
|
||||||
|
* @param string $data Chunked body
|
||||||
|
* @return string Decoded body
|
||||||
|
*/
|
||||||
|
protected static function decode_chunked($data) {
|
||||||
|
if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($data))) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = '';
|
||||||
|
$encoded = $data;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
$is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
|
||||||
|
if (!$is_chunked) {
|
||||||
|
// Looks like it's not chunked after all
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$length = hexdec(trim($matches[1]));
|
||||||
|
if ($length === 0) {
|
||||||
|
// Ignore trailer headers
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
$chunk_length = strlen($matches[0]);
|
||||||
|
$decoded .= $part = substr($encoded, $chunk_length, $length);
|
||||||
|
$encoded = substr($encoded, $chunk_length + $length + 2);
|
||||||
|
|
||||||
|
if (trim($encoded) === '0' || empty($encoded)) {
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll never actually get down here
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a key => value array to a 'key: value' array for headers
|
||||||
|
*
|
||||||
|
* @param array $array Dictionary of header values
|
||||||
|
* @return array List of headers
|
||||||
|
*/
|
||||||
|
public static function flatten($array) {
|
||||||
|
$return = array();
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
$return[] = "$key: $value";
|
||||||
|
}
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a key => value array to a 'key: value' array for headers
|
||||||
|
*
|
||||||
|
* @deprecated Misspelling of {@see Requests::flatten}
|
||||||
|
* @param array $array Dictionary of header values
|
||||||
|
* @return array List of headers
|
||||||
|
*/
|
||||||
|
public static function flattern($array) {
|
||||||
|
return self::flatten($array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompress an encoded body
|
||||||
|
*
|
||||||
|
* Implements gzip, compress and deflate. Guesses which it is by attempting
|
||||||
|
* to decode.
|
||||||
|
*
|
||||||
|
* @todo Make this smarter by defaulting to whatever the headers say first
|
||||||
|
* @param string $data Compressed data in one of the above formats
|
||||||
|
* @return string Decompressed string
|
||||||
|
*/
|
||||||
|
public static function decompress($data) {
|
||||||
|
if (substr($data, 0, 2) !== "\x1f\x8b" && substr($data, 0, 2) !== "\x78\x9c") {
|
||||||
|
// Not actually compressed. Probably cURL ruining this for us.
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('gzdecode') && ($decoded = @gzdecode($data)) !== false) {
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
elseif (function_exists('gzinflate') && ($decoded = @gzinflate($data)) !== false) {
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
elseif (($decoded = self::compatible_gzinflate($data)) !== false) {
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
elseif (function_exists('gzuncompress') && ($decoded = @gzuncompress($data)) !== false) {
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompression of deflated string while staying compatible with the majority of servers.
|
||||||
|
*
|
||||||
|
* Certain Servers will return deflated data with headers which PHP's gzinflate()
|
||||||
|
* function cannot handle out of the box. The following function has been created from
|
||||||
|
* various snippets on the gzinflate() PHP documentation.
|
||||||
|
*
|
||||||
|
* Warning: Magic numbers within. Due to the potential different formats that the compressed
|
||||||
|
* data may be returned in, some "magic offsets" are needed to ensure proper decompression
|
||||||
|
* takes place. For a simple progmatic way to determine the magic offset in use, see:
|
||||||
|
* http://core.trac.wordpress.org/ticket/18273
|
||||||
|
*
|
||||||
|
* @since 2.8.1
|
||||||
|
* @link http://core.trac.wordpress.org/ticket/18273
|
||||||
|
* @link http://au2.php.net/manual/en/function.gzinflate.php#70875
|
||||||
|
* @link http://au2.php.net/manual/en/function.gzinflate.php#77336
|
||||||
|
*
|
||||||
|
* @param string $gzData String to decompress.
|
||||||
|
* @return string|bool False on failure.
|
||||||
|
*/
|
||||||
|
public static function compatible_gzinflate($gzData) {
|
||||||
|
// Compressed data might contain a full zlib header, if so strip it for
|
||||||
|
// gzinflate()
|
||||||
|
if ( substr($gzData, 0, 3) == "\x1f\x8b\x08" ) {
|
||||||
|
$i = 10;
|
||||||
|
$flg = ord( substr($gzData, 3, 1) );
|
||||||
|
if ( $flg > 0 ) {
|
||||||
|
if ( $flg & 4 ) {
|
||||||
|
list($xlen) = unpack('v', substr($gzData, $i, 2) );
|
||||||
|
$i = $i + 2 + $xlen;
|
||||||
|
}
|
||||||
|
if ( $flg & 8 )
|
||||||
|
$i = strpos($gzData, "\0", $i) + 1;
|
||||||
|
if ( $flg & 16 )
|
||||||
|
$i = strpos($gzData, "\0", $i) + 1;
|
||||||
|
if ( $flg & 2 )
|
||||||
|
$i = $i + 2;
|
||||||
|
}
|
||||||
|
$decompressed = self::compatible_gzinflate( substr( $gzData, $i ) );
|
||||||
|
if ( false !== $decompressed ) {
|
||||||
|
return $decompressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the data is Huffman Encoded, we must first strip the leading 2
|
||||||
|
// byte Huffman marker for gzinflate()
|
||||||
|
// The response is Huffman coded by many compressors such as
|
||||||
|
// java.util.zip.Deflater, Ruby’s Zlib::Deflate, and .NET's
|
||||||
|
// System.IO.Compression.DeflateStream.
|
||||||
|
//
|
||||||
|
// See http://decompres.blogspot.com/ for a quick explanation of this
|
||||||
|
// data type
|
||||||
|
$huffman_encoded = false;
|
||||||
|
|
||||||
|
// low nibble of first byte should be 0x08
|
||||||
|
list( , $first_nibble ) = unpack( 'h', $gzData );
|
||||||
|
|
||||||
|
// First 2 bytes should be divisible by 0x1F
|
||||||
|
list( , $first_two_bytes ) = unpack( 'n', $gzData );
|
||||||
|
|
||||||
|
if ( 0x08 == $first_nibble && 0 == ( $first_two_bytes % 0x1F ) )
|
||||||
|
$huffman_encoded = true;
|
||||||
|
|
||||||
|
if ( $huffman_encoded ) {
|
||||||
|
if ( false !== ( $decompressed = @gzinflate( substr( $gzData, 2 ) ) ) )
|
||||||
|
return $decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( "\x50\x4b\x03\x04" == substr( $gzData, 0, 4 ) ) {
|
||||||
|
// ZIP file format header
|
||||||
|
// Offset 6: 2 bytes, General-purpose field
|
||||||
|
// Offset 26: 2 bytes, filename length
|
||||||
|
// Offset 28: 2 bytes, optional field length
|
||||||
|
// Offset 30: Filename field, followed by optional field, followed
|
||||||
|
// immediately by data
|
||||||
|
list( , $general_purpose_flag ) = unpack( 'v', substr( $gzData, 6, 2 ) );
|
||||||
|
|
||||||
|
// If the file has been compressed on the fly, 0x08 bit is set of
|
||||||
|
// the general purpose field. We can use this to differentiate
|
||||||
|
// between a compressed document, and a ZIP file
|
||||||
|
$zip_compressed_on_the_fly = ( 0x08 == (0x08 & $general_purpose_flag ) );
|
||||||
|
|
||||||
|
if ( ! $zip_compressed_on_the_fly ) {
|
||||||
|
// Don't attempt to decode a compressed zip file
|
||||||
|
return $gzData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the first byte of data, based on the above ZIP header
|
||||||
|
// offsets:
|
||||||
|
$first_file_start = array_sum( unpack( 'v2', substr( $gzData, 26, 4 ) ) );
|
||||||
|
if ( false !== ( $decompressed = @gzinflate( substr( $gzData, 30 + $first_file_start ) ) ) ) {
|
||||||
|
return $decompressed;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally fall back to straight gzinflate
|
||||||
|
if ( false !== ( $decompressed = @gzinflate( $gzData ) ) ) {
|
||||||
|
return $decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for all above failing, not expected, but included for
|
||||||
|
// debugging and preventing regressions and to track stats
|
||||||
|
if ( false !== ( $decompressed = @gzinflate( substr( $gzData, 2 ) ) ) ) {
|
||||||
|
return $decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function match_domain($host, $reference) {
|
||||||
|
// Check for a direct match
|
||||||
|
if ($host === $reference) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the valid wildcard match if the host is not an IP address
|
||||||
|
// Also validates that the host has 3 parts or more, as per Firefox's
|
||||||
|
// ruleset.
|
||||||
|
$parts = explode('.', $host);
|
||||||
|
if (ip2long($host) === false && count($parts) >= 3) {
|
||||||
|
$parts[0] = '*';
|
||||||
|
$wildcard = implode('.', $parts);
|
||||||
|
if ($wildcard === $reference) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
33
source/includes/Requests/Requests/Auth.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Authentication provider interface
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Authentication
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication provider interface
|
||||||
|
*
|
||||||
|
* Implement this interface to act as an authentication provider.
|
||||||
|
*
|
||||||
|
* Parameters should be passed via the constructor where possible, as this
|
||||||
|
* makes it much easier for users to use your provider.
|
||||||
|
*
|
||||||
|
* @see Requests_Hooks
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Authentication
|
||||||
|
*/
|
||||||
|
interface Requests_Auth {
|
||||||
|
/**
|
||||||
|
* Register hooks as needed
|
||||||
|
*
|
||||||
|
* This method is called in {@see Requests::request} when the user has set
|
||||||
|
* an instance as the 'auth' option. Use this callback to register all the
|
||||||
|
* hooks you'll need.
|
||||||
|
*
|
||||||
|
* @see Requests_Hooks::register
|
||||||
|
* @param Requests_Hooks $hooks Hook system
|
||||||
|
*/
|
||||||
|
public function register(Requests_Hooks &$hooks);
|
||||||
|
}
|
88
source/includes/Requests/Requests/Auth/Basic.php
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Basic Authentication provider
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Authentication
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic Authentication provider
|
||||||
|
*
|
||||||
|
* Provides a handler for Basic HTTP authentication via the Authorization
|
||||||
|
* header.
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Authentication
|
||||||
|
*/
|
||||||
|
class Requests_Auth_Basic implements Requests_Auth {
|
||||||
|
/**
|
||||||
|
* Username
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Password
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $pass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On incorrect number of arguments (`authbasicbadargs`)
|
||||||
|
* @param array|null $args Array of user and password. Must have exactly two elements
|
||||||
|
*/
|
||||||
|
public function __construct($args = null) {
|
||||||
|
if (is_array($args)) {
|
||||||
|
if (count($args) !== 2) {
|
||||||
|
throw new Requests_Exception('Invalid number of arguments', 'authbasicbadargs');
|
||||||
|
}
|
||||||
|
|
||||||
|
list($this->user, $this->pass) = $args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the necessary callbacks
|
||||||
|
*
|
||||||
|
* @see curl_before_send
|
||||||
|
* @see fsockopen_header
|
||||||
|
* @param Requests_Hooks $hooks Hook system
|
||||||
|
*/
|
||||||
|
public function register(Requests_Hooks &$hooks) {
|
||||||
|
$hooks->register('curl.before_send', array(&$this, 'curl_before_send'));
|
||||||
|
$hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set cURL parameters before the data is sent
|
||||||
|
*
|
||||||
|
* @param resource $handle cURL resource
|
||||||
|
*/
|
||||||
|
public function curl_before_send(&$handle) {
|
||||||
|
curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||||
|
curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add extra headers to the request before sending
|
||||||
|
*
|
||||||
|
* @param string $out HTTP header string
|
||||||
|
*/
|
||||||
|
public function fsockopen_header(&$out) {
|
||||||
|
$out .= "Authorization: Basic " . base64_encode($this->getAuthString()) . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the authentication string (user:pass)
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAuthString() {
|
||||||
|
return $this->user . ':' . $this->pass;
|
||||||
|
}
|
||||||
|
}
|
171
source/includes/Requests/Requests/Cookie.php
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Cookie storage object
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Cookies
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie storage object
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Cookies
|
||||||
|
*/
|
||||||
|
class Requests_Cookie {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie attributes
|
||||||
|
*
|
||||||
|
* Valid keys are (currently) path, domain, expires, max-age, secure and
|
||||||
|
* httponly.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $attributes = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new cookie object
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string $value
|
||||||
|
* @param array $attributes Associative array of attribute data
|
||||||
|
*/
|
||||||
|
public function __construct($name, $value, $attributes = array()) {
|
||||||
|
$this->name = $name;
|
||||||
|
$this->value = $value;
|
||||||
|
$this->attributes = $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a cookie for a Cookie header
|
||||||
|
*
|
||||||
|
* This is used when sending cookies to a server.
|
||||||
|
*
|
||||||
|
* @return string Cookie formatted for Cookie header
|
||||||
|
*/
|
||||||
|
public function formatForHeader() {
|
||||||
|
return sprintf('%s=%s', $this->name, $this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a cookie for a Set-Cookie header
|
||||||
|
*
|
||||||
|
* This is used when sending cookies to clients. This isn't really
|
||||||
|
* applicable to client-side usage, but might be handy for debugging.
|
||||||
|
*
|
||||||
|
* @return string Cookie formatted for Set-Cookie header
|
||||||
|
*/
|
||||||
|
public function formatForSetCookie() {
|
||||||
|
$header_value = $this->formatForHeader();
|
||||||
|
if (!empty($this->attributes)) {
|
||||||
|
$parts = array();
|
||||||
|
foreach ($this->attributes as $key => $value) {
|
||||||
|
// Ignore non-associative attributes
|
||||||
|
if (is_numeric($key)) {
|
||||||
|
$parts[] = $value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$parts[] = sprintf('%s=%s', $key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$header_value .= '; ' . implode('; ', $parts);
|
||||||
|
}
|
||||||
|
return $header_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cookie value
|
||||||
|
*
|
||||||
|
* Attributes and other data can be accessed via methods.
|
||||||
|
*/
|
||||||
|
public function __toString() {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a cookie string into a cookie object
|
||||||
|
*
|
||||||
|
* Based on Mozilla's parsing code in Firefox and related projects, which
|
||||||
|
* is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265
|
||||||
|
* specifies some of this handling, but not in a thorough manner.
|
||||||
|
*
|
||||||
|
* @param string Cookie header value (from a Set-Cookie header)
|
||||||
|
* @return Requests_Cookie Parsed cookie object
|
||||||
|
*/
|
||||||
|
public static function parse($string, $name = '') {
|
||||||
|
$parts = explode(';', $string);
|
||||||
|
$kvparts = array_shift($parts);
|
||||||
|
|
||||||
|
if (!empty($name)) {
|
||||||
|
$value = $string;
|
||||||
|
}
|
||||||
|
elseif (strpos($kvparts, '=') === false) {
|
||||||
|
// Some sites might only have a value without the equals separator.
|
||||||
|
// Deviate from RFC 6265 and pretend it was actually a blank name
|
||||||
|
// (`=foo`)
|
||||||
|
//
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=169091
|
||||||
|
$name = '';
|
||||||
|
$value = $kvparts;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list($name, $value) = explode('=', $kvparts, 2);
|
||||||
|
}
|
||||||
|
$name = trim($name);
|
||||||
|
$value = trim($value);
|
||||||
|
|
||||||
|
// Attribute key are handled case-insensitively
|
||||||
|
$attributes = new Requests_Utility_CaseInsensitiveDictionary();
|
||||||
|
|
||||||
|
if (!empty($parts)) {
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if (strpos($part, '=') === false) {
|
||||||
|
$part_key = $part;
|
||||||
|
$part_value = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list($part_key, $part_value) = explode('=', $part, 2);
|
||||||
|
$part_value = trim($part_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$part_key = trim($part_key);
|
||||||
|
$attributes[$part_key] = $part_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Requests_Cookie($name, $value, $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse all Set-Cookie headers from request headers
|
||||||
|
*
|
||||||
|
* @param Requests_Response_Headers $headers
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function parseFromHeaders(Requests_Response_Headers $headers) {
|
||||||
|
$cookie_headers = $headers->getValues('Set-Cookie');
|
||||||
|
if (empty($cookie_headers)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$cookies = array();
|
||||||
|
foreach ($cookie_headers as $header) {
|
||||||
|
$parsed = self::parse($header);
|
||||||
|
$cookies[$parsed->name] = $parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cookies;
|
||||||
|
}
|
||||||
|
}
|
146
source/includes/Requests/Requests/Cookie/Jar.php
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Cookie holder object
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Cookies
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie holder object
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Cookies
|
||||||
|
*/
|
||||||
|
class Requests_Cookie_Jar implements ArrayAccess, IteratorAggregate {
|
||||||
|
/**
|
||||||
|
* Actual item data
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $cookies = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new jar
|
||||||
|
*
|
||||||
|
* @param array $cookies Existing cookie values
|
||||||
|
*/
|
||||||
|
public function __construct($cookies = array()) {
|
||||||
|
$this->cookies = $cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalise cookie data into a Requests_Cookie
|
||||||
|
*
|
||||||
|
* @param string|Requests_Cookie $cookie
|
||||||
|
* @return Requests_Cookie
|
||||||
|
*/
|
||||||
|
public function normalizeCookie($cookie, $key = null) {
|
||||||
|
if ($cookie instanceof Requests_Cookie) {
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Requests_Cookie::parse($cookie, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given item exists
|
||||||
|
*
|
||||||
|
* @param string $key Item key
|
||||||
|
* @return boolean Does the item exist?
|
||||||
|
*/
|
||||||
|
public function offsetExists($key) {
|
||||||
|
return isset($this->cookies[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value for the item
|
||||||
|
*
|
||||||
|
* @param string $key Item key
|
||||||
|
* @return string Item value
|
||||||
|
*/
|
||||||
|
public function offsetGet($key) {
|
||||||
|
if (!isset($this->cookies[$key]))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return $this->cookies[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the given item
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
|
||||||
|
*
|
||||||
|
* @param string $key Item name
|
||||||
|
* @param string $value Item value
|
||||||
|
*/
|
||||||
|
public function offsetSet($key, $value) {
|
||||||
|
if ($key === null) {
|
||||||
|
throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cookies[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unset the given header
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
public function offsetUnset($key) {
|
||||||
|
unset($this->cookies[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an iterator for the data
|
||||||
|
*
|
||||||
|
* @return ArrayIterator
|
||||||
|
*/
|
||||||
|
public function getIterator() {
|
||||||
|
return new ArrayIterator($this->cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the cookie handler with the request's hooking system
|
||||||
|
*
|
||||||
|
* @param Requests_Hooker $hooks Hooking system
|
||||||
|
*/
|
||||||
|
public function register(Requests_Hooker $hooks) {
|
||||||
|
$hooks->register('requests.before_request', array($this, 'before_request'));
|
||||||
|
$hooks->register('requests.before_redirect_check', array($this, 'before_redirect_check'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Cookie header to a request if we have any
|
||||||
|
*
|
||||||
|
* As per RFC 6265, cookies are separated by '; '
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param array $headers
|
||||||
|
* @param array $data
|
||||||
|
* @param string $type
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public function before_request(&$url, &$headers, &$data, &$type, &$options) {
|
||||||
|
if (!empty($this->cookies)) {
|
||||||
|
$cookies = array();
|
||||||
|
foreach ($this->cookies as $key => $cookie) {
|
||||||
|
$cookie = $this->normalizeCookie($cookie, $key);
|
||||||
|
$cookies[] = $cookie->formatForHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers['Cookie'] = implode('; ', $cookies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse all cookies from a response and attach them to the response
|
||||||
|
*
|
||||||
|
* @var Requests_Response $response
|
||||||
|
*/
|
||||||
|
public function before_redirect_check(Requests_Response &$return) {
|
||||||
|
$cookies = Requests_Cookie::parseFromHeaders($return->headers);
|
||||||
|
$this->cookies = array_merge($this->cookies, $cookies);
|
||||||
|
$return->cookies = $this;
|
||||||
|
}
|
||||||
|
}
|
62
source/includes/Requests/Requests/Exception.php
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for HTTP requests
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for HTTP requests
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception extends Exception {
|
||||||
|
/**
|
||||||
|
* Type of exception
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data associated with the exception
|
||||||
|
*
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
protected $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new exception
|
||||||
|
*
|
||||||
|
* @param string $message Exception message
|
||||||
|
* @param string $type Exception type
|
||||||
|
* @param mixed $data Associated data
|
||||||
|
* @param integer $code Exception numerical code, if applicable
|
||||||
|
*/
|
||||||
|
public function __construct($message, $type, $data = null, $code = 0) {
|
||||||
|
parent::__construct($message, $code);
|
||||||
|
|
||||||
|
$this->type = $type;
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like {@see getCode()}, but a string code.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType() {
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives any relevant data
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getData() {
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
}
|
67
source/includes/Requests/Requests/Exception/HTTP.php
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception based on HTTP response
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception based on HTTP response
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP extends Requests_Exception {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Unknown';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new exception
|
||||||
|
*
|
||||||
|
* There is no mechanism to pass in the status code, as this is set by the
|
||||||
|
* subclass used. Reason phrases can vary, however.
|
||||||
|
*
|
||||||
|
* @param string $reason Reason phrase
|
||||||
|
* @param mixed $data Associated data
|
||||||
|
*/
|
||||||
|
public function __construct($reason = null, $data = null) {
|
||||||
|
if ($reason !== null) {
|
||||||
|
$this->reason = $reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = sprintf('%d %s', $this->code, $this->reason);
|
||||||
|
parent::__construct($message, 'httpresponse', $data, $this->code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the status message
|
||||||
|
*/
|
||||||
|
public function getReason() {
|
||||||
|
return $this->reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the correct exception class for a given error code
|
||||||
|
*
|
||||||
|
* @param int $code HTTP status code
|
||||||
|
* @return string Exception class name to use
|
||||||
|
*/
|
||||||
|
public static function get_class($code) {
|
||||||
|
$class = sprintf('Requests_Exception_HTTP_%d', $code);
|
||||||
|
if (class_exists($class)) {
|
||||||
|
return $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Requests_Exception_HTTP_Unknown';
|
||||||
|
}
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/400.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 400 Bad Request responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 400 Bad Request responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_400 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 400;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Bad Request';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/401.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 401 Unauthorized responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 401 Unauthorized responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_401 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 401;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Unauthorized';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/402.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 402 Payment Required responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 402 Payment Required responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_402 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 402;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Payment Required';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/403.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 403 Forbidden responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 403 Forbidden responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_403 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 403;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Forbidden';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/404.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 404 Not Found responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 404 Not Found responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_404 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 404;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Not Found';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/405.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 405 Method Not Allowed responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 405 Method Not Allowed responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_405 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 405;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Method Not Allowed';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/406.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 406 Not Acceptable responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 406 Not Acceptable responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_406 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 406;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Not Acceptable';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/407.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 407 Proxy Authentication Required responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 407 Proxy Authentication Required responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_407 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 407;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Proxy Authentication Required';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/408.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 408 Request Timeout responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 408 Request Timeout responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_408 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 408;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Request Timeout';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/409.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 409 Conflict responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 409 Conflict responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_409 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 409;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Conflict';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/410.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 410 Gone responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 410 Gone responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_410 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 410;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Gone';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/411.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 411 Length Required responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 411 Length Required responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_411 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 411;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Length Required';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/412.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 412 Precondition Failed responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 412 Precondition Failed responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_412 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 412;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Precondition Failed';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/413.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 413 Request Entity Too Large responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 413 Request Entity Too Large responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_413 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 413;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Request Entity Too Large';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/414.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 414 Request-URI Too Large responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 414 Request-URI Too Large responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_414 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 414;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Request-URI Too Large';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/415.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 415 Unsupported Media Type responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 415 Unsupported Media Type responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_415 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 415;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Unsupported Media Type';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/416.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 416 Requested Range Not Satisfiable responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 416 Requested Range Not Satisfiable responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_416 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 416;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Requested Range Not Satisfiable';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/417.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 417 Expectation Failed responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 417 Expectation Failed responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_417 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 417;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Expectation Failed';
|
||||||
|
}
|
29
source/includes/Requests/Requests/Exception/HTTP/418.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 418 I'm A Teapot responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc2324
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 418 I'm A Teapot responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc2324
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_418 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 418;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = "I'm A Teapot";
|
||||||
|
}
|
29
source/includes/Requests/Requests/Exception/HTTP/428.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 428 Precondition Required responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6585
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 428 Precondition Required responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6585
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_428 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 428;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Precondition Required';
|
||||||
|
}
|
29
source/includes/Requests/Requests/Exception/HTTP/429.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 429 Too Many Requests responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/draft-nottingham-http-new-status-04
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 429 Too Many Requests responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/draft-nottingham-http-new-status-04
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_429 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 429;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Too Many Requests';
|
||||||
|
}
|
29
source/includes/Requests/Requests/Exception/HTTP/431.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 431 Request Header Fields Too Large responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6585
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 431 Request Header Fields Too Large responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6585
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_431 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 431;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Request Header Fields Too Large';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/500.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 500 Internal Server Error responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 500 Internal Server Error responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_500 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Internal Server Error';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/501.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 501 Not Implemented responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 501 Not Implemented responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_501 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 501;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Not Implemented';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/502.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 502 Bad Gateway responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 502 Bad Gateway responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_502 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 502;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Bad Gateway';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/503.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 503 Service Unavailable responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 503 Service Unavailable responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_503 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 503;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Service Unavailable';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/504.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 504 Gateway Timeout responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 504 Gateway Timeout responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_504 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 504;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Gateway Timeout';
|
||||||
|
}
|
27
source/includes/Requests/Requests/Exception/HTTP/505.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 505 HTTP Version Not Supported responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 505 HTTP Version Not Supported responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_505 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 505;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'HTTP Version Not Supported';
|
||||||
|
}
|
29
source/includes/Requests/Requests/Exception/HTTP/511.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for 511 Network Authentication Required responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6585
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for 511 Network Authentication Required responses
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc6585
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_511 extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 511;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Network Authentication Required';
|
||||||
|
}
|
44
source/includes/Requests/Requests/Exception/HTTP/Unknown.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Exception for unknown status responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for unknown status responses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Exception_HTTP_Unknown extends Requests_Exception_HTTP {
|
||||||
|
/**
|
||||||
|
* HTTP status code
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $code = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reason phrase
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reason = 'Unknown';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new exception
|
||||||
|
*
|
||||||
|
* If `$data` is an instance of {@see Requests_Response}, uses the status
|
||||||
|
* code from it. Otherwise, sets as 0
|
||||||
|
*
|
||||||
|
* @param string $reason Reason phrase
|
||||||
|
* @param mixed $data Associated data
|
||||||
|
*/
|
||||||
|
public function __construct($reason = null, $data = null) {
|
||||||
|
if ($data instanceof Requests_Response) {
|
||||||
|
$this->code = $data->status_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($reason, $data);
|
||||||
|
}
|
||||||
|
}
|
33
source/includes/Requests/Requests/Hooker.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Event dispatcher
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event dispatcher
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
interface Requests_Hooker {
|
||||||
|
/**
|
||||||
|
* Register a callback for a hook
|
||||||
|
*
|
||||||
|
* @param string $hook Hook name
|
||||||
|
* @param callback $callback Function/method to call on event
|
||||||
|
* @param int $priority Priority number. <0 is executed earlier, >0 is executed later
|
||||||
|
*/
|
||||||
|
public function register($hook, $callback, $priority = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a message
|
||||||
|
*
|
||||||
|
* @param string $hook Hook name
|
||||||
|
* @param array $parameters Parameters to pass to callbacks
|
||||||
|
* @return boolean Successfulness
|
||||||
|
*/
|
||||||
|
public function dispatch($hook, $parameters = array());
|
||||||
|
}
|
61
source/includes/Requests/Requests/Hooks.php
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles adding and dispatching events
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles adding and dispatching events
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
class Requests_Hooks implements Requests_Hooker {
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback for a hook
|
||||||
|
*
|
||||||
|
* @param string $hook Hook name
|
||||||
|
* @param callback $callback Function/method to call on event
|
||||||
|
* @param int $priority Priority number. <0 is executed earlier, >0 is executed later
|
||||||
|
*/
|
||||||
|
public function register($hook, $callback, $priority = 0) {
|
||||||
|
if (!isset($this->hooks[$hook])) {
|
||||||
|
$this->hooks[$hook] = array();
|
||||||
|
}
|
||||||
|
if (!isset($this->hooks[$hook][$priority])) {
|
||||||
|
$this->hooks[$hook][$priority] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hooks[$hook][$priority][] = $callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a message
|
||||||
|
*
|
||||||
|
* @param string $hook Hook name
|
||||||
|
* @param array $parameters Parameters to pass to callbacks
|
||||||
|
* @return boolean Successfulness
|
||||||
|
*/
|
||||||
|
public function dispatch($hook, $parameters = array()) {
|
||||||
|
if (empty($this->hooks[$hook])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->hooks[$hook] as $priority => $hooked) {
|
||||||
|
foreach ($hooked as $callback) {
|
||||||
|
call_user_func_array($callback, $parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
390
source/includes/Requests/Requests/IDNAEncoder.php
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IDNA URL encoder
|
||||||
|
*
|
||||||
|
* Note: Not fully compliant, as nameprep does nothing yet.
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
* @see http://tools.ietf.org/html/rfc3490 IDNA specification
|
||||||
|
* @see http://tools.ietf.org/html/rfc3492 Punycode/Bootstrap specification
|
||||||
|
*/
|
||||||
|
class Requests_IDNAEncoder {
|
||||||
|
/**
|
||||||
|
* ACE prefix used for IDNA
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc3490#section-5
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const ACE_PREFIX = 'xn--';
|
||||||
|
|
||||||
|
/**#@+
|
||||||
|
* Bootstrap constant for Punycode
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc3492#section-5
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const BOOTSTRAP_BASE = 36;
|
||||||
|
const BOOTSTRAP_TMIN = 1;
|
||||||
|
const BOOTSTRAP_TMAX = 26;
|
||||||
|
const BOOTSTRAP_SKEW = 38;
|
||||||
|
const BOOTSTRAP_DAMP = 700;
|
||||||
|
const BOOTSTRAP_INITIAL_BIAS = 72;
|
||||||
|
const BOOTSTRAP_INITIAL_N = 128;
|
||||||
|
/**#@-*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a hostname using Punycode
|
||||||
|
*
|
||||||
|
* @param string $string Hostname
|
||||||
|
* @return string Punycode-encoded hostname
|
||||||
|
*/
|
||||||
|
public static function encode($string) {
|
||||||
|
$parts = explode('.', $string);
|
||||||
|
foreach ($parts as &$part) {
|
||||||
|
$part = self::to_ascii($part);
|
||||||
|
}
|
||||||
|
return implode('.', $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a UTF-8 string to an ASCII string using Punycode
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception Provided string longer than 64 ASCII characters (`idna.provided_too_long`)
|
||||||
|
* @throws Requests_Exception Prepared string longer than 64 ASCII characters (`idna.prepared_too_long`)
|
||||||
|
* @throws Requests_Exception Provided string already begins with xn-- (`idna.provided_is_prefixed`)
|
||||||
|
* @throws Requests_Exception Encoded string longer than 64 ASCII characters (`idna.encoded_too_long`)
|
||||||
|
*
|
||||||
|
* @param string $string ASCII or UTF-8 string (max length 64 characters)
|
||||||
|
* @return string ASCII string
|
||||||
|
*/
|
||||||
|
public static function to_ascii($string) {
|
||||||
|
// Step 1: Check if the string is already ASCII
|
||||||
|
if (self::is_ascii($string)) {
|
||||||
|
// Skip to step 7
|
||||||
|
if (strlen($string) < 64) {
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Requests_Exception('Provided string is too long', 'idna.provided_too_long', $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: nameprep
|
||||||
|
$string = self::nameprep($string);
|
||||||
|
|
||||||
|
// Step 3: UseSTD3ASCIIRules is false, continue
|
||||||
|
// Step 4: Check if it's ASCII now
|
||||||
|
if (self::is_ascii($string)) {
|
||||||
|
// Skip to step 7
|
||||||
|
if (strlen($string) < 64) {
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Requests_Exception('Prepared string is too long', 'idna.prepared_too_long', $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: Check ACE prefix
|
||||||
|
if (strpos($string, self::ACE_PREFIX) === 0) {
|
||||||
|
throw new Requests_Exception('Provided string begins with ACE prefix', 'idna.provided_is_prefixed', $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Encode with Punycode
|
||||||
|
$string = self::punycode_encode($string);
|
||||||
|
|
||||||
|
// Step 7: Prepend ACE prefix
|
||||||
|
$string = self::ACE_PREFIX . $string;
|
||||||
|
|
||||||
|
// Step 8: Check size
|
||||||
|
if (strlen($string) < 64) {
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Requests_Exception('Encoded string is too long', 'idna.encoded_too_long', $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a given string contains only ASCII characters
|
||||||
|
*
|
||||||
|
* @internal (Testing found regex was the fastest implementation)
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @return bool Is the string ASCII-only?
|
||||||
|
*/
|
||||||
|
protected static function is_ascii($string) {
|
||||||
|
return (preg_match('/(?:[^\x00-\x7F])/', $string) !== 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare a string for use as an IDNA name
|
||||||
|
*
|
||||||
|
* @todo Implement this based on RFC 3491 and the newer 5891
|
||||||
|
* @param string $string
|
||||||
|
* @return string Prepared string
|
||||||
|
*/
|
||||||
|
protected static function nameprep($string) {
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a UTF-8 string to a UCS-4 codepoint array
|
||||||
|
*
|
||||||
|
* Based on Requests_IRI::replace_invalid_with_pct_encoding()
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception Invalid UTF-8 codepoint (`idna.invalidcodepoint`)
|
||||||
|
* @param string $input
|
||||||
|
* @return array Unicode code points
|
||||||
|
*/
|
||||||
|
protected static function utf8_to_codepoints($input) {
|
||||||
|
$codepoints = array();
|
||||||
|
|
||||||
|
// Get number of bytes
|
||||||
|
$strlen = strlen($input);
|
||||||
|
|
||||||
|
for ($position = 0; $position < $strlen; $position++) {
|
||||||
|
$value = ord($input[$position]);
|
||||||
|
|
||||||
|
// One byte sequence:
|
||||||
|
if ((~$value & 0x80) === 0x80) {
|
||||||
|
$character = $value;
|
||||||
|
$length = 1;
|
||||||
|
$remaining = 0;
|
||||||
|
}
|
||||||
|
// Two byte sequence:
|
||||||
|
elseif (($value & 0xE0) === 0xC0) {
|
||||||
|
$character = ($value & 0x1F) << 6;
|
||||||
|
$length = 2;
|
||||||
|
$remaining = 1;
|
||||||
|
}
|
||||||
|
// Three byte sequence:
|
||||||
|
elseif (($value & 0xF0) === 0xE0) {
|
||||||
|
$character = ($value & 0x0F) << 12;
|
||||||
|
$length = 3;
|
||||||
|
$remaining = 2;
|
||||||
|
}
|
||||||
|
// Four byte sequence:
|
||||||
|
elseif (($value & 0xF8) === 0xF0) {
|
||||||
|
$character = ($value & 0x07) << 18;
|
||||||
|
$length = 4;
|
||||||
|
$remaining = 3;
|
||||||
|
}
|
||||||
|
// Invalid byte:
|
||||||
|
else {
|
||||||
|
throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($remaining > 0) {
|
||||||
|
if ($position + $length > $strlen) {
|
||||||
|
throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
|
||||||
|
}
|
||||||
|
for ($position++; $remaining > 0; $position++) {
|
||||||
|
$value = ord($input[$position]);
|
||||||
|
|
||||||
|
// If it is invalid, count the sequence as invalid and reprocess the current byte:
|
||||||
|
if (($value & 0xC0) !== 0x80) {
|
||||||
|
throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
|
||||||
|
}
|
||||||
|
|
||||||
|
$character |= ($value & 0x3F) << (--$remaining * 6);
|
||||||
|
}
|
||||||
|
$position--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
// Non-shortest form sequences are invalid
|
||||||
|
$length > 1 && $character <= 0x7F
|
||||||
|
|| $length > 2 && $character <= 0x7FF
|
||||||
|
|| $length > 3 && $character <= 0xFFFF
|
||||||
|
// Outside of range of ucschar codepoints
|
||||||
|
// Noncharacters
|
||||||
|
|| ($character & 0xFFFE) === 0xFFFE
|
||||||
|
|| $character >= 0xFDD0 && $character <= 0xFDEF
|
||||||
|
|| (
|
||||||
|
// Everything else not in ucschar
|
||||||
|
$character > 0xD7FF && $character < 0xF900
|
||||||
|
|| $character < 0x20
|
||||||
|
|| $character > 0x7E && $character < 0xA0
|
||||||
|
|| $character > 0xEFFFD
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
|
||||||
|
}
|
||||||
|
|
||||||
|
$codepoints[] = $character;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $codepoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RFC3492-compliant encoder
|
||||||
|
*
|
||||||
|
* @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code
|
||||||
|
* @throws Requests_Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`)
|
||||||
|
*
|
||||||
|
* @param string $input UTF-8 encoded string to encode
|
||||||
|
* @return string Punycode-encoded string
|
||||||
|
*/
|
||||||
|
public static function punycode_encode($input) {
|
||||||
|
$output = '';
|
||||||
|
# let n = initial_n
|
||||||
|
$n = self::BOOTSTRAP_INITIAL_N;
|
||||||
|
# let delta = 0
|
||||||
|
$delta = 0;
|
||||||
|
# let bias = initial_bias
|
||||||
|
$bias = self::BOOTSTRAP_INITIAL_BIAS;
|
||||||
|
# let h = b = the number of basic code points in the input
|
||||||
|
$h = $b = 0; // see loop
|
||||||
|
# copy them to the output in order
|
||||||
|
$codepoints = self::utf8_to_codepoints($input);
|
||||||
|
|
||||||
|
foreach ($codepoints as $char) {
|
||||||
|
if ($char < 128) {
|
||||||
|
// Character is valid ASCII
|
||||||
|
// TODO: this should also check if it's valid for a URL
|
||||||
|
$output .= chr($char);
|
||||||
|
$h++;
|
||||||
|
}
|
||||||
|
// Check if the character is non-ASCII, but below initial n
|
||||||
|
// This never occurs for Punycode, so ignore in coverage
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
elseif ($char < $n) {
|
||||||
|
throw new Requests_Exception('Invalid character', 'idna.character_outside_domain', $char);
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
else {
|
||||||
|
$extended[$char] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$extended = array_keys($extended);
|
||||||
|
sort($extended);
|
||||||
|
$b = $h;
|
||||||
|
# [copy them] followed by a delimiter if b > 0
|
||||||
|
if (strlen($output) > 0) {
|
||||||
|
$output .= '-';
|
||||||
|
}
|
||||||
|
# {if the input contains a non-basic code point < n then fail}
|
||||||
|
# while h < length(input) do begin
|
||||||
|
while ($h < count($codepoints)) {
|
||||||
|
# let m = the minimum code point >= n in the input
|
||||||
|
$m = array_shift($extended);
|
||||||
|
//printf('next code point to insert is %s' . PHP_EOL, dechex($m));
|
||||||
|
# let delta = delta + (m - n) * (h + 1), fail on overflow
|
||||||
|
$delta += ($m - $n) * ($h + 1);
|
||||||
|
# let n = m
|
||||||
|
$n = $m;
|
||||||
|
# for each code point c in the input (in order) do begin
|
||||||
|
for ($num = 0; $num < count($codepoints); $num++) {
|
||||||
|
$c = $codepoints[$num];
|
||||||
|
# if c < n then increment delta, fail on overflow
|
||||||
|
if ($c < $n) {
|
||||||
|
$delta++;
|
||||||
|
}
|
||||||
|
# if c == n then begin
|
||||||
|
elseif ($c === $n) {
|
||||||
|
# let q = delta
|
||||||
|
$q = $delta;
|
||||||
|
# for k = base to infinity in steps of base do begin
|
||||||
|
for ($k = self::BOOTSTRAP_BASE; ; $k += self::BOOTSTRAP_BASE) {
|
||||||
|
# let t = tmin if k <= bias {+ tmin}, or
|
||||||
|
# tmax if k >= bias + tmax, or k - bias otherwise
|
||||||
|
if ($k <= ($bias + self::BOOTSTRAP_TMIN)) {
|
||||||
|
$t = self::BOOTSTRAP_TMIN;
|
||||||
|
}
|
||||||
|
elseif ($k >= ($bias + self::BOOTSTRAP_TMAX)) {
|
||||||
|
$t = self::BOOTSTRAP_TMAX;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$t = $k - $bias;
|
||||||
|
}
|
||||||
|
# if q < t then break
|
||||||
|
if ($q < $t) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
# output the code point for digit t + ((q - t) mod (base - t))
|
||||||
|
$digit = $t + (($q - $t) % (self::BOOTSTRAP_BASE - $t));
|
||||||
|
//printf('needed delta is %d, encodes as "%s"' . PHP_EOL, $delta, self::digit_to_char($digit));
|
||||||
|
$output .= self::digit_to_char($digit);
|
||||||
|
# let q = (q - t) div (base - t)
|
||||||
|
$q = floor(($q - $t) / (self::BOOTSTRAP_BASE - $t));
|
||||||
|
# end
|
||||||
|
}
|
||||||
|
# output the code point for digit q
|
||||||
|
$output .= self::digit_to_char($q);
|
||||||
|
//printf('needed delta is %d, encodes as "%s"' . PHP_EOL, $delta, self::digit_to_char($q));
|
||||||
|
# let bias = adapt(delta, h + 1, test h equals b?)
|
||||||
|
$bias = self::adapt($delta, $h + 1, $h === $b);
|
||||||
|
//printf('bias becomes %d' . PHP_EOL, $bias);
|
||||||
|
# let delta = 0
|
||||||
|
$delta = 0;
|
||||||
|
# increment h
|
||||||
|
$h++;
|
||||||
|
# end
|
||||||
|
}
|
||||||
|
# end
|
||||||
|
}
|
||||||
|
# increment delta and n
|
||||||
|
$delta++;
|
||||||
|
$n++;
|
||||||
|
# end
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a digit to its respective character
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc3492#section-5
|
||||||
|
* @throws Requests_Exception On invalid digit (`idna.invalid_digit`)
|
||||||
|
*
|
||||||
|
* @param int $digit Digit in the range 0-35
|
||||||
|
* @return string Single character corresponding to digit
|
||||||
|
*/
|
||||||
|
protected static function digit_to_char($digit) {
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
// As far as I know, this never happens, but still good to be sure.
|
||||||
|
if ($digit < 0 || $digit > 35) {
|
||||||
|
throw new Requests_Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit);
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
$digits = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
return substr($digits, $digit, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapt the bias
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc3492#section-6.1
|
||||||
|
* @param int $delta
|
||||||
|
* @param int $numpoints
|
||||||
|
* @param bool $firsttime
|
||||||
|
* @return int New bias
|
||||||
|
*/
|
||||||
|
protected static function adapt($delta, $numpoints, $firsttime) {
|
||||||
|
# function adapt(delta,numpoints,firsttime):
|
||||||
|
# if firsttime then let delta = delta div damp
|
||||||
|
if ($firsttime) {
|
||||||
|
$delta = floor($delta / self::BOOTSTRAP_DAMP);
|
||||||
|
}
|
||||||
|
# else let delta = delta div 2
|
||||||
|
else {
|
||||||
|
$delta = floor($delta / 2);
|
||||||
|
}
|
||||||
|
# let delta = delta + (delta div numpoints)
|
||||||
|
$delta += floor($delta / $numpoints);
|
||||||
|
# let k = 0
|
||||||
|
$k = 0;
|
||||||
|
# while delta > ((base - tmin) * tmax) div 2 do begin
|
||||||
|
$max = floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN) * self::BOOTSTRAP_TMAX) / 2);
|
||||||
|
while ($delta > $max) {
|
||||||
|
# let delta = delta div (base - tmin)
|
||||||
|
$delta = floor($delta / (self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN));
|
||||||
|
# let k = k + base
|
||||||
|
$k += self::BOOTSTRAP_BASE;
|
||||||
|
# end
|
||||||
|
}
|
||||||
|
# return k + (((base - tmin + 1) * delta) div (delta + skew))
|
||||||
|
return $k + floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN + 1) * $delta) / ($delta + self::BOOTSTRAP_SKEW));
|
||||||
|
}
|
||||||
|
}
|
221
source/includes/Requests/Requests/IPv6.php
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class to validate and to work with IPv6 addresses
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to validate and to work with IPv6 addresses
|
||||||
|
*
|
||||||
|
* This was originally based on the PEAR class of the same name, but has been
|
||||||
|
* entirely rewritten.
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
class Requests_IPv6
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Uncompresses an IPv6 address
|
||||||
|
*
|
||||||
|
* RFC 4291 allows you to compress consecutive zero pieces in an address to
|
||||||
|
* '::'. This method expects a valid IPv6 address and expands the '::' to
|
||||||
|
* the required number of zero pieces.
|
||||||
|
*
|
||||||
|
* Example: FF01::101 -> FF01:0:0:0:0:0:0:101
|
||||||
|
* ::1 -> 0:0:0:0:0:0:0:1
|
||||||
|
*
|
||||||
|
* @author Alexander Merz <alexander.merz@web.de>
|
||||||
|
* @author elfrink at introweb dot nl
|
||||||
|
* @author Josh Peck <jmp at joshpeck dot org>
|
||||||
|
* @copyright 2003-2005 The PHP Group
|
||||||
|
* @license http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
* @param string $ip An IPv6 address
|
||||||
|
* @return string The uncompressed IPv6 address
|
||||||
|
*/
|
||||||
|
public static function uncompress($ip)
|
||||||
|
{
|
||||||
|
$c1 = -1;
|
||||||
|
$c2 = -1;
|
||||||
|
if (substr_count($ip, '::') === 1)
|
||||||
|
{
|
||||||
|
list($ip1, $ip2) = explode('::', $ip);
|
||||||
|
if ($ip1 === '')
|
||||||
|
{
|
||||||
|
$c1 = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$c1 = substr_count($ip1, ':');
|
||||||
|
}
|
||||||
|
if ($ip2 === '')
|
||||||
|
{
|
||||||
|
$c2 = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$c2 = substr_count($ip2, ':');
|
||||||
|
}
|
||||||
|
if (strpos($ip2, '.') !== false)
|
||||||
|
{
|
||||||
|
$c2++;
|
||||||
|
}
|
||||||
|
// ::
|
||||||
|
if ($c1 === -1 && $c2 === -1)
|
||||||
|
{
|
||||||
|
$ip = '0:0:0:0:0:0:0:0';
|
||||||
|
}
|
||||||
|
// ::xxx
|
||||||
|
else if ($c1 === -1)
|
||||||
|
{
|
||||||
|
$fill = str_repeat('0:', 7 - $c2);
|
||||||
|
$ip = str_replace('::', $fill, $ip);
|
||||||
|
}
|
||||||
|
// xxx::
|
||||||
|
else if ($c2 === -1)
|
||||||
|
{
|
||||||
|
$fill = str_repeat(':0', 7 - $c1);
|
||||||
|
$ip = str_replace('::', $fill, $ip);
|
||||||
|
}
|
||||||
|
// xxx::xxx
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
|
||||||
|
$ip = str_replace('::', $fill, $ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compresses an IPv6 address
|
||||||
|
*
|
||||||
|
* RFC 4291 allows you to compress consecutive zero pieces in an address to
|
||||||
|
* '::'. This method expects a valid IPv6 address and compresses consecutive
|
||||||
|
* zero pieces to '::'.
|
||||||
|
*
|
||||||
|
* Example: FF01:0:0:0:0:0:0:101 -> FF01::101
|
||||||
|
* 0:0:0:0:0:0:0:1 -> ::1
|
||||||
|
*
|
||||||
|
* @see uncompress()
|
||||||
|
* @param string $ip An IPv6 address
|
||||||
|
* @return string The compressed IPv6 address
|
||||||
|
*/
|
||||||
|
public static function compress($ip)
|
||||||
|
{
|
||||||
|
// Prepare the IP to be compressed
|
||||||
|
$ip = self::uncompress($ip);
|
||||||
|
$ip_parts = self::split_v6_v4($ip);
|
||||||
|
|
||||||
|
// Replace all leading zeros
|
||||||
|
$ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
|
||||||
|
|
||||||
|
// Find bunches of zeros
|
||||||
|
if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
|
||||||
|
{
|
||||||
|
$max = 0;
|
||||||
|
$pos = null;
|
||||||
|
foreach ($matches[0] as $match)
|
||||||
|
{
|
||||||
|
if (strlen($match[0]) > $max)
|
||||||
|
{
|
||||||
|
$max = strlen($match[0]);
|
||||||
|
$pos = $match[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ip_parts[1] !== '')
|
||||||
|
{
|
||||||
|
return implode(':', $ip_parts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $ip_parts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits an IPv6 address into the IPv6 and IPv4 representation parts
|
||||||
|
*
|
||||||
|
* RFC 4291 allows you to represent the last two parts of an IPv6 address
|
||||||
|
* using the standard IPv4 representation
|
||||||
|
*
|
||||||
|
* Example: 0:0:0:0:0:0:13.1.68.3
|
||||||
|
* 0:0:0:0:0:FFFF:129.144.52.38
|
||||||
|
*
|
||||||
|
* @param string $ip An IPv6 address
|
||||||
|
* @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
|
||||||
|
*/
|
||||||
|
private static function split_v6_v4($ip)
|
||||||
|
{
|
||||||
|
if (strpos($ip, '.') !== false)
|
||||||
|
{
|
||||||
|
$pos = strrpos($ip, ':');
|
||||||
|
$ipv6_part = substr($ip, 0, $pos);
|
||||||
|
$ipv4_part = substr($ip, $pos + 1);
|
||||||
|
return array($ipv6_part, $ipv4_part);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return array($ip, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks an IPv6 address
|
||||||
|
*
|
||||||
|
* Checks if the given IP is a valid IPv6 address
|
||||||
|
*
|
||||||
|
* @param string $ip An IPv6 address
|
||||||
|
* @return bool true if $ip is a valid IPv6 address
|
||||||
|
*/
|
||||||
|
public static function check_ipv6($ip)
|
||||||
|
{
|
||||||
|
$ip = self::uncompress($ip);
|
||||||
|
list($ipv6, $ipv4) = self::split_v6_v4($ip);
|
||||||
|
$ipv6 = explode(':', $ipv6);
|
||||||
|
$ipv4 = explode('.', $ipv4);
|
||||||
|
if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
|
||||||
|
{
|
||||||
|
foreach ($ipv6 as $ipv6_part)
|
||||||
|
{
|
||||||
|
// The section can't be empty
|
||||||
|
if ($ipv6_part === '')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Nor can it be over four characters
|
||||||
|
if (strlen($ipv6_part) > 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Remove leading zeros (this is safe because of the above)
|
||||||
|
$ipv6_part = ltrim($ipv6_part, '0');
|
||||||
|
if ($ipv6_part === '')
|
||||||
|
$ipv6_part = '0';
|
||||||
|
|
||||||
|
// Check the value is valid
|
||||||
|
$value = hexdec($ipv6_part);
|
||||||
|
if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (count($ipv4) === 4)
|
||||||
|
{
|
||||||
|
foreach ($ipv4 as $ipv4_part)
|
||||||
|
{
|
||||||
|
$value = (int) $ipv4_part;
|
||||||
|
if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1220
source/includes/Requests/Requests/IRI.php
Normal file
35
source/includes/Requests/Requests/Proxy.php
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Proxy connection interface
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Proxy
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy connection interface
|
||||||
|
*
|
||||||
|
* Implement this interface to handle proxy settings and authentication
|
||||||
|
*
|
||||||
|
* Parameters should be passed via the constructor where possible, as this
|
||||||
|
* makes it much easier for users to use your provider.
|
||||||
|
*
|
||||||
|
* @see Requests_Hooks
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Proxy
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
interface Requests_Proxy {
|
||||||
|
/**
|
||||||
|
* Register hooks as needed
|
||||||
|
*
|
||||||
|
* This method is called in {@see Requests::request} when the user has set
|
||||||
|
* an instance as the 'auth' option. Use this callback to register all the
|
||||||
|
* hooks you'll need.
|
||||||
|
*
|
||||||
|
* @see Requests_Hooks::register
|
||||||
|
* @param Requests_Hooks $hooks Hook system
|
||||||
|
*/
|
||||||
|
public function register(Requests_Hooks &$hooks);
|
||||||
|
}
|
150
source/includes/Requests/Requests/Proxy/HTTP.php
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* HTTP Proxy connection interface
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Proxy
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP Proxy connection interface
|
||||||
|
*
|
||||||
|
* Provides a handler for connection via an HTTP proxy
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Proxy
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
class Requests_Proxy_HTTP implements Requests_Proxy {
|
||||||
|
/**
|
||||||
|
* Proxy host and port
|
||||||
|
*
|
||||||
|
* Notation: "host:port" (eg 127.0.0.1:8080 or someproxy.com:3128)
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $proxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Username
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Password
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $pass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do we need to authenticate? (ie username & password have been provided)
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $use_authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @since 1.6
|
||||||
|
* @throws Requests_Exception On incorrect number of arguments (`authbasicbadargs`)
|
||||||
|
* @param array|null $args Array of user and password. Must have exactly two elements
|
||||||
|
*/
|
||||||
|
public function __construct($args = null) {
|
||||||
|
if (is_string($args)) {
|
||||||
|
$this->proxy = $args;
|
||||||
|
}
|
||||||
|
elseif (is_array($args)) {
|
||||||
|
if (count($args) == 1) {
|
||||||
|
list($this->proxy) = $args;
|
||||||
|
}
|
||||||
|
elseif (count($args) == 3) {
|
||||||
|
list($this->proxy, $this->user, $this->pass) = $args;
|
||||||
|
$this->use_authentication = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Requests_Exception( 'Invalid number of arguments', 'proxyhttpbadargs');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the necessary callbacks
|
||||||
|
*
|
||||||
|
* @since 1.6
|
||||||
|
* @see curl_before_send
|
||||||
|
* @see fsockopen_remote_socket
|
||||||
|
* @see fsockopen_remote_host_path
|
||||||
|
* @see fsockopen_header
|
||||||
|
* @param Requests_Hooks $hooks Hook system
|
||||||
|
*/
|
||||||
|
public function register(Requests_Hooks &$hooks) {
|
||||||
|
$hooks->register('curl.before_send', array(&$this, 'curl_before_send'));
|
||||||
|
|
||||||
|
$hooks->register('fsockopen.remote_socket', array(&$this, 'fsockopen_remote_socket'));
|
||||||
|
$hooks->register('fsockopen.remote_host_path', array(&$this, 'fsockopen_remote_host_path'));
|
||||||
|
if( $this->use_authentication ) {
|
||||||
|
$hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set cURL parameters before the data is sent
|
||||||
|
*
|
||||||
|
* @since 1.6
|
||||||
|
* @param resource $handle cURL resource
|
||||||
|
*/
|
||||||
|
public function curl_before_send(&$handle) {
|
||||||
|
curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
||||||
|
curl_setopt($handle, CURLOPT_PROXY, $this->proxy);
|
||||||
|
|
||||||
|
if ($this->use_authentication) {
|
||||||
|
curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||||||
|
curl_setopt($handle, CURLOPT_PROXYUSERPWD, $this->get_auth_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alter remote socket information before opening socket connection
|
||||||
|
*
|
||||||
|
* @since 1.6
|
||||||
|
* @param string $out HTTP header string
|
||||||
|
*/
|
||||||
|
public function fsockopen_remote_socket( &$remote_socket ) {
|
||||||
|
$remote_socket = $this->proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alter remote path before getting stream data
|
||||||
|
*
|
||||||
|
* @since 1.6
|
||||||
|
* @param string $out HTTP header string
|
||||||
|
*/
|
||||||
|
public function fsockopen_remote_host_path( &$path, $url ) {
|
||||||
|
$path = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add extra headers to the request before sending
|
||||||
|
*
|
||||||
|
* @since 1.6
|
||||||
|
* @param string $out HTTP header string
|
||||||
|
*/
|
||||||
|
public function fsockopen_header( &$out ) {
|
||||||
|
$out .= "Proxy-Authorization: Basic " . base64_encode($this->get_auth_string()) . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the authentication string (user:pass)
|
||||||
|
*
|
||||||
|
* @since 1.6
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_auth_string() {
|
||||||
|
return $this->user . ':' . $this->pass;
|
||||||
|
}
|
||||||
|
}
|
95
source/includes/Requests/Requests/Response.php
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* HTTP response class
|
||||||
|
*
|
||||||
|
* Contains a response from Requests::request()
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP response class
|
||||||
|
*
|
||||||
|
* Contains a response from Requests::request()
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Response {
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
$this->headers = new Requests_Response_Headers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response body
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $body = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw HTTP data from the transport
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $raw = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Headers, as an associative array
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $headers = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status code, false if non-blocking
|
||||||
|
* @var integer|boolean
|
||||||
|
*/
|
||||||
|
public $status_code = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the request succeeded or not
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $success = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of redirects the request used
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
public $redirects = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL requested
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $url = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous requests (from redirects)
|
||||||
|
* @var array Array of Requests_Response objects
|
||||||
|
*/
|
||||||
|
public $history = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookies from the request
|
||||||
|
*/
|
||||||
|
public $cookies = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an exception if the request was not successful
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`)
|
||||||
|
* @throws Requests_Exception_HTTP On non-successful status code. Exception class corresponds to code (e.g. {@see Requests_Exception_HTTP_404})
|
||||||
|
* @param boolean $allow_redirects Set to false to throw on a 3xx as well
|
||||||
|
*/
|
||||||
|
public function throw_for_status($allow_redirects = true) {
|
||||||
|
if ($this->status_code >= 300 && $this->status_code < 400) {
|
||||||
|
if (!$allow_redirects) {
|
||||||
|
throw new Requests_Exception('Redirection not allowed', 'response.no_redirects', $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif (!$this->success) {
|
||||||
|
$exception = Requests_Exception_HTTP::get_class($this->status_code);
|
||||||
|
throw new $exception(null, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
source/includes/Requests/Requests/Response/Headers.php
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Case-insensitive dictionary, suitable for HTTP headers
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Case-insensitive dictionary, suitable for HTTP headers
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
*/
|
||||||
|
class Requests_Response_Headers extends Requests_Utility_CaseInsensitiveDictionary {
|
||||||
|
/**
|
||||||
|
* Get the given header
|
||||||
|
*
|
||||||
|
* Unlike {@see self::getValues()}, this returns a string. If there are
|
||||||
|
* multiple values, it concatenates them with a comma as per RFC2616.
|
||||||
|
*
|
||||||
|
* Avoid using this where commas may be used unquoted in values, such as
|
||||||
|
* Set-Cookie headers.
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return string Header value
|
||||||
|
*/
|
||||||
|
public function offsetGet($key) {
|
||||||
|
$key = strtolower($key);
|
||||||
|
if (!isset($this->data[$key]))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return $this->flatten($this->data[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the given item
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
|
||||||
|
*
|
||||||
|
* @param string $key Item name
|
||||||
|
* @param string $value Item value
|
||||||
|
*/
|
||||||
|
public function offsetSet($key, $value) {
|
||||||
|
if ($key === null) {
|
||||||
|
throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = strtolower($key);
|
||||||
|
|
||||||
|
if (!isset($this->data[$key])) {
|
||||||
|
$this->data[$key] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->data[$key][] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all values for a given header
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return array Header values
|
||||||
|
*/
|
||||||
|
public function getValues($key) {
|
||||||
|
$key = strtolower($key);
|
||||||
|
if (!isset($this->data[$key]))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return $this->data[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flattens a value into a string
|
||||||
|
*
|
||||||
|
* Converts an array into a string by imploding values with a comma, as per
|
||||||
|
* RFC2616's rules for folding headers.
|
||||||
|
*
|
||||||
|
* @param string|array $value Value to flatten
|
||||||
|
* @return string Flattened value
|
||||||
|
*/
|
||||||
|
public function flatten($value) {
|
||||||
|
if (is_array($value))
|
||||||
|
$value = implode(',', $value);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an iterator for the data
|
||||||
|
*
|
||||||
|
* Converts the internal
|
||||||
|
* @return ArrayIterator
|
||||||
|
*/
|
||||||
|
public function getIterator() {
|
||||||
|
return new Requests_Utility_FilteredIterator($this->data, array($this, 'flatten'));
|
||||||
|
}
|
||||||
|
}
|
151
source/includes/Requests/Requests/SSL.php
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SSL utilities for Requests
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSL utilities for Requests
|
||||||
|
*
|
||||||
|
* Collection of utilities for working with and verifying SSL certificates.
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
class Requests_SSL {
|
||||||
|
/**
|
||||||
|
* Verify the certificate against common name and subject alternative names
|
||||||
|
*
|
||||||
|
* Unfortunately, PHP doesn't check the certificate against the alternative
|
||||||
|
* names, leading things like 'https://www.github.com/' to be invalid.
|
||||||
|
* Instead
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
|
||||||
|
* @param string $host Host name to verify against
|
||||||
|
* @param resource $context Stream context
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function verify_certificate($host, $cert) {
|
||||||
|
// Calculate the valid wildcard match if the host is not an IP address
|
||||||
|
$parts = explode('.', $host);
|
||||||
|
if (ip2long($host) === false) {
|
||||||
|
$parts[0] = '*';
|
||||||
|
}
|
||||||
|
$wildcard = implode('.', $parts);
|
||||||
|
|
||||||
|
$has_dns_alt = false;
|
||||||
|
|
||||||
|
// Check the subjectAltName
|
||||||
|
if (!empty($cert['extensions']) && !empty($cert['extensions']['subjectAltName'])) {
|
||||||
|
$altnames = explode(',', $cert['extensions']['subjectAltName']);
|
||||||
|
foreach ($altnames as $altname) {
|
||||||
|
$altname = trim($altname);
|
||||||
|
if (strpos($altname, 'DNS:') !== 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$has_dns_alt = true;
|
||||||
|
|
||||||
|
// Strip the 'DNS:' prefix and trim whitespace
|
||||||
|
$altname = trim(substr($altname, 4));
|
||||||
|
|
||||||
|
// Check for a match
|
||||||
|
if (self::match_domain($host, $altname) === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to checking the common name if we didn't get any dNSName
|
||||||
|
// alt names, as per RFC2818
|
||||||
|
if (!$has_dns_alt && !empty($cert['subject']['CN'])) {
|
||||||
|
// Check for a match
|
||||||
|
if (self::match_domain($host, $cert['subject']['CN']) === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a reference name is valid
|
||||||
|
*
|
||||||
|
* Verifies a dNSName for HTTPS usage, (almost) as per Firefox's rules:
|
||||||
|
* - Wildcards can only occur in a name with more than 3 components
|
||||||
|
* - Wildcards can only occur as the last character in the first
|
||||||
|
* component
|
||||||
|
* - Wildcards may be preceded by additional characters
|
||||||
|
*
|
||||||
|
* We modify these rules to be a bit stricter and only allow the wildcard
|
||||||
|
* character to be the full first component; that is, with the exclusion of
|
||||||
|
* the third rule.
|
||||||
|
*
|
||||||
|
* @param string $reference Reference dNSName
|
||||||
|
* @return boolean Is the name valid?
|
||||||
|
*/
|
||||||
|
public static function verify_reference_name($reference) {
|
||||||
|
$parts = explode('.', $reference);
|
||||||
|
|
||||||
|
// Check the first part of the name
|
||||||
|
$first = array_shift($parts);
|
||||||
|
|
||||||
|
if (strpos($first, '*') !== false) {
|
||||||
|
// Check that the wildcard is the full part
|
||||||
|
if ($first !== '*') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we have at least 3 components (including first)
|
||||||
|
if (count($parts) < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the remaining parts
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if (strpos($part, '*') !== false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing found, verified!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match a hostname against a dNSName reference
|
||||||
|
*
|
||||||
|
* @param string $host Requested host
|
||||||
|
* @param string $reference dNSName to match against
|
||||||
|
* @return boolean Does the domain match?
|
||||||
|
*/
|
||||||
|
public static function match_domain($host, $reference) {
|
||||||
|
// Check if the reference is blacklisted first
|
||||||
|
if (self::verify_reference_name($reference) !== true) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a direct match
|
||||||
|
if ($host === $reference) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the valid wildcard match if the host is not an IP address
|
||||||
|
// Also validates that the host has 3 parts or more, as per Firefox's
|
||||||
|
// ruleset.
|
||||||
|
if (ip2long($host) === false) {
|
||||||
|
$parts = explode('.', $host);
|
||||||
|
$parts[0] = '*';
|
||||||
|
$wildcard = implode('.', $parts);
|
||||||
|
if ($wildcard === $reference) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
253
source/includes/Requests/Requests/Session.php
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Session handler for persistent requests and default parameters
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Session Handler
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session handler for persistent requests and default parameters
|
||||||
|
*
|
||||||
|
* Allows various options to be set as default values, and merges both the
|
||||||
|
* options and URL properties together. A base URL can be set for all requests,
|
||||||
|
* with all subrequests resolved from this. Base options can be set (including
|
||||||
|
* a shared cookie jar), then overridden for individual requests.
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Session Handler
|
||||||
|
*/
|
||||||
|
class Requests_Session {
|
||||||
|
/**
|
||||||
|
* Base URL for requests
|
||||||
|
*
|
||||||
|
* URLs will be made absolute using this as the base
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $url = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base headers for requests
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $headers = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base data for requests
|
||||||
|
*
|
||||||
|
* If both the base data and the per-request data are arrays, the data will
|
||||||
|
* be merged before sending the request.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $data = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base options for requests
|
||||||
|
*
|
||||||
|
* The base options are merged with the per-request data for each request.
|
||||||
|
* The only default option is a shared cookie jar between requests.
|
||||||
|
*
|
||||||
|
* Values here can also be set directly via properties on the Session
|
||||||
|
* object, e.g. `$session->useragent = 'X';`
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $options = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new session
|
||||||
|
*
|
||||||
|
* @param string|null $url Base URL for requests
|
||||||
|
* @param array $headers Default headers for requests
|
||||||
|
* @param array $data Default data for requests
|
||||||
|
* @param array $options Default options for requests
|
||||||
|
*/
|
||||||
|
public function __construct($url = null, $headers = array(), $data = array(), $options = array()) {
|
||||||
|
$this->url = $url;
|
||||||
|
$this->headers = $headers;
|
||||||
|
$this->data = $data;
|
||||||
|
$this->options = $options;
|
||||||
|
|
||||||
|
if (empty($this->options['cookies'])) {
|
||||||
|
$this->options['cookies'] = new Requests_Cookie_Jar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a property's value
|
||||||
|
*
|
||||||
|
* @param string $key Property key
|
||||||
|
* @return mixed|null Property value, null if none found
|
||||||
|
*/
|
||||||
|
public function __get($key) {
|
||||||
|
if (isset($this->options[$key]))
|
||||||
|
return $this->options[$key];
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a property's value
|
||||||
|
*
|
||||||
|
* @param string $key Property key
|
||||||
|
* @param mixed $value Property value
|
||||||
|
*/
|
||||||
|
public function __set($key, $value) {
|
||||||
|
$this->options[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a property's value
|
||||||
|
*
|
||||||
|
* @param string $key Property key
|
||||||
|
*/
|
||||||
|
public function __isset($key) {
|
||||||
|
return isset($this->options[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a property's value
|
||||||
|
*
|
||||||
|
* @param string $key Property key
|
||||||
|
*/
|
||||||
|
public function __unset($key) {
|
||||||
|
$this->options[$key] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**#@+
|
||||||
|
* @see request()
|
||||||
|
* @param string $url
|
||||||
|
* @param array $headers
|
||||||
|
* @param array $options
|
||||||
|
* @return Requests_Response
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Send a GET request
|
||||||
|
*/
|
||||||
|
public function get($url, $headers = array(), $options = array()) {
|
||||||
|
return $this->request($url, $headers, null, Requests::GET, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a HEAD request
|
||||||
|
*/
|
||||||
|
public function head($url, $headers = array(), $options = array()) {
|
||||||
|
return $this->request($url, $headers, null, Requests::HEAD, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a DELETE request
|
||||||
|
*/
|
||||||
|
public function delete($url, $headers = array(), $options = array()) {
|
||||||
|
return $this->request($url, $headers, null, Requests::DELETE, $options);
|
||||||
|
}
|
||||||
|
/**#@-*/
|
||||||
|
|
||||||
|
/**#@+
|
||||||
|
* @see request()
|
||||||
|
* @param string $url
|
||||||
|
* @param array $headers
|
||||||
|
* @param array $data
|
||||||
|
* @param array $options
|
||||||
|
* @return Requests_Response
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Send a POST request
|
||||||
|
*/
|
||||||
|
public function post($url, $headers = array(), $data = array(), $options = array()) {
|
||||||
|
return $this->request($url, $headers, $data, Requests::POST, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a PUT request
|
||||||
|
*/
|
||||||
|
public function put($url, $headers = array(), $data = array(), $options = array()) {
|
||||||
|
return $this->request($url, $headers, $data, Requests::PUT, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a PATCH request
|
||||||
|
*
|
||||||
|
* Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
|
||||||
|
* specification recommends that should send an ETag
|
||||||
|
*
|
||||||
|
* @link http://tools.ietf.org/html/rfc5789
|
||||||
|
*/
|
||||||
|
public function patch($url, $headers, $data = array(), $options = array()) {
|
||||||
|
return $this->request($url, $headers, $data, Requests::PATCH, $options);
|
||||||
|
}
|
||||||
|
/**#@-*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main interface for HTTP requests
|
||||||
|
*
|
||||||
|
* This method initiates a request and sends it via a transport before
|
||||||
|
* parsing.
|
||||||
|
*
|
||||||
|
* @see Requests::request()
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On invalid URLs (`nonhttp`)
|
||||||
|
*
|
||||||
|
* @param string $url URL to request
|
||||||
|
* @param array $headers Extra headers to send with the request
|
||||||
|
* @param array $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
|
||||||
|
* @param string $type HTTP request type (use Requests constants)
|
||||||
|
* @param array $options Options for the request (see {@see Requests::request})
|
||||||
|
* @return Requests_Response
|
||||||
|
*/
|
||||||
|
public function request($url, $headers = array(), $data = array(), $type = Requests::GET, $options = array()) {
|
||||||
|
$request = $this->merge_request(compact('url', 'headers', 'data', 'options'));
|
||||||
|
|
||||||
|
return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send multiple HTTP requests simultaneously
|
||||||
|
*
|
||||||
|
* @see Requests::request_multiple()
|
||||||
|
*
|
||||||
|
* @param array $requests Requests data (see {@see Requests::request_multiple})
|
||||||
|
* @param array $options Global and default options (see {@see Requests::request})
|
||||||
|
* @return array Responses (either Requests_Response or a Requests_Exception object)
|
||||||
|
*/
|
||||||
|
public function request_multiple($requests, $options = array()) {
|
||||||
|
foreach ($requests as $key => $request) {
|
||||||
|
$requests[$key] = $this->merge_request($request, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$options = array_merge($this->options, $options);
|
||||||
|
|
||||||
|
// Disallow forcing the type, as that's a per request setting
|
||||||
|
unset($options['type']);
|
||||||
|
|
||||||
|
return Requests::request_multiple($requests, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge a request's data with the default data
|
||||||
|
*
|
||||||
|
* @param array $request Request data (same form as {@see request_multiple})
|
||||||
|
* @param boolean $merge_options Should we merge options as well?
|
||||||
|
* @return array Request data
|
||||||
|
*/
|
||||||
|
protected function merge_request($request, $merge_options = true) {
|
||||||
|
if ($this->url !== null) {
|
||||||
|
$request['url'] = Requests_IRI::absolutize($this->url, $request['url']);
|
||||||
|
$request['url'] = $request['url']->uri;
|
||||||
|
}
|
||||||
|
$request['headers'] = array_merge($this->headers, $request['headers']);
|
||||||
|
|
||||||
|
if (is_array($request['data']) && is_array($this->data)) {
|
||||||
|
$request['data'] = array_merge($this->data, $request['data']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($merge_options !== false) {
|
||||||
|
$request['options'] = array_merge($this->options, $request['options']);
|
||||||
|
|
||||||
|
// Disallow forcing the type, as that's a per request setting
|
||||||
|
unset($request['options']['type']);
|
||||||
|
}
|
||||||
|
return $request;
|
||||||
|
}
|
||||||
|
}
|
41
source/includes/Requests/Requests/Transport.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Base HTTP transport
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Transport
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base HTTP transport
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Transport
|
||||||
|
*/
|
||||||
|
interface Requests_Transport {
|
||||||
|
/**
|
||||||
|
* Perform a request
|
||||||
|
*
|
||||||
|
* @param string $url URL to request
|
||||||
|
* @param array $headers Associative array of request headers
|
||||||
|
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
|
||||||
|
* @param array $options Request options, see {@see Requests::response()} for documentation
|
||||||
|
* @return string Raw HTTP result
|
||||||
|
*/
|
||||||
|
public function request($url, $headers = array(), $data = array(), $options = array());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send multiple requests simultaneously
|
||||||
|
*
|
||||||
|
* @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request}
|
||||||
|
* @param array $options Global options, see {@see Requests::response()} for documentation
|
||||||
|
* @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
|
||||||
|
*/
|
||||||
|
public function request_multiple($requests, $options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Self-test whether the transport can be used
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function test();
|
||||||
|
}
|
349
source/includes/Requests/Requests/Transport/cURL.php
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* cURL HTTP transport
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Transport
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cURL HTTP transport
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Transport
|
||||||
|
*/
|
||||||
|
class Requests_Transport_cURL implements Requests_Transport {
|
||||||
|
/**
|
||||||
|
* Raw HTTP data
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $headers = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information on the current request
|
||||||
|
*
|
||||||
|
* @var array cURL information array, see {@see http://php.net/curl_getinfo}
|
||||||
|
*/
|
||||||
|
public $info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version string
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cURL handle
|
||||||
|
*
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $fp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Have we finished the headers yet?
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $done_headers = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If streaming to a file, keep the file pointer
|
||||||
|
*
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $stream_handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
$curl = curl_version();
|
||||||
|
$this->version = $curl['version'];
|
||||||
|
$this->fp = curl_init();
|
||||||
|
|
||||||
|
curl_setopt($this->fp, CURLOPT_HEADER, false);
|
||||||
|
curl_setopt($this->fp, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
if (version_compare($this->version, '7.10.5', '>=')) {
|
||||||
|
curl_setopt($this->fp, CURLOPT_ENCODING, '');
|
||||||
|
}
|
||||||
|
if (version_compare($this->version, '7.19.4', '>=')) {
|
||||||
|
curl_setopt($this->fp, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a request
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On a cURL error (`curlerror`)
|
||||||
|
*
|
||||||
|
* @param string $url URL to request
|
||||||
|
* @param array $headers Associative array of request headers
|
||||||
|
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
|
||||||
|
* @param array $options Request options, see {@see Requests::response()} for documentation
|
||||||
|
* @return string Raw HTTP result
|
||||||
|
*/
|
||||||
|
public function request($url, $headers = array(), $data = array(), $options = array()) {
|
||||||
|
$this->setup_handle($url, $headers, $data, $options);
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('curl.before_send', array(&$this->fp));
|
||||||
|
|
||||||
|
if ($options['filename'] !== false) {
|
||||||
|
$this->stream_handle = fopen($options['filename'], 'wb');
|
||||||
|
curl_setopt($this->fp, CURLOPT_FILE, $this->stream_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($options['verify'])) {
|
||||||
|
if ($options['verify'] === false) {
|
||||||
|
curl_setopt($this->fp, CURLOPT_SSL_VERIFYHOST, 0);
|
||||||
|
curl_setopt($this->fp, CURLOPT_SSL_VERIFYPEER, 0);
|
||||||
|
|
||||||
|
} elseif (is_string($options['verify'])) {
|
||||||
|
curl_setopt($this->fp, CURLOPT_CAINFO, $options['verify']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($options['verifyname']) && $options['verifyname'] === false) {
|
||||||
|
curl_setopt($this->fp, CURLOPT_SSL_VERIFYHOST, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = curl_exec($this->fp);
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('curl.after_send', array(&$fake_headers));
|
||||||
|
|
||||||
|
if (curl_errno($this->fp) === 23 || curl_errno($this->fp) === 61) {
|
||||||
|
curl_setopt($this->fp, CURLOPT_ENCODING, 'none');
|
||||||
|
$response = curl_exec($this->fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->process_response($response, $options);
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send multiple requests simultaneously
|
||||||
|
*
|
||||||
|
* @param array $requests Request data
|
||||||
|
* @param array $options Global options
|
||||||
|
* @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
|
||||||
|
*/
|
||||||
|
public function request_multiple($requests, $options) {
|
||||||
|
$multihandle = curl_multi_init();
|
||||||
|
$subrequests = array();
|
||||||
|
$subhandles = array();
|
||||||
|
|
||||||
|
$class = get_class($this);
|
||||||
|
foreach ($requests as $id => $request) {
|
||||||
|
$subrequests[$id] = new $class();
|
||||||
|
$subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']);
|
||||||
|
$request['options']['hooks']->dispatch('curl.before_multi_add', array(&$subhandles[$id]));
|
||||||
|
curl_multi_add_handle($multihandle, $subhandles[$id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$completed = 0;
|
||||||
|
$responses = array();
|
||||||
|
|
||||||
|
$request['options']['hooks']->dispatch('curl.before_multi_exec', array(&$multihandle));
|
||||||
|
|
||||||
|
do {
|
||||||
|
$active = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$status = curl_multi_exec($multihandle, $active);
|
||||||
|
}
|
||||||
|
while ($status === CURLM_CALL_MULTI_PERFORM);
|
||||||
|
|
||||||
|
$to_process = array();
|
||||||
|
|
||||||
|
// Read the information as needed
|
||||||
|
while ($done = curl_multi_info_read($multihandle)) {
|
||||||
|
$key = array_search($done['handle'], $subhandles, true);
|
||||||
|
if (!isset($to_process[$key])) {
|
||||||
|
$to_process[$key] = $done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the finished requests before we start getting the new ones
|
||||||
|
foreach ($to_process as $key => $done) {
|
||||||
|
$options = $requests[$key]['options'];
|
||||||
|
$responses[$key] = $subrequests[$key]->process_response(curl_multi_getcontent($done['handle']), $options);
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$key], $requests[$key]));
|
||||||
|
|
||||||
|
curl_multi_remove_handle($multihandle, $done['handle']);
|
||||||
|
curl_close($done['handle']);
|
||||||
|
|
||||||
|
if (!is_string($responses[$key])) {
|
||||||
|
$options['hooks']->dispatch('multiple.request.complete', array(&$responses[$key], $key));
|
||||||
|
}
|
||||||
|
$completed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ($active || $completed < count($subrequests));
|
||||||
|
|
||||||
|
$request['options']['hooks']->dispatch('curl.after_multi_exec', array(&$multihandle));
|
||||||
|
|
||||||
|
curl_multi_close($multihandle);
|
||||||
|
|
||||||
|
return $responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cURL handle for use in a multi-request
|
||||||
|
*
|
||||||
|
* @param string $url URL to request
|
||||||
|
* @param array $headers Associative array of request headers
|
||||||
|
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
|
||||||
|
* @param array $options Request options, see {@see Requests::response()} for documentation
|
||||||
|
* @return resource Subrequest's cURL handle
|
||||||
|
*/
|
||||||
|
public function &get_subrequest_handle($url, $headers, $data, $options) {
|
||||||
|
$this->setup_handle($url, $headers, $data, $options);
|
||||||
|
|
||||||
|
if ($options['filename'] !== false) {
|
||||||
|
$this->stream_handle = fopen($options['filename'], 'wb');
|
||||||
|
curl_setopt($this->fp, CURLOPT_FILE, $this->stream_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the cURL handle for the given data
|
||||||
|
*
|
||||||
|
* @param string $url URL to request
|
||||||
|
* @param array $headers Associative array of request headers
|
||||||
|
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
|
||||||
|
* @param array $options Request options, see {@see Requests::response()} for documentation
|
||||||
|
*/
|
||||||
|
protected function setup_handle($url, $headers, $data, $options) {
|
||||||
|
$options['hooks']->dispatch('curl.before_request', array(&$this->fp));
|
||||||
|
|
||||||
|
$headers = Requests::flatten($headers);
|
||||||
|
if (in_array($options['type'], array(Requests::HEAD, Requests::GET, Requests::DELETE)) & !empty($data)) {
|
||||||
|
$url = self::format_get($url, $data);
|
||||||
|
}
|
||||||
|
elseif (!empty($data) && !is_string($data)) {
|
||||||
|
$data = http_build_query($data, null, '&');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($options['type']) {
|
||||||
|
case Requests::POST:
|
||||||
|
curl_setopt($this->fp, CURLOPT_POST, true);
|
||||||
|
curl_setopt($this->fp, CURLOPT_POSTFIELDS, $data);
|
||||||
|
break;
|
||||||
|
case Requests::PATCH:
|
||||||
|
case Requests::PUT:
|
||||||
|
curl_setopt($this->fp, CURLOPT_CUSTOMREQUEST, $options['type']);
|
||||||
|
curl_setopt($this->fp, CURLOPT_POSTFIELDS, $data);
|
||||||
|
break;
|
||||||
|
case Requests::DELETE:
|
||||||
|
curl_setopt($this->fp, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||||
|
break;
|
||||||
|
case Requests::HEAD:
|
||||||
|
curl_setopt($this->fp, CURLOPT_NOBODY, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_setopt($this->fp, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($this->fp, CURLOPT_TIMEOUT, $options['timeout']);
|
||||||
|
curl_setopt($this->fp, CURLOPT_CONNECTTIMEOUT, $options['timeout']);
|
||||||
|
curl_setopt($this->fp, CURLOPT_REFERER, $url);
|
||||||
|
curl_setopt($this->fp, CURLOPT_USERAGENT, $options['useragent']);
|
||||||
|
curl_setopt($this->fp, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
|
||||||
|
if (true === $options['blocking']) {
|
||||||
|
curl_setopt($this->fp, CURLOPT_HEADERFUNCTION, array(&$this, 'stream_headers'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process_response($response, $options) {
|
||||||
|
if ($options['blocking'] === false) {
|
||||||
|
curl_close($this->fp);
|
||||||
|
$fake_headers = '';
|
||||||
|
$options['hooks']->dispatch('curl.after_request', array(&$fake_headers));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($options['filename'] !== false) {
|
||||||
|
fclose($this->stream_handle);
|
||||||
|
$this->headers = trim($this->headers);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->headers .= $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curl_errno($this->fp)) {
|
||||||
|
throw new Requests_Exception('cURL error ' . curl_errno($this->fp) . ': ' . curl_error($this->fp), 'curlerror', $this->fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->info = curl_getinfo($this->fp);
|
||||||
|
|
||||||
|
curl_close($this->fp);
|
||||||
|
$options['hooks']->dispatch('curl.after_request', array(&$this->headers));
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect the headers as they are received
|
||||||
|
*
|
||||||
|
* @param resource $handle cURL resource
|
||||||
|
* @param string $headers Header string
|
||||||
|
* @return integer Length of provided header
|
||||||
|
*/
|
||||||
|
protected function stream_headers($handle, $headers) {
|
||||||
|
// Why do we do this? cURL will send both the final response and any
|
||||||
|
// interim responses, such as a 100 Continue. We don't need that.
|
||||||
|
// (We may want to keep this somewhere just in case)
|
||||||
|
if ($this->done_headers) {
|
||||||
|
$this->headers = '';
|
||||||
|
$this->done_headers = false;
|
||||||
|
}
|
||||||
|
$this->headers .= $headers;
|
||||||
|
|
||||||
|
if ($headers === "\r\n") {
|
||||||
|
$this->done_headers = true;
|
||||||
|
}
|
||||||
|
return strlen($headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a URL given GET data
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param array|object $data Data to build query using, see {@see http://php.net/http_build_query}
|
||||||
|
* @return string URL with data
|
||||||
|
*/
|
||||||
|
protected static function format_get($url, $data) {
|
||||||
|
if (!empty($data)) {
|
||||||
|
$url_parts = parse_url($url);
|
||||||
|
if (empty($url_parts['query'])) {
|
||||||
|
$query = $url_parts['query'] = '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$query = $url_parts['query'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= '&' . http_build_query($data, null, '&');
|
||||||
|
$query = trim($query, '&');
|
||||||
|
|
||||||
|
if (empty($url_parts['query'])) {
|
||||||
|
$url .= '?' . $query;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$url = str_replace($url_parts['query'], $query, $url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this transport is valid
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
* @return boolean True if the transport is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function test() {
|
||||||
|
return (function_exists('curl_init') && function_exists('curl_exec'));
|
||||||
|
}
|
||||||
|
}
|
3554
source/includes/Requests/Requests/Transport/cacert.pem
Normal file
381
source/includes/Requests/Requests/Transport/fsockopen.php
Normal file
|
@ -0,0 +1,381 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* fsockopen HTTP transport
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Transport
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fsockopen HTTP transport
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Transport
|
||||||
|
*/
|
||||||
|
class Requests_Transport_fsockopen implements Requests_Transport {
|
||||||
|
/**
|
||||||
|
* Raw HTTP data
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $headers = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream metadata
|
||||||
|
*
|
||||||
|
* @var array Associative array of properties, see {@see http://php.net/stream_get_meta_data}
|
||||||
|
*/
|
||||||
|
public $info;
|
||||||
|
|
||||||
|
protected $connect_error = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a request
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On failure to connect to socket (`fsockopenerror`)
|
||||||
|
* @throws Requests_Exception On socket timeout (`timeout`)
|
||||||
|
*
|
||||||
|
* @param string $url URL to request
|
||||||
|
* @param array $headers Associative array of request headers
|
||||||
|
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
|
||||||
|
* @param array $options Request options, see {@see Requests::response()} for documentation
|
||||||
|
* @return string Raw HTTP result
|
||||||
|
*/
|
||||||
|
public function request($url, $headers = array(), $data = array(), $options = array()) {
|
||||||
|
$options['hooks']->dispatch('fsockopen.before_request');
|
||||||
|
|
||||||
|
$url_parts = parse_url($url);
|
||||||
|
$host = $url_parts['host'];
|
||||||
|
$context = stream_context_create();
|
||||||
|
$verifyname = false;
|
||||||
|
|
||||||
|
// HTTPS support
|
||||||
|
if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
|
||||||
|
$remote_socket = 'ssl://' . $host;
|
||||||
|
$url_parts['port'] = 443;
|
||||||
|
|
||||||
|
$context_options = array(
|
||||||
|
'verify_peer' => true,
|
||||||
|
// 'CN_match' => $host,
|
||||||
|
'capture_peer_cert' => true
|
||||||
|
);
|
||||||
|
$verifyname = true;
|
||||||
|
|
||||||
|
// SNI, if enabled (OpenSSL >=0.9.8j)
|
||||||
|
if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) {
|
||||||
|
$context_options['SNI_enabled'] = true;
|
||||||
|
if (isset($options['verifyname']) && $options['verifyname'] === false) {
|
||||||
|
$context_options['SNI_enabled'] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($options['verify'])) {
|
||||||
|
if ($options['verify'] === false) {
|
||||||
|
$context_options['verify_peer'] = false;
|
||||||
|
} elseif (is_string($options['verify'])) {
|
||||||
|
$context_options['cafile'] = $options['verify'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($options['verifyname']) && $options['verifyname'] === false) {
|
||||||
|
$verifyname = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_context_set_option($context, array('ssl' => $context_options));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$remote_socket = 'tcp://' . $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
$proxy = isset( $options['proxy'] );
|
||||||
|
$proxy_auth = $proxy && isset( $options['proxy_username'] ) && isset( $options['proxy_password'] );
|
||||||
|
|
||||||
|
if (!isset($url_parts['port'])) {
|
||||||
|
$url_parts['port'] = 80;
|
||||||
|
}
|
||||||
|
$remote_socket .= ':' . $url_parts['port'];
|
||||||
|
|
||||||
|
set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE);
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('fsockopen.remote_socket', array(&$remote_socket));
|
||||||
|
|
||||||
|
$fp = stream_socket_client($remote_socket, $errno, $errstr, $options['timeout'], STREAM_CLIENT_CONNECT, $context);
|
||||||
|
|
||||||
|
restore_error_handler();
|
||||||
|
|
||||||
|
if ($verifyname) {
|
||||||
|
if (!$this->verify_certificate_from_context($host, $context)) {
|
||||||
|
throw new Requests_Exception('SSL certificate did not match the requested domain name', 'ssl.no_match');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$fp) {
|
||||||
|
if ($errno === 0) {
|
||||||
|
// Connection issue
|
||||||
|
throw new Requests_Exception(rtrim($this->connect_error), 'fsockopen.connect_error');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Requests_Exception($errstr, 'fsockopenerror');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$request_body = '';
|
||||||
|
$out = '';
|
||||||
|
switch ($options['type']) {
|
||||||
|
case Requests::POST:
|
||||||
|
case Requests::PUT:
|
||||||
|
case Requests::PATCH:
|
||||||
|
if (isset($url_parts['path'])) {
|
||||||
|
$path = $url_parts['path'];
|
||||||
|
if (isset($url_parts['query'])) {
|
||||||
|
$path .= '?' . $url_parts['query'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$path = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['hooks']->dispatch( 'fsockopen.remote_host_path', array( &$path, $url ) );
|
||||||
|
$out = $options['type'] . " $path HTTP/1.0\r\n";
|
||||||
|
|
||||||
|
if (is_array($data)) {
|
||||||
|
$request_body = http_build_query($data, null, '&');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$request_body = $data;
|
||||||
|
}
|
||||||
|
if (empty($headers['Content-Length'])) {
|
||||||
|
$headers['Content-Length'] = strlen($request_body);
|
||||||
|
}
|
||||||
|
if (empty($headers['Content-Type'])) {
|
||||||
|
$headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Requests::HEAD:
|
||||||
|
case Requests::GET:
|
||||||
|
case Requests::DELETE:
|
||||||
|
$path = self::format_get($url_parts, $data);
|
||||||
|
$options['hooks']->dispatch('fsockopen.remote_host_path', array(&$path, $url));
|
||||||
|
$out = $options['type'] . " $path HTTP/1.0\r\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$out .= "Host: {$url_parts['host']}";
|
||||||
|
|
||||||
|
if ($url_parts['port'] !== 80) {
|
||||||
|
$out .= ":{$url_parts['port']}";
|
||||||
|
}
|
||||||
|
$out .= "\r\n";
|
||||||
|
|
||||||
|
$out .= "User-Agent: {$options['useragent']}\r\n";
|
||||||
|
$accept_encoding = $this->accept_encoding();
|
||||||
|
if (!empty($accept_encoding)) {
|
||||||
|
$out .= "Accept-Encoding: $accept_encoding\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = Requests::flatten($headers);
|
||||||
|
|
||||||
|
if (!empty($headers)) {
|
||||||
|
$out .= implode($headers, "\r\n") . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('fsockopen.after_headers', array(&$out));
|
||||||
|
|
||||||
|
if (substr($out, -2) !== "\r\n") {
|
||||||
|
$out .= "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$out .= "Connection: Close\r\n\r\n" . $request_body;
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('fsockopen.before_send', array(&$out));
|
||||||
|
|
||||||
|
fwrite($fp, $out);
|
||||||
|
$options['hooks']->dispatch('fsockopen.after_send', array(&$fake_headers));
|
||||||
|
|
||||||
|
if (!$options['blocking']) {
|
||||||
|
fclose($fp);
|
||||||
|
$fake_headers = '';
|
||||||
|
$options['hooks']->dispatch('fsockopen.after_request', array(&$fake_headers));
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
stream_set_timeout($fp, $options['timeout']);
|
||||||
|
|
||||||
|
$this->info = stream_get_meta_data($fp);
|
||||||
|
|
||||||
|
$this->headers = '';
|
||||||
|
$this->info = stream_get_meta_data($fp);
|
||||||
|
if (!$options['filename']) {
|
||||||
|
while (!feof($fp)) {
|
||||||
|
$this->info = stream_get_meta_data($fp);
|
||||||
|
if ($this->info['timed_out']) {
|
||||||
|
throw new Requests_Exception('fsocket timed out', 'timeout');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->headers .= fread($fp, 1160);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$download = fopen($options['filename'], 'wb');
|
||||||
|
$doingbody = false;
|
||||||
|
$response = '';
|
||||||
|
while (!feof($fp)) {
|
||||||
|
$this->info = stream_get_meta_data($fp);
|
||||||
|
if ($this->info['timed_out']) {
|
||||||
|
throw new Requests_Exception('fsocket timed out', 'timeout');
|
||||||
|
}
|
||||||
|
|
||||||
|
$block = fread($fp, 1160);
|
||||||
|
if ($doingbody) {
|
||||||
|
fwrite($download, $block);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$response .= $block;
|
||||||
|
if (strpos($response, "\r\n\r\n")) {
|
||||||
|
list($this->headers, $block) = explode("\r\n\r\n", $response, 2);
|
||||||
|
$doingbody = true;
|
||||||
|
fwrite($download, $block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose($download);
|
||||||
|
}
|
||||||
|
fclose($fp);
|
||||||
|
|
||||||
|
$options['hooks']->dispatch('fsockopen.after_request', array(&$this->headers));
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send multiple requests simultaneously
|
||||||
|
*
|
||||||
|
* @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request}
|
||||||
|
* @param array $options Global options, see {@see Requests::response()} for documentation
|
||||||
|
* @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
|
||||||
|
*/
|
||||||
|
public function request_multiple($requests, $options) {
|
||||||
|
$responses = array();
|
||||||
|
$class = get_class($this);
|
||||||
|
foreach ($requests as $id => $request) {
|
||||||
|
try {
|
||||||
|
$handler = new $class();
|
||||||
|
$responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']);
|
||||||
|
|
||||||
|
$request['options']['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$id], $request));
|
||||||
|
}
|
||||||
|
catch (Requests_Exception $e) {
|
||||||
|
$responses[$id] = $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_string($responses[$id])) {
|
||||||
|
$request['options']['hooks']->dispatch('multiple.request.complete', array(&$responses[$id], $id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the encodings we can accept
|
||||||
|
*
|
||||||
|
* @return string Accept-Encoding header value
|
||||||
|
*/
|
||||||
|
protected static function accept_encoding() {
|
||||||
|
$type = array();
|
||||||
|
if (function_exists('gzinflate')) {
|
||||||
|
$type[] = 'deflate;q=1.0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('gzuncompress')) {
|
||||||
|
$type[] = 'compress;q=0.5';
|
||||||
|
}
|
||||||
|
|
||||||
|
$type[] = 'gzip;q=0.5';
|
||||||
|
|
||||||
|
return implode(', ', $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a URL given GET data
|
||||||
|
*
|
||||||
|
* @param array $url_parts
|
||||||
|
* @param array|object $data Data to build query using, see {@see http://php.net/http_build_query}
|
||||||
|
* @return string URL with data
|
||||||
|
*/
|
||||||
|
protected static function format_get($url_parts, $data) {
|
||||||
|
if (!empty($data)) {
|
||||||
|
if (empty($url_parts['query']))
|
||||||
|
$url_parts['query'] = '';
|
||||||
|
|
||||||
|
$url_parts['query'] .= '&' . http_build_query($data, null, '&');
|
||||||
|
$url_parts['query'] = trim($url_parts['query'], '&');
|
||||||
|
}
|
||||||
|
if (isset($url_parts['path'])) {
|
||||||
|
if (isset($url_parts['query'])) {
|
||||||
|
$get = $url_parts['path'] . '?' . $url_parts['query'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$get = $url_parts['path'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$get = '/';
|
||||||
|
}
|
||||||
|
return $get;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error handler for stream_socket_client()
|
||||||
|
*
|
||||||
|
* @param int $errno Error number (e.g. E_WARNING)
|
||||||
|
* @param string $errstr Error message
|
||||||
|
*/
|
||||||
|
public function connect_error_handler($errno, $errstr) {
|
||||||
|
// Double-check we can handle it
|
||||||
|
if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) {
|
||||||
|
// Return false to indicate the default error handler should engage
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->connect_error .= $errstr . "\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the certificate against common name and subject alternative names
|
||||||
|
*
|
||||||
|
* Unfortunately, PHP doesn't check the certificate against the alternative
|
||||||
|
* names, leading things like 'https://www.github.com/' to be invalid.
|
||||||
|
* Instead
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`)
|
||||||
|
* @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
|
||||||
|
* @param string $host Host name to verify against
|
||||||
|
* @param resource $context Stream context
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function verify_certificate_from_context($host, $context) {
|
||||||
|
$meta = stream_context_get_options($context);
|
||||||
|
|
||||||
|
// If we don't have SSL options, then we couldn't make the connection at
|
||||||
|
// all
|
||||||
|
if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) {
|
||||||
|
throw new Requests_Exception(rtrim($this->connect_error), 'ssl.connect_error');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cert = openssl_x509_parse($meta['ssl']['peer_certificate']);
|
||||||
|
|
||||||
|
return Requests_SSL::verify_certificate($host, $cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this transport is valid
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
* @return boolean True if the transport is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function test() {
|
||||||
|
return function_exists('fsockopen');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Case-insensitive dictionary, suitable for HTTP headers
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Case-insensitive dictionary, suitable for HTTP headers
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
class Requests_Utility_CaseInsensitiveDictionary implements ArrayAccess, IteratorAggregate {
|
||||||
|
/**
|
||||||
|
* Actual item data
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $data = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given item exists
|
||||||
|
*
|
||||||
|
* @param string $key Item key
|
||||||
|
* @return boolean Does the item exist?
|
||||||
|
*/
|
||||||
|
public function offsetExists($key) {
|
||||||
|
$key = strtolower($key);
|
||||||
|
return isset($this->data[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value for the item
|
||||||
|
*
|
||||||
|
* @param string $key Item key
|
||||||
|
* @return string Item value
|
||||||
|
*/
|
||||||
|
public function offsetGet($key) {
|
||||||
|
$key = strtolower($key);
|
||||||
|
if (!isset($this->data[$key]))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return $this->data[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the given item
|
||||||
|
*
|
||||||
|
* @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
|
||||||
|
*
|
||||||
|
* @param string $key Item name
|
||||||
|
* @param string $value Item value
|
||||||
|
*/
|
||||||
|
public function offsetSet($key, $value) {
|
||||||
|
if ($key === null) {
|
||||||
|
throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = strtolower($key);
|
||||||
|
$this->data[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unset the given header
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
public function offsetUnset($key) {
|
||||||
|
unset($this->data[strtolower($key)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an iterator for the data
|
||||||
|
*
|
||||||
|
* @return ArrayIterator
|
||||||
|
*/
|
||||||
|
public function getIterator() {
|
||||||
|
return new ArrayIterator($this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the headers as an array
|
||||||
|
*
|
||||||
|
* @return array Header data
|
||||||
|
*/
|
||||||
|
public function getAll() {
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Iterator for arrays requiring filtered values
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterator for arrays requiring filtered values
|
||||||
|
*
|
||||||
|
* @package Requests
|
||||||
|
* @subpackage Utilities
|
||||||
|
*/
|
||||||
|
class Requests_Utility_FilteredIterator extends ArrayIterator {
|
||||||
|
/**
|
||||||
|
* Create a new iterator
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @param callable $callback Callback to be called on each value
|
||||||
|
*/
|
||||||
|
public function __construct($data, $callback) {
|
||||||
|
parent::__construct($data);
|
||||||
|
|
||||||
|
$this->callback = $callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current item's value after filtering
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function current() {
|
||||||
|
$value = parent::current();
|
||||||
|
$value = call_user_func($this->callback, $value);
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
63
source/includes/auth.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
// No direct call
|
||||||
|
if( !defined( 'YOURLS_ABSPATH' ) ) die();
|
||||||
|
|
||||||
|
$auth = yourls_is_valid_user();
|
||||||
|
|
||||||
|
if( $auth !== true ) {
|
||||||
|
|
||||||
|
// API mode,
|
||||||
|
if ( yourls_is_API() ) {
|
||||||
|
$format = ( isset($_REQUEST['format']) ? $_REQUEST['format'] : 'xml' );
|
||||||
|
$callback = ( isset($_REQUEST['callback']) ? $_REQUEST['callback'] : '' );
|
||||||
|
yourls_api_output( $format, array(
|
||||||
|
'simple' => $auth,
|
||||||
|
'message' => $auth,
|
||||||
|
'errorCode' => 403,
|
||||||
|
'callback' => $callback,
|
||||||
|
) );
|
||||||
|
|
||||||
|
// Regular mode
|
||||||
|
} else {
|
||||||
|
yourls_login_screen( $auth );
|
||||||
|
}
|
||||||
|
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
yourls_do_action( 'auth_successful' );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following code is a shim that helps users store passwords securely in config.php
|
||||||
|
* by storing a password hash and removing the plaintext.
|
||||||
|
*
|
||||||
|
* TODO: Remove this once real user management is implemented
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Did we just fail at encrypting passwords ?
|
||||||
|
if ( isset( $_GET['dismiss'] ) && $_GET['dismiss'] == 'hasherror' ) {
|
||||||
|
yourls_update_option( 'defer_hashing_error', time() + 86400 * 7 ); // now + 1 week
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Encrypt passwords that are clear text
|
||||||
|
if ( !defined( 'YOURLS_NO_HASH_PASSWORD' ) && yourls_has_cleartext_passwords() ) {
|
||||||
|
$hash = yourls_hash_passwords_now( YOURLS_CONFIGFILE );
|
||||||
|
if ( $hash === true ) {
|
||||||
|
// Hashing succesful. Remove flag from DB if any.
|
||||||
|
if( yourls_get_option( 'defer_hashing_error' ) )
|
||||||
|
yourls_delete_option( 'defer_hashing_error' );
|
||||||
|
} else {
|
||||||
|
// It failed, display message for first time or if last time was a week ago
|
||||||
|
if ( time() > yourls_get_option( 'defer_hashing_error' ) or !yourls_get_option( 'defer_hashing_error' ) ) {
|
||||||
|
$message = yourls_s( 'Could not auto-encrypt passwords. Error was: "%s".', $hash );
|
||||||
|
$message .= ' ';
|
||||||
|
$message .= yourls_s( '<a href="%s">Get help</a>.', 'http://yourls.org/userpassword' );
|
||||||
|
$message .= '</p><p>';
|
||||||
|
$message .= yourls_s( '<a href="%s">Click here</a> to dismiss this message for one week.', '?dismiss=hasherror' );
|
||||||
|
|
||||||
|
yourls_add_notice( $message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
source/includes/class-mysql.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick the right DB class and return an instance
|
||||||
|
*
|
||||||
|
* @since 1.7
|
||||||
|
* @param string $extension Optional: user defined choice
|
||||||
|
* @return class $ydb DB class instance
|
||||||
|
*/
|
||||||
|
function yourls_set_DB_driver( ) {
|
||||||
|
|
||||||
|
// Auto-pick the driver. Priority: user defined, then PDO, then mysqli, then mysql
|
||||||
|
if ( defined( 'YOURLS_DB_DRIVER' ) ) {
|
||||||
|
$driver = strtolower( YOURLS_DB_DRIVER ); // accept 'MySQL', 'mySQL', etc
|
||||||
|
} elseif ( extension_loaded( 'pdo_mysql' ) ) {
|
||||||
|
$driver = 'pdo';
|
||||||
|
} elseif ( extension_loaded( 'mysqli' ) ) {
|
||||||
|
$driver = 'mysqli';
|
||||||
|
} elseif ( extension_loaded( 'mysql' ) ) {
|
||||||
|
$driver = 'mysql';
|
||||||
|
} else {
|
||||||
|
$driver = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the new driver
|
||||||
|
if ( in_array( $driver, array( 'mysql', 'mysqli', 'pdo' ) ) ) {
|
||||||
|
require_once( YOURLS_INC . '/ezSQL/ez_sql_core.php' );
|
||||||
|
require_once( YOURLS_INC . '/ezSQL/ez_sql_core_yourls.php' );
|
||||||
|
require_once( YOURLS_INC . '/ezSQL/ez_sql_' . $driver . '.php' );
|
||||||
|
require_once( YOURLS_INC . '/ezSQL/ez_sql_' . $driver . '_yourls.php' );
|
||||||
|
}
|
||||||
|
$class = 'ezSQL_' . $driver . '_yourls';
|
||||||
|
|
||||||
|
global $ydb;
|
||||||
|
|
||||||
|
if ( !class_exists( $class, false ) ) {
|
||||||
|
$ydb = new stdClass();
|
||||||
|
yourls_die(
|
||||||
|
yourls__( 'YOURLS requires the mysql, mysqli or pdo_mysql PHP extension. No extension found. Check your server config, or contact your host.' ),
|
||||||
|
yourls__( 'Fatal error' ),
|
||||||
|
503
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
yourls_do_action( 'set_DB_driver', $driver );
|
||||||
|
|
||||||
|
$ydb = new $class( YOURLS_DB_USER, YOURLS_DB_PASS, YOURLS_DB_NAME, YOURLS_DB_HOST );
|
||||||
|
|
||||||
|
yourls_debug_log( "DB driver: $driver" );
|
||||||
|
}
|
||||||
|
|
17
source/includes/ezSQL/README.md
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# ezSQL
|
||||||
|
|
||||||
|
> -===================================================
|
||||||
|
> Author: Justin Vincent - http://justinvincent.com/ezsql
|
||||||
|
> Name: ezSQL
|
||||||
|
> Desc: Class to make it very easy to deal with database connections.
|
||||||
|
> License: FREE / Donation (LGPL - You may do what you like with ezSQL - no exceptions.)
|
||||||
|
> -===================================================
|
||||||
|
|
||||||
|
Source code: https://github.com/jv2222/ezSQL
|
||||||
|
|
||||||
|
# ezSQL - YOURLS implementation
|
||||||
|
|
||||||
|
* The original ezSQL files (`ez_sql_[core|mysql|mysqli|pdo].php`) are unmodified to make updating easy when (if) the original classes are updated.
|
||||||
|
* The YOURLS modifications live in their own files (`ez_sql_*_yourls.php`).
|
||||||
|
* Each `ez_sql_stuff.php` must have a corresponding `ez_sql_stuff_yourls_php` file.
|
||||||
|
|
614
source/includes/ezSQL/ez_sql_core.php
Normal file
|
@ -0,0 +1,614 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Author: Justin Vincent (jv@vip.ie)
|
||||||
|
* Web...: http://justinvincent.com
|
||||||
|
* Name..: ezSQL
|
||||||
|
* Desc..: ezSQL Core module - database abstraction library to make
|
||||||
|
* it very easy to deal with databases. ezSQLcore can not be used by
|
||||||
|
* itself (it is designed for use by database specific modules).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* ezSQL Constants
|
||||||
|
*/
|
||||||
|
|
||||||
|
define('EZSQL_VERSION','2.17');
|
||||||
|
define('OBJECT','OBJECT',true);
|
||||||
|
define('ARRAY_A','ARRAY_A',true);
|
||||||
|
define('ARRAY_N','ARRAY_N',true);
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Core class containg common functions to manipulate query result
|
||||||
|
* sets once returned
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ezSQLcore
|
||||||
|
{
|
||||||
|
|
||||||
|
var $trace = false; // same as $debug_all
|
||||||
|
var $debug_all = false; // same as $trace
|
||||||
|
var $debug_called = false;
|
||||||
|
var $vardump_called = false;
|
||||||
|
var $show_errors = true;
|
||||||
|
var $num_queries = 0;
|
||||||
|
var $last_query = null;
|
||||||
|
var $last_error = null;
|
||||||
|
var $col_info = null;
|
||||||
|
var $captured_errors = array();
|
||||||
|
var $cache_dir = false;
|
||||||
|
var $cache_queries = false;
|
||||||
|
var $cache_inserts = false;
|
||||||
|
var $use_disk_cache = false;
|
||||||
|
var $cache_timeout = 24; // hours
|
||||||
|
var $timers = array();
|
||||||
|
var $total_query_time = 0;
|
||||||
|
var $db_connect_time = 0;
|
||||||
|
var $trace_log = array();
|
||||||
|
var $use_trace_log = false;
|
||||||
|
var $sql_log_file = false;
|
||||||
|
var $do_profile = false;
|
||||||
|
var $profile_times = array();
|
||||||
|
|
||||||
|
// == TJH == default now needed for echo of debug function
|
||||||
|
var $debug_echo_is_on = true;
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
function ezSQLcore()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Get host and port from an "host:port" notation.
|
||||||
|
* Returns array of host and port. If port is omitted, returns $default
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_host_port( $host, $default = false )
|
||||||
|
{
|
||||||
|
$port = $default;
|
||||||
|
if ( false !== strpos( $host, ':' ) ) {
|
||||||
|
list( $host, $port ) = explode( ':', $host );
|
||||||
|
$port = (int)$port;
|
||||||
|
}
|
||||||
|
return array( $host, $port );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Print SQL/DB error - over-ridden by specific DB class
|
||||||
|
*/
|
||||||
|
|
||||||
|
function register_error($err_str)
|
||||||
|
{
|
||||||
|
// Keep track of last error
|
||||||
|
$this->last_error = $err_str;
|
||||||
|
|
||||||
|
// Capture all errors to an error array no matter what happens
|
||||||
|
$this->captured_errors[] = array
|
||||||
|
(
|
||||||
|
'error_str' => $err_str,
|
||||||
|
'query' => $this->last_query
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Turn error handling on or off..
|
||||||
|
*/
|
||||||
|
|
||||||
|
function show_errors()
|
||||||
|
{
|
||||||
|
$this->show_errors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide_errors()
|
||||||
|
{
|
||||||
|
$this->show_errors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Kill cached query results
|
||||||
|
*/
|
||||||
|
|
||||||
|
function flush()
|
||||||
|
{
|
||||||
|
// Get rid of these
|
||||||
|
$this->last_result = null;
|
||||||
|
$this->col_info = null;
|
||||||
|
$this->last_query = null;
|
||||||
|
$this->from_disk_cache = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Get one variable from the DB - see docs for more detail
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_var($query=null,$x=0,$y=0)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Log how the function was called
|
||||||
|
$this->func_call = "\$db->get_var(\"$query\",$x,$y)";
|
||||||
|
|
||||||
|
// If there is a query then perform it if not then use cached results..
|
||||||
|
if ( $query )
|
||||||
|
{
|
||||||
|
$this->query($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract var out of cached results based x,y vals
|
||||||
|
if ( $this->last_result[$y] )
|
||||||
|
{
|
||||||
|
$values = array_values(get_object_vars($this->last_result[$y]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a value return it else return null
|
||||||
|
return (isset($values[$x]) && $values[$x]!=='')?$values[$x]:null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Get one row from the DB - see docs for more detail
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_row($query=null,$output=OBJECT,$y=0)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Log how the function was called
|
||||||
|
$this->func_call = "\$db->get_row(\"$query\",$output,$y)";
|
||||||
|
|
||||||
|
// If there is a query then perform it if not then use cached results..
|
||||||
|
if ( $query )
|
||||||
|
{
|
||||||
|
$this->query($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the output is an object then return object using the row offset..
|
||||||
|
if ( $output == OBJECT )
|
||||||
|
{
|
||||||
|
return $this->last_result[$y]?$this->last_result[$y]:null;
|
||||||
|
}
|
||||||
|
// If the output is an associative array then return row as such..
|
||||||
|
elseif ( $output == ARRAY_A )
|
||||||
|
{
|
||||||
|
return $this->last_result[$y]?get_object_vars($this->last_result[$y]):null;
|
||||||
|
}
|
||||||
|
// If the output is an numerical array then return row as such..
|
||||||
|
elseif ( $output == ARRAY_N )
|
||||||
|
{
|
||||||
|
return $this->last_result[$y]?array_values(get_object_vars($this->last_result[$y])):null;
|
||||||
|
}
|
||||||
|
// If invalid output type was specified..
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->show_errors ? trigger_error(" \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N",E_USER_WARNING) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Function to get 1 column from the cached result set based in X index
|
||||||
|
* see docs for usage and info
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_col($query=null,$x=0)
|
||||||
|
{
|
||||||
|
|
||||||
|
$new_array = array();
|
||||||
|
|
||||||
|
// If there is a query then perform it if not then use cached results..
|
||||||
|
if ( $query )
|
||||||
|
{
|
||||||
|
$this->query($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the column values
|
||||||
|
for ( $i=0; $i < count($this->last_result); $i++ )
|
||||||
|
{
|
||||||
|
$new_array[$i] = $this->get_var(null,$x,$i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Return the the query as a result set - see docs for more details
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_results($query=null, $output = OBJECT)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Log how the function was called
|
||||||
|
$this->func_call = "\$db->get_results(\"$query\", $output)";
|
||||||
|
|
||||||
|
// If there is a query then perform it if not then use cached results..
|
||||||
|
if ( $query )
|
||||||
|
{
|
||||||
|
$this->query($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send back array of objects. Each row is an object
|
||||||
|
if ( $output == OBJECT )
|
||||||
|
{
|
||||||
|
return $this->last_result;
|
||||||
|
}
|
||||||
|
elseif ( $output == ARRAY_A || $output == ARRAY_N )
|
||||||
|
{
|
||||||
|
if ( $this->last_result )
|
||||||
|
{
|
||||||
|
$i=0;
|
||||||
|
foreach( $this->last_result as $row )
|
||||||
|
{
|
||||||
|
|
||||||
|
$new_array[$i] = get_object_vars($row);
|
||||||
|
|
||||||
|
if ( $output == ARRAY_N )
|
||||||
|
{
|
||||||
|
$new_array[$i] = array_values($new_array[$i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new_array;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Function to get column meta data info pertaining to the last query
|
||||||
|
* see docs for more info and usage
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_col_info($info_type="name",$col_offset=-1)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( $this->col_info )
|
||||||
|
{
|
||||||
|
if ( $col_offset == -1 )
|
||||||
|
{
|
||||||
|
$i=0;
|
||||||
|
foreach($this->col_info as $col )
|
||||||
|
{
|
||||||
|
$new_array[$i] = $col->{$info_type};
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return $new_array;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $this->col_info[$col_offset]->{$info_type};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* store_cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
function store_cache($query,$is_insert)
|
||||||
|
{
|
||||||
|
|
||||||
|
// The would be cache file for this query
|
||||||
|
$cache_file = $this->cache_dir.'/'.md5($query);
|
||||||
|
|
||||||
|
// disk caching of queries
|
||||||
|
if ( $this->use_disk_cache && ( $this->cache_queries && ! $is_insert ) || ( $this->cache_inserts && $is_insert ))
|
||||||
|
{
|
||||||
|
if ( ! is_dir($this->cache_dir) )
|
||||||
|
{
|
||||||
|
$this->register_error("Could not open cache dir: $this->cache_dir");
|
||||||
|
$this->show_errors ? trigger_error("Could not open cache dir: $this->cache_dir",E_USER_WARNING) : null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cache all result values
|
||||||
|
$result_cache = array
|
||||||
|
(
|
||||||
|
'col_info' => $this->col_info,
|
||||||
|
'last_result' => $this->last_result,
|
||||||
|
'num_rows' => $this->num_rows,
|
||||||
|
'return_value' => $this->num_rows,
|
||||||
|
);
|
||||||
|
file_put_contents($cache_file, serialize($result_cache));
|
||||||
|
if( file_exists($cache_file . ".updating") )
|
||||||
|
unlink($cache_file . ".updating");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* get_cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_cache($query)
|
||||||
|
{
|
||||||
|
|
||||||
|
// The would be cache file for this query
|
||||||
|
$cache_file = $this->cache_dir.'/'.md5($query);
|
||||||
|
|
||||||
|
// Try to get previously cached version
|
||||||
|
if ( $this->use_disk_cache && file_exists($cache_file) )
|
||||||
|
{
|
||||||
|
// Only use this cache file if less than 'cache_timeout' (hours)
|
||||||
|
if ( (time() - filemtime($cache_file)) > ($this->cache_timeout*3600) &&
|
||||||
|
!(file_exists($cache_file . ".updating") && (time() - filemtime($cache_file . ".updating") < 60)) )
|
||||||
|
{
|
||||||
|
touch($cache_file . ".updating"); // Show that we in the process of updating the cache
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$result_cache = unserialize(file_get_contents($cache_file));
|
||||||
|
|
||||||
|
$this->col_info = $result_cache['col_info'];
|
||||||
|
$this->last_result = $result_cache['last_result'];
|
||||||
|
$this->num_rows = $result_cache['num_rows'];
|
||||||
|
|
||||||
|
$this->from_disk_cache = true;
|
||||||
|
|
||||||
|
// If debug ALL queries
|
||||||
|
$this->trace || $this->debug_all ? $this->debug() : null ;
|
||||||
|
|
||||||
|
return $result_cache['return_value'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Dumps the contents of any input variable to screen in a nicely
|
||||||
|
* formatted and easy to understand way - any type: Object, Var or Array
|
||||||
|
*/
|
||||||
|
|
||||||
|
function vardump($mixed='')
|
||||||
|
{
|
||||||
|
|
||||||
|
// Start outup buffering
|
||||||
|
ob_start();
|
||||||
|
|
||||||
|
echo "<p><table><tr><td bgcolor=ffffff><blockquote><font color=000090>";
|
||||||
|
echo "<pre><font face=arial>";
|
||||||
|
|
||||||
|
if ( ! $this->vardump_called )
|
||||||
|
{
|
||||||
|
echo "<font color=800080><b>ezSQL</b> (v".EZSQL_VERSION.") <b>Variable Dump..</b></font>\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$var_type = gettype ($mixed);
|
||||||
|
print_r(($mixed?$mixed:"<font color=red>No Value / False</font>"));
|
||||||
|
echo "\n\n<b>Type:</b> " . ucfirst($var_type) . "\n";
|
||||||
|
echo "<b>Last Query</b> [$this->num_queries]<b>:</b> ".($this->last_query?$this->last_query:"NULL")."\n";
|
||||||
|
echo "<b>Last Function Call:</b> " . ($this->func_call?$this->func_call:"None")."\n";
|
||||||
|
echo "<b>Last Rows Returned:</b> ".count($this->last_result)."\n";
|
||||||
|
echo "</font></pre></font></blockquote></td></tr></table>".$this->donation();
|
||||||
|
echo "\n<hr size=1 noshade color=dddddd>";
|
||||||
|
|
||||||
|
// Stop output buffering and capture debug HTML
|
||||||
|
$html = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
// Only echo output if it is turned on
|
||||||
|
if ( $this->debug_echo_is_on )
|
||||||
|
{
|
||||||
|
echo $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->vardump_called = true;
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Alias for the above function
|
||||||
|
*/
|
||||||
|
|
||||||
|
function dumpvar($mixed)
|
||||||
|
{
|
||||||
|
$this->vardump($mixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Displays the last query string that was sent to the database & a
|
||||||
|
* table listing results (if there were any).
|
||||||
|
* (abstracted into a seperate file to save server overhead).
|
||||||
|
*/
|
||||||
|
|
||||||
|
function debug($print_to_screen=true)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Start outup buffering
|
||||||
|
ob_start();
|
||||||
|
|
||||||
|
echo "<blockquote>";
|
||||||
|
|
||||||
|
// Only show ezSQL credits once..
|
||||||
|
if ( ! $this->debug_called )
|
||||||
|
{
|
||||||
|
echo "<font color=800080 face=arial size=2><b>ezSQL</b> (v".EZSQL_VERSION.") <b>Debug..</b></font><p>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $this->last_error )
|
||||||
|
{
|
||||||
|
echo "<font face=arial size=2 color=000099><b>Last Error --</b> [<font color=000000><b>$this->last_error</b></font>]<p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $this->from_disk_cache )
|
||||||
|
{
|
||||||
|
echo "<font face=arial size=2 color=000099><b>Results retrieved from disk cache</b></font><p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<font face=arial size=2 color=000099><b>Query</b> [$this->num_queries] <b>--</b> ";
|
||||||
|
echo "[<font color=000000><b>$this->last_query</b></font>]</font><p>";
|
||||||
|
|
||||||
|
echo "<font face=arial size=2 color=000099><b>Query Result..</b></font>";
|
||||||
|
echo "<blockquote>";
|
||||||
|
|
||||||
|
if ( $this->col_info )
|
||||||
|
{
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// Results top rows
|
||||||
|
|
||||||
|
echo "<table cellpadding=5 cellspacing=1 bgcolor=555555>";
|
||||||
|
echo "<tr bgcolor=eeeeee><td nowrap valign=bottom><font color=555599 face=arial size=2><b>(row)</b></font></td>";
|
||||||
|
|
||||||
|
|
||||||
|
for ( $i=0; $i < count($this->col_info); $i++ )
|
||||||
|
{
|
||||||
|
echo "<td nowrap align=left valign=top><font size=1 color=555599 face=arial>{$this->col_info[$i]->type} {$this->col_info[$i]->max_length}</font><br><span style='font-family: arial; font-size: 10pt; font-weight: bold;'>{$this->col_info[$i]->name}</span></td>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</tr>";
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// print main results
|
||||||
|
|
||||||
|
if ( $this->last_result )
|
||||||
|
{
|
||||||
|
|
||||||
|
$i=0;
|
||||||
|
foreach ( $this->get_results(null,ARRAY_N) as $one_row )
|
||||||
|
{
|
||||||
|
$i++;
|
||||||
|
echo "<tr bgcolor=ffffff><td bgcolor=eeeeee nowrap align=middle><font size=2 color=555599 face=arial>$i</font></td>";
|
||||||
|
|
||||||
|
foreach ( $one_row as $item )
|
||||||
|
{
|
||||||
|
echo "<td nowrap><font face=arial size=2>$item</font></td>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // if last result
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "<tr bgcolor=ffffff><td colspan=".(count($this->col_info)+1)."><font face=arial size=2>No Results</font></td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</table>";
|
||||||
|
|
||||||
|
} // if col_info
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "<font face=arial size=2>No Results</font>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</blockquote></blockquote>".$this->donation()."<hr noshade color=dddddd size=1>";
|
||||||
|
|
||||||
|
// Stop output buffering and capture debug HTML
|
||||||
|
$html = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
// Only echo output if it is turned on
|
||||||
|
if ( $this->debug_echo_is_on && $print_to_screen)
|
||||||
|
{
|
||||||
|
echo $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->debug_called = true;
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Naughty little function to ask for some remuniration!
|
||||||
|
*/
|
||||||
|
|
||||||
|
function donation()
|
||||||
|
{
|
||||||
|
return "<font size=1 face=arial color=000000>If ezSQL has helped <a href=\"https://www.paypal.com/xclick/business=justin%40justinvincent.com&item_name=ezSQL&no_note=1&tax=0\" style=\"color: 0000CC;\">make a donation!?</a> <!--[ go on! you know you want to! ]--></font>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Timer related functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
function timer_get_cur()
|
||||||
|
{
|
||||||
|
list($usec, $sec) = explode(" ",microtime());
|
||||||
|
return ((float)$usec + (float)$sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
function timer_start($timer_name)
|
||||||
|
{
|
||||||
|
$this->timers[$timer_name] = $this->timer_get_cur();
|
||||||
|
}
|
||||||
|
|
||||||
|
function timer_elapsed($timer_name)
|
||||||
|
{
|
||||||
|
return round($this->timer_get_cur() - $this->timers[$timer_name],2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function timer_update_global($timer_name)
|
||||||
|
{
|
||||||
|
if ( $this->do_profile )
|
||||||
|
{
|
||||||
|
$this->profile_times[] = array
|
||||||
|
(
|
||||||
|
'query' => $this->last_query,
|
||||||
|
'time' => $this->timer_elapsed($timer_name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->total_query_time += $this->timer_elapsed($timer_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Creates a SET nvp sql string from an associative array (and escapes all values)
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* $db_data = array('login'=>'jv','email'=>'jv@vip.ie', 'user_id' => 1, 'created' => 'NOW()');
|
||||||
|
*
|
||||||
|
* $db->query("INSERT INTO users SET ".$db->get_set($db_data));
|
||||||
|
*
|
||||||
|
* ...OR...
|
||||||
|
*
|
||||||
|
* $db->query("UPDATE users SET ".$db->get_set($db_data)." WHERE user_id = 1");
|
||||||
|
*
|
||||||
|
* Output:
|
||||||
|
*
|
||||||
|
* login = 'jv', email = 'jv@vip.ie', user_id = 1, created = NOW()
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_set($params)
|
||||||
|
{
|
||||||
|
if( !is_array( $params ) )
|
||||||
|
{
|
||||||
|
$this->register_error( 'get_set() parameter invalid. Expected array in '.__FILE__.' on line '.__LINE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$sql = array();
|
||||||
|
foreach ( $params as $field => $val )
|
||||||
|
{
|
||||||
|
if ( $val === 'true' || $val === true )
|
||||||
|
$val = 1;
|
||||||
|
if ( $val === 'false' || $val === false )
|
||||||
|
$val = 0;
|
||||||
|
|
||||||
|
switch( $val ){
|
||||||
|
case 'NOW()' :
|
||||||
|
case 'NULL' :
|
||||||
|
$sql[] = "$field = $val";
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
$sql[] = "$field = '".$this->escape( $val )."'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode( ', ' , $sql );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
source/includes/ezSQL/ez_sql_core_yourls.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class ezSQLcore_YOURLS extends ezSQLcore {
|
||||||
|
|
||||||
|
var $debug_log = array();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
328
source/includes/ezSQL/ez_sql_mysql.php
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Author: Justin Vincent (jv@jvmultimedia.com)
|
||||||
|
* Web...: http://twitter.com/justinvincent
|
||||||
|
* Name..: ezSQL_mysql
|
||||||
|
* Desc..: mySQL component (part of ezSQL databse abstraction library)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* ezSQL error strings - mySQL
|
||||||
|
*/
|
||||||
|
|
||||||
|
$ezsql_mysql_str = array
|
||||||
|
(
|
||||||
|
1 => 'Require $dbuser and $dbpassword to connect to a database server',
|
||||||
|
2 => 'Error establishing mySQL database connection. Correct user/password? Correct hostname? Database server running?',
|
||||||
|
3 => 'Require $dbname to select a database',
|
||||||
|
4 => 'mySQL database connection is not active',
|
||||||
|
5 => 'Unexpected error while trying to select database'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* ezSQL Database specific class - mySQL
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! function_exists ('mysql_connect') ) die('<b>Fatal Error:</b> ezSQL_mysql requires mySQL Lib to be compiled and or linked in to the PHP engine');
|
||||||
|
if ( ! class_exists ('ezSQLcore') ) die('<b>Fatal Error:</b> ezSQL_mysql requires ezSQLcore (ez_sql_core.php) to be included/loaded before it can be used');
|
||||||
|
|
||||||
|
class ezSQL_mysql extends ezSQLcore
|
||||||
|
{
|
||||||
|
|
||||||
|
var $dbuser = false;
|
||||||
|
var $dbpassword = false;
|
||||||
|
var $dbname = false;
|
||||||
|
var $dbhost = false;
|
||||||
|
var $encoding = false;
|
||||||
|
var $rows_affected = false;
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Constructor - allow the user to perform a qucik connect at the
|
||||||
|
* same time as initialising the ezSQL_mysql class
|
||||||
|
*/
|
||||||
|
|
||||||
|
function ezSQL_mysql($dbuser='', $dbpassword='', $dbname='', $dbhost='localhost', $encoding='')
|
||||||
|
{
|
||||||
|
$this->dbuser = $dbuser;
|
||||||
|
$this->dbpassword = $dbpassword;
|
||||||
|
$this->dbname = $dbname;
|
||||||
|
$this->dbhost = $dbhost;
|
||||||
|
$this->encoding = $encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Short hand way to connect to mySQL database server
|
||||||
|
* and select a mySQL database at the same time
|
||||||
|
*/
|
||||||
|
|
||||||
|
function quick_connect($dbuser='', $dbpassword='', $dbname='', $dbhost='localhost', $encoding='')
|
||||||
|
{
|
||||||
|
$return_val = false;
|
||||||
|
if ( ! $this->connect($dbuser, $dbpassword, $dbhost,true) ) ;
|
||||||
|
else if ( ! $this->select($dbname,$encoding) ) ;
|
||||||
|
else $return_val = true;
|
||||||
|
return $return_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Try to connect to mySQL database server
|
||||||
|
*/
|
||||||
|
|
||||||
|
function connect($dbuser='', $dbpassword='', $dbhost='localhost')
|
||||||
|
{
|
||||||
|
global $ezsql_mysql_str; $return_val = false;
|
||||||
|
|
||||||
|
// Keep track of how long the DB takes to connect
|
||||||
|
$this->timer_start('db_connect_time');
|
||||||
|
|
||||||
|
// Must have a user and a password
|
||||||
|
if ( ! $dbuser )
|
||||||
|
{
|
||||||
|
$this->register_error($ezsql_mysql_str[1].' in '.__FILE__.' on line '.__LINE__);
|
||||||
|
$this->show_errors ? trigger_error($ezsql_mysql_str[1],E_USER_WARNING) : null;
|
||||||
|
}
|
||||||
|
// Try to establish the server database handle
|
||||||
|
else if ( ! $this->dbh = @mysql_connect($dbhost,$dbuser,$dbpassword,true,131074) )
|
||||||
|
{
|
||||||
|
$this->register_error($ezsql_mysql_str[2].' in '.__FILE__.' on line '.__LINE__);
|
||||||
|
$this->show_errors ? trigger_error($ezsql_mysql_str[2],E_USER_WARNING) : null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->dbuser = $dbuser;
|
||||||
|
$this->dbpassword = $dbpassword;
|
||||||
|
$this->dbhost = $dbhost;
|
||||||
|
$return_val = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Try to select a mySQL database
|
||||||
|
*/
|
||||||
|
|
||||||
|
function select($dbname='', $encoding='')
|
||||||
|
{
|
||||||
|
global $ezsql_mysql_str; $return_val = false;
|
||||||
|
|
||||||
|
// Must have a database name
|
||||||
|
if ( ! $dbname )
|
||||||
|
{
|
||||||
|
$this->register_error($ezsql_mysql_str[3].' in '.__FILE__.' on line '.__LINE__);
|
||||||
|
$this->show_errors ? trigger_error($ezsql_mysql_str[3],E_USER_WARNING) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must have an active database connection
|
||||||
|
else if ( ! $this->dbh )
|
||||||
|
{
|
||||||
|
$this->register_error($ezsql_mysql_str[4].' in '.__FILE__.' on line '.__LINE__);
|
||||||
|
$this->show_errors ? trigger_error($ezsql_mysql_str[4],E_USER_WARNING) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to connect to the database
|
||||||
|
else if ( !@mysql_select_db($dbname,$this->dbh) )
|
||||||
|
{
|
||||||
|
// Try to get error supplied by mysql if not use our own
|
||||||
|
if ( !$str = @mysql_error($this->dbh))
|
||||||
|
$str = $ezsql_mysql_str[5];
|
||||||
|
|
||||||
|
$this->register_error($str.' in '.__FILE__.' on line '.__LINE__);
|
||||||
|
$this->show_errors ? trigger_error($str,E_USER_WARNING) : null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->dbname = $dbname;
|
||||||
|
if($encoding!='')
|
||||||
|
{
|
||||||
|
$encoding = strtolower(str_replace("-","",$encoding));
|
||||||
|
$charsets = array();
|
||||||
|
$result = mysql_query("SHOW CHARACTER SET");
|
||||||
|
while($row = mysql_fetch_array($result,MYSQL_ASSOC))
|
||||||
|
{
|
||||||
|
$charsets[] = $row["Charset"];
|
||||||
|
}
|
||||||
|
if(in_array($encoding,$charsets)){
|
||||||
|
mysql_query("SET NAMES '".$encoding."'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$return_val = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Format a mySQL string correctly for safe mySQL insert
|
||||||
|
* (no mater if magic quotes are on or not)
|
||||||
|
*/
|
||||||
|
|
||||||
|
function escape($str)
|
||||||
|
{
|
||||||
|
// If there is no existing database connection then try to connect
|
||||||
|
if ( ! isset($this->dbh) || ! $this->dbh )
|
||||||
|
{
|
||||||
|
$this->connect($this->dbuser, $this->dbpassword, $this->dbhost);
|
||||||
|
$this->select($this->dbname, $this->encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mysql_real_escape_string(stripslashes($str));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Return mySQL specific system date syntax
|
||||||
|
* i.e. Oracle: SYSDATE Mysql: NOW()
|
||||||
|
*/
|
||||||
|
|
||||||
|
function sysdate()
|
||||||
|
{
|
||||||
|
return 'NOW()';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Perform mySQL query and try to detirmin result value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function query($query)
|
||||||
|
{
|
||||||
|
|
||||||
|
// This keeps the connection alive for very long running scripts
|
||||||
|
if ( $this->num_queries >= 500 )
|
||||||
|
{
|
||||||
|
$this->num_queries = 0;
|
||||||
|
$this->disconnect();
|
||||||
|
$this->quick_connect($this->dbuser,$this->dbpassword,$this->dbname,$this->dbhost,$this->encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise return
|
||||||
|
$return_val = 0;
|
||||||
|
|
||||||
|
// Flush cached values..
|
||||||
|
$this->flush();
|
||||||
|
|
||||||
|
// For reg expressions
|
||||||
|
$query = trim($query);
|
||||||
|
|
||||||
|
// Log how the function was called
|
||||||
|
$this->func_call = "\$db->query(\"$query\")";
|
||||||
|
|
||||||
|
// Keep track of the last query for debug..
|
||||||
|
$this->last_query = $query;
|
||||||
|
|
||||||
|
// Count how many queries there have been
|
||||||
|
$this->num_queries++;
|
||||||
|
|
||||||
|
// Start timer
|
||||||
|
$this->timer_start($this->num_queries);
|
||||||
|
|
||||||
|
// Use core file cache function
|
||||||
|
if ( $cache = $this->get_cache($query) )
|
||||||
|
{
|
||||||
|
// Keep tack of how long all queries have taken
|
||||||
|
$this->timer_update_global($this->num_queries);
|
||||||
|
|
||||||
|
// Trace all queries
|
||||||
|
if ( $this->use_trace_log )
|
||||||
|
{
|
||||||
|
$this->trace_log[] = $this->debug(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no existing database connection then try to connect
|
||||||
|
if ( ! isset($this->dbh) || ! $this->dbh )
|
||||||
|
{
|
||||||
|
$this->connect($this->dbuser, $this->dbpassword, $this->dbhost);
|
||||||
|
$this->select($this->dbname,$this->encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the query via std mysql_query function..
|
||||||
|
$this->result = @mysql_query($query,$this->dbh);
|
||||||
|
|
||||||
|
// If there is an error then take note of it..
|
||||||
|
if ( $str = @mysql_error($this->dbh) )
|
||||||
|
{
|
||||||
|
$is_insert = true;
|
||||||
|
$this->register_error($str);
|
||||||
|
$this->show_errors ? trigger_error($str,E_USER_WARNING) : null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query was an insert, delete, update, replace
|
||||||
|
$is_insert = false;
|
||||||
|
if ( preg_match("/^(insert|delete|update|replace|truncate|drop|create|alter|set)\s+/i",$query) )
|
||||||
|
{
|
||||||
|
$this->rows_affected = @mysql_affected_rows($this->dbh);
|
||||||
|
|
||||||
|
// Take note of the insert_id
|
||||||
|
if ( preg_match("/^(insert|replace)\s+/i",$query) )
|
||||||
|
{
|
||||||
|
$this->insert_id = @mysql_insert_id($this->dbh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number fo rows affected
|
||||||
|
$return_val = $this->rows_affected;
|
||||||
|
}
|
||||||
|
// Query was a select
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// Take note of column info
|
||||||
|
$i=0;
|
||||||
|
while ($i < @mysql_num_fields($this->result))
|
||||||
|
{
|
||||||
|
$this->col_info[$i] = @mysql_fetch_field($this->result);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store Query Results
|
||||||
|
$num_rows=0;
|
||||||
|
while ( $row = @mysql_fetch_object($this->result) )
|
||||||
|
{
|
||||||
|
// Store relults as an objects within main array
|
||||||
|
$this->last_result[$num_rows] = $row;
|
||||||
|
$num_rows++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mysql_free_result($this->result);
|
||||||
|
|
||||||
|
// Log number of rows the query returned
|
||||||
|
$this->num_rows = $num_rows;
|
||||||
|
|
||||||
|
// Return number of rows selected
|
||||||
|
$return_val = $this->num_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disk caching of queries
|
||||||
|
$this->store_cache($query,$is_insert);
|
||||||
|
|
||||||
|
// If debug ALL queries
|
||||||
|
$this->trace || $this->debug_all ? $this->debug() : null ;
|
||||||
|
|
||||||
|
// Keep tack of how long all queries have taken
|
||||||
|
$this->timer_update_global($this->num_queries);
|
||||||
|
|
||||||
|
// Trace all queries
|
||||||
|
if ( $this->use_trace_log )
|
||||||
|
{
|
||||||
|
$this->trace_log[] = $this->debug(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return_val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Close the active mySQL connection
|
||||||
|
*/
|
||||||
|
|
||||||
|
function disconnect()
|
||||||
|
{
|
||||||
|
@mysql_close($this->dbh);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
source/includes/ezSQL/ez_sql_mysql_yourls.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class ezSQL_mysql_YOURLS extends ezSQL_mysql {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return MySQL server version
|
||||||
|
*
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
function mysql_version() {
|
||||||
|
return mysql_get_server_info( $this->dbh ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform mySQL query
|
||||||
|
*
|
||||||
|
* Added to the original function: logging of all queries
|
||||||
|
*
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
function query( $query ) {
|
||||||
|
|
||||||
|
// Keep history of all queries
|
||||||
|
$this->debug_log[] = $query;
|
||||||
|
|
||||||
|
// Original function
|
||||||
|
return parent::query( $query );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|