Version 3.4.6
This commit is contained in:
1 parent
e4478369d8
commit
b45ea0dffb
1568 files changed
+155104
-161665
No files matched your search
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,102 +1,101 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Validates a host according to the IPv4, IPv6 and DNS (future) specifications.
|
||||
*/
|
||||
class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
|
||||
{
|
||||
|
||||
/**
|
||||
* Instance of HTMLPurifier_AttrDef_URI_IPv4 sub-validator
|
||||
*/
|
||||
protected $ipv4;
|
||||
|
||||
/**
|
||||
* Instance of HTMLPurifier_AttrDef_URI_IPv6 sub-validator
|
||||
*/
|
||||
protected $ipv6;
|
||||
|
||||
public function __construct() {
|
||||
$this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4();
|
||||
$this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6();
|
||||
}
|
||||
|
||||
public function validate($string, $config, $context) {
|
||||
$length = strlen($string);
|
||||
// empty hostname is OK; it's usually semantically equivalent:
|
||||
// the default host as defined by a URI scheme is used:
|
||||
//
|
||||
// If the URI scheme defines a default for host, then that
|
||||
// default applies when the host subcomponent is undefined
|
||||
// or when the registered name is empty (zero length).
|
||||
if ($string === '') return '';
|
||||
if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') {
|
||||
//IPv6
|
||||
$ip = substr($string, 1, $length - 2);
|
||||
$valid = $this->ipv6->validate($ip, $config, $context);
|
||||
if ($valid === false) return false;
|
||||
return '['. $valid . ']';
|
||||
}
|
||||
|
||||
// need to do checks on unusual encodings too
|
||||
$ipv4 = $this->ipv4->validate($string, $config, $context);
|
||||
if ($ipv4 !== false) return $ipv4;
|
||||
|
||||
// A regular domain name.
|
||||
|
||||
// This doesn't match I18N domain names, but we don't have proper IRI support,
|
||||
// so force users to insert Punycode.
|
||||
|
||||
// The productions describing this are:
|
||||
$a = '[a-z]'; // alpha
|
||||
$an = '[a-z0-9]'; // alphanum
|
||||
$and = '[a-z0-9-]'; // alphanum | "-"
|
||||
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
|
||||
$domainlabel = "$an($and*$an)?";
|
||||
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum
|
||||
$toplabel = "$a($and*$an)?";
|
||||
// hostname = *( domainlabel "." ) toplabel [ "." ]
|
||||
$uni=(IPS_DOC_CHAR_SET=="UTF-8")?"u":"";
|
||||
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i".$uni, $string)) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
// If we have Net_IDNA2 support, we can support IRIs by
|
||||
// punycoding them. (This is the most portable thing to do,
|
||||
// since otherwise we have to assume browsers support
|
||||
|
||||
if ($config->get('Core.EnableIDNA')) {
|
||||
$idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true));
|
||||
// we need to encode each period separately
|
||||
$parts = explode('.', $string);
|
||||
try {
|
||||
$new_parts = array();
|
||||
foreach ($parts as $part) {
|
||||
$encodable = false;
|
||||
for ($i = 0, $c = strlen($part); $i < $c; $i++) {
|
||||
if (ord($part[$i]) > 0x7a) {
|
||||
$encodable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$encodable) {
|
||||
$new_parts[] = $part;
|
||||
} else {
|
||||
$new_parts[] = $idna->encode($part);
|
||||
}
|
||||
}
|
||||
$string = implode('.', $new_parts);
|
||||
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
|
||||
return $string;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// XXX error reporting
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// vim: et sw=4 sts=4
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Validates a host according to the IPv4, IPv6 and DNS (future) specifications.
|
||||
*/
|
||||
class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
|
||||
{
|
||||
|
||||
/**
|
||||
* Instance of HTMLPurifier_AttrDef_URI_IPv4 sub-validator
|
||||
*/
|
||||
protected $ipv4;
|
||||
|
||||
/**
|
||||
* Instance of HTMLPurifier_AttrDef_URI_IPv6 sub-validator
|
||||
*/
|
||||
protected $ipv6;
|
||||
|
||||
public function __construct() {
|
||||
$this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4();
|
||||
$this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6();
|
||||
}
|
||||
|
||||
public function validate($string, $config, $context) {
|
||||
$length = strlen($string);
|
||||
// empty hostname is OK; it's usually semantically equivalent:
|
||||
// the default host as defined by a URI scheme is used:
|
||||
//
|
||||
// If the URI scheme defines a default for host, then that
|
||||
// default applies when the host subcomponent is undefined
|
||||
// or when the registered name is empty (zero length).
|
||||
if ($string === '') return '';
|
||||
if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') {
|
||||
//IPv6
|
||||
$ip = substr($string, 1, $length - 2);
|
||||
$valid = $this->ipv6->validate($ip, $config, $context);
|
||||
if ($valid === false) return false;
|
||||
return '['. $valid . ']';
|
||||
}
|
||||
|
||||
// need to do checks on unusual encodings too
|
||||
$ipv4 = $this->ipv4->validate($string, $config, $context);
|
||||
if ($ipv4 !== false) return $ipv4;
|
||||
|
||||
// A regular domain name.
|
||||
|
||||
// This doesn't match I18N domain names, but we don't have proper IRI support,
|
||||
// so force users to insert Punycode.
|
||||
|
||||
// The productions describing this are:
|
||||
$a = '[a-z]'; // alpha
|
||||
$an = '[a-z0-9]'; // alphanum
|
||||
$and = '[a-z0-9-]'; // alphanum | "-"
|
||||
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
|
||||
$domainlabel = "$an($and*$an)?";
|
||||
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum
|
||||
$toplabel = "$a($and*$an)?";
|
||||
// hostname = *( domainlabel "." ) toplabel [ "." ]
|
||||
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
// If we have Net_IDNA2 support, we can support IRIs by
|
||||
// punycoding them. (This is the most portable thing to do,
|
||||
// since otherwise we have to assume browsers support
|
||||
|
||||
if ($config->get('Core.EnableIDNA')) {
|
||||
$idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true));
|
||||
// we need to encode each period separately
|
||||
$parts = explode('.', $string);
|
||||
try {
|
||||
$new_parts = array();
|
||||
foreach ($parts as $part) {
|
||||
$encodable = false;
|
||||
for ($i = 0, $c = strlen($part); $i < $c; $i++) {
|
||||
if (ord($part[$i]) > 0x7a) {
|
||||
$encodable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$encodable) {
|
||||
$new_parts[] = $part;
|
||||
} else {
|
||||
$new_parts[] = $idna->encode($part);
|
||||
}
|
||||
}
|
||||
$string = implode('.', $new_parts);
|
||||
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
|
||||
return $string;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// XXX error reporting
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// vim: et sw=4 sts=4
|
||||
@@ -333,7 +333,7 @@ class HTMLPurifier_Encoder
|
||||
/**
|
||||
* Converts a string to UTF-8 based on configuration.
|
||||
*/
|
||||
public static function convertToUTF8($str, $config, $context) {
|
||||
public static function convertToUTF8($str, $config, $context) {
|
||||
$encoding = $config->get('Core.Encoding');
|
||||
if ($encoding === 'utf-8') return $str;
|
||||
static $iconv = null;
|
||||
@@ -355,6 +355,10 @@ class HTMLPurifier_Encoder
|
||||
$str = utf8_encode($str);
|
||||
return $str;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IPSText::convertCharsets( $str, $encoding );
|
||||
}
|
||||
trigger_error('Encoding not supported, please install iconv', E_USER_ERROR);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,99 +1,122 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Injector that converts http, https and ftp text URLs to actual links.
|
||||
*/
|
||||
class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector
|
||||
{
|
||||
|
||||
public $name = 'Linkify';
|
||||
public $needed = array('a' => array('href'));
|
||||
|
||||
public function handleText(&$token) {
|
||||
if (!$this->allowsElement('a')) return;
|
||||
|
||||
if (strpos($token->data, '://') === false) {
|
||||
// our really quick heuristic failed, abort
|
||||
// this may not work so well if we want to match things like
|
||||
// "google.com", but then again, most people don't
|
||||
return;
|
||||
}
|
||||
//print $token->data;
|
||||
// there is/are URL(s). Let's split the string:
|
||||
// Note: this regex is extremely permissive
|
||||
//$bits = preg_split('#((?:https?|ftp)://[^\s\'"<>()]+)#S', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
/* MODIFIED April 26, 2013
|
||||
@link http://community.invisionpower.com/resources/bugs.html/_/ip-board/links-being-corrupted-or-malformed-in-board-and-nexus-r41993
|
||||
Test case:
|
||||
http://invisionpower.com,
|
||||
http://invisionpower.com.
|
||||
http://invisionpower.com
|
||||
https://invisionpower.com
|
||||
https://blah.gov/blah-blah.as
|
||||
http://en.wikipedia.org/wiki/Chi_(mythology)
|
||||
(http://google.com)
|
||||
*/
|
||||
$uni=(IPS_DOC_CHAR_SET=="UTF-8")?"u":"";
|
||||
preg_match_all( "#(.*?)(\()?((?:http|ftp|https):\/\/[\p{L}\-_]+(?:\.[\p{L}\-_]+)?(?:[\p{L}\-\.,\(\)@?^=%&:\/~\+\#]*[\p{L}\-\@?^=%&\/~\+\#]))(.*?)$#ims" . $uni, $token->data, $matches );
|
||||
//print_r($matches);exit;
|
||||
|
||||
//$token = array();
|
||||
|
||||
// $i = index
|
||||
// $c = count
|
||||
// $l = is link
|
||||
/*for ($i = 0, $c = count($bits), $l = false; $i < $c; $i++, $l = !$l) {
|
||||
if (!$l) {
|
||||
if ($bits[$i] === '') continue;
|
||||
$token[] = new HTMLPurifier_Token_Text($bits[$i]);
|
||||
} else {
|
||||
$token[] = new HTMLPurifier_Token_Start('a', array('href' => $bits[$i]));
|
||||
$token[] = new HTMLPurifier_Token_Text($bits[$i]);
|
||||
$token[] = new HTMLPurifier_Token_End('a');
|
||||
}
|
||||
}*/
|
||||
|
||||
if( is_array($matches) AND count($matches) )
|
||||
{
|
||||
$token = array();//by denchu 06062013
|
||||
foreach( $matches[0] as $k => $match )
|
||||
{
|
||||
if( !$matches[3][$k] )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text($token->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( $matches[1][$k] )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text($matches[1][$k]);
|
||||
}
|
||||
|
||||
if( $matches[2][$k] )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text($matches[2][$k]);
|
||||
}
|
||||
|
||||
if( !$matches[2][$k] AND $matches[4][$k] == ')' )
|
||||
{
|
||||
$matches[3][$k] .= ')';
|
||||
unset($matches[4][$k]);
|
||||
}
|
||||
|
||||
$token[] = new HTMLPurifier_Token_Start('a', array('href' => $matches[3][$k]));
|
||||
$token[] = new HTMLPurifier_Token_Text($matches[3][$k]);
|
||||
$token[] = new HTMLPurifier_Token_End('a');
|
||||
|
||||
if( $matches[4][$k] )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text($matches[4][$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//print_r($token);exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// vim: et sw=4 sts=4
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Injector that converts http, https and ftp text URLs to actual links.
|
||||
*/
|
||||
class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector
|
||||
{
|
||||
|
||||
public $name = 'Linkify';
|
||||
public $needed = array('a' => array('href'));
|
||||
|
||||
public function handleText(&$token) {
|
||||
if (!$this->allowsElement('a')) return;
|
||||
|
||||
//var_dump( $token->data ); exit;
|
||||
|
||||
if (strpos($token->data, '://') === false) {
|
||||
// our really quick heuristic failed, abort
|
||||
// this may not work so well if we want to match things like
|
||||
// "google.com", but then again, most people don't
|
||||
return;
|
||||
}
|
||||
//print $token->data;
|
||||
// there is/are URL(s). Let's split the string:
|
||||
// Note: this regex is extremely permissive
|
||||
//$bits = preg_split('#((?:https?|ftp)://[^\s\'"<>()]+)#S', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
/* MODIFIED April 26, 2013
|
||||
@link http://community.invisionpower.com/resources/bugs.html/_/ip-board/links-being-corrupted-or-malformed-in-board-and-nexus-r41993
|
||||
Test case:
|
||||
http://invisionpower.com,
|
||||
http://invisionpower.com.
|
||||
http://invisionpower.com
|
||||
https://invisionpower.com
|
||||
https://blah.gov/blah-blah.as
|
||||
http://en.wikipedia.org/wiki/Chi_(mythology)
|
||||
http://en.wikipedia.org/wiki/Assassin's_Creed
|
||||
(http://google.com)
|
||||
*/
|
||||
|
||||
preg_match_all( "#(.*?)(\()?((?:http|ftp|https):\/\/[\w\-_]+(?:\.[\w\-_]+)?(?:[\w\-\.,\'\(\)@?^=%&:/~\+\#]*[\w\-\@?^=%&/~\+\#]))(.*)(?(?=\S+)\S+)(.*)$#ims", $token->data, $matches );
|
||||
|
||||
//$token = array();
|
||||
|
||||
// $i = index
|
||||
// $c = count
|
||||
// $l = is link
|
||||
/*for ($i = 0, $c = count($bits), $l = false; $i < $c; $i++, $l = !$l) {
|
||||
if (!$l) {
|
||||
if ($bits[$i] === '') continue;
|
||||
$token[] = new HTMLPurifier_Token_Text($bits[$i]);
|
||||
} else {
|
||||
$token[] = new HTMLPurifier_Token_Start('a', array('href' => $bits[$i]));
|
||||
$token[] = new HTMLPurifier_Token_Text($bits[$i]);
|
||||
$token[] = new HTMLPurifier_Token_End('a');
|
||||
}
|
||||
}*/
|
||||
if( is_array($matches[0]) AND count($matches[0]) )
|
||||
{
|
||||
$token = array();
|
||||
|
||||
foreach( $matches[0] as $k => $match )
|
||||
{
|
||||
if( !$matches[3][$k] )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text($token->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( $matches[1][$k] )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text($matches[1][$k]);
|
||||
}
|
||||
|
||||
if( $matches[2][$k] )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text($matches[2][$k]);
|
||||
}
|
||||
|
||||
if( !$matches[2][$k] AND !in_array( $matches[4][$k], array( '!', '.', ',' ) ) AND strpos( $matches[4][$k], ' ' ) === false AND ! preg_match( "#(\r|\n|\r\n)#i", $matches[4][$k] ) )
|
||||
{
|
||||
$matches[3][$k] .= $matches[4][$k];
|
||||
unset($matches[4][$k]);
|
||||
}
|
||||
|
||||
$token[] = new HTMLPurifier_Token_Start('a', array('href' => str_replace( '\'', '%27', $matches[3][$k] )));
|
||||
$token[] = new HTMLPurifier_Token_Text($matches[3][$k]);
|
||||
$token[] = new HTMLPurifier_Token_End('a');
|
||||
|
||||
if( $matches[4][$k] )
|
||||
{
|
||||
// Let's do some testing. We may need to recurse in on this line for extra links.
|
||||
$test = explode( ' ', $matches[4][$k] );
|
||||
foreach( $test AS $v )
|
||||
{
|
||||
if ( strpos( $v, 'http' ) !== false OR strpos( $v, 'https' ) !== false OR strpos( $v, 'ftp' ) !== false )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Start('a', array('href' => str_replace( '\'', '%27', $v )));
|
||||
$token[] = new HTMLPurifier_Token_Text($v);
|
||||
$token[] = new HTMLPurifier_Token_End('a');
|
||||
$token[] = new HTMLPurifier_Token_Text(' '); // Because we exploded the text, spaces were lost. Re-add them.
|
||||
}
|
||||
else
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text($v);
|
||||
$token[] = new HTMLPurifier_Token_Text(' '); // Because we exploded the text, spaces were lost. Re-add them.
|
||||
}
|
||||
}
|
||||
//$token[] = new HTMLPurifier_Token_Text($matches[4][$k]);
|
||||
}
|
||||
|
||||
if( $matches[5][$k] )
|
||||
{
|
||||
$token[] = new HTMLPurifier_Token_Text( $matches[5][$k] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// vim: et sw=4 sts=4
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
+426
-426
@@ -1,427 +1,427 @@
|
||||
<?php
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* AJAX input parsing and handling
|
||||
* Last Updated: $Date: 2012-08-28 17:56:22 -0400 (Tue, 28 Aug 2012) $
|
||||
* </pre>
|
||||
*
|
||||
* @author $Author: bfarber $
|
||||
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/company/standards.php#license
|
||||
* @package IP.Board
|
||||
* @subpackage Kernel
|
||||
* @link http://www.invisionpower.com
|
||||
* @since Friday 19th May 2006 17:33
|
||||
* @version $Revision: 11296 $
|
||||
*/
|
||||
|
||||
|
||||
class classAjax
|
||||
{
|
||||
/**
|
||||
* XML output
|
||||
*
|
||||
* @var string Output
|
||||
*/
|
||||
public $xml_output;
|
||||
|
||||
/**
|
||||
* XML Header
|
||||
*
|
||||
* @var string XML doctype
|
||||
*/
|
||||
public $xml_header;
|
||||
|
||||
/**
|
||||
* Character sets
|
||||
*
|
||||
* @var array Charsets supported by html_entity_decode
|
||||
*/
|
||||
protected $decodeCharsets = array('iso-8859-1' => 'ISO-8859-1',
|
||||
'iso8859-1' => 'ISO-8859-1',
|
||||
'iso-8859-15' => 'ISO-8859-15',
|
||||
'iso8859-15' => 'ISO-8859-15',
|
||||
'utf-8' => 'UTF-8',
|
||||
'cp866' => 'cp866',
|
||||
'ibm866' => 'cp866',
|
||||
'cp1251' => 'windows-1251',
|
||||
'windows-1251' => 'windows-1251',
|
||||
'win-1251' => 'windows-1251',
|
||||
'cp1252' => 'windows-1252',
|
||||
'windows-1252' => 'windows-1252',
|
||||
'koi8-r' => 'KOI8-R',
|
||||
'koi8-ru' => 'KOI8-R',
|
||||
'koi8r' => 'KOI8-R',
|
||||
'big5' => 'BIG5',
|
||||
'gb2312' => 'GB2312',
|
||||
'big5-hkscs' => 'BIG5-HKSCS',
|
||||
'shift_jis' => 'Shift_JIS',
|
||||
'sjis' => 'Shift_JIS',
|
||||
'euc-jp' => 'EUC-JP',
|
||||
'eucjp' => 'EUC-JP' );
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return @e void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ( ! defined( 'IPS_DOC_CHAR_SET' ) )
|
||||
{
|
||||
define( 'IPS_DOC_CHAR_SET', 'UTF-8' );
|
||||
}
|
||||
|
||||
$this->xml_header = "<?xml version=\"1.0\" encoding=\"" . IPS_DOC_CHAR_SET . "\"?".'>';
|
||||
|
||||
/* Convert incoming $_POST fields */
|
||||
array_walk_recursive( $_POST, array( $this, 'arrayWalkConvert' ) );
|
||||
|
||||
//-----------------------------------------
|
||||
// Using this code allows characters that ARE supported
|
||||
// within the character set to be recoded properly, instead
|
||||
// of as HTML entities when submitted via AJAX. The problem is,
|
||||
// any characters NOT supported in the charset are corrupted. :-\
|
||||
//-----------------------------------------
|
||||
//array_walk_recursive( $_POST, create_function( '&$value, $key', '$value = IPSText::convertCharsets( IPSText::convertUnicode($value, true), "utf-8", "' . IPS_DOC_CHAR_SET . '" );' ) );
|
||||
|
||||
// We use $_REQUEST in a lot of places, so we might need to do this, but based on the below comments I'll leave this
|
||||
// commented out for now...
|
||||
//array_walk_recursive( $_REQUEST, create_function( '&$value, $key', '$value = IPSText::convertUnicode($value);' ) );
|
||||
|
||||
/* Risky converting $_GET because it calls rawurldecode which could allow crafty users to hide html entities */
|
||||
//array_walk_recursive( $_GET , create_function( '&$value, $key', '$value = IPSText::convertUnicode($value);' ) );
|
||||
//array_walk_recursive( ipsRegistry::$request, create_function( '&$value, $key', '$value = IPSText::convertUnicode($value);' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to convert unicode and charset for AJAX requests
|
||||
*
|
||||
* @param mixed Value
|
||||
* @param string Key
|
||||
* @return @e void
|
||||
*/
|
||||
public function arrayWalkConvert( &$value, $key )
|
||||
{
|
||||
if( is_string( $value ) )
|
||||
{
|
||||
$value = IPSText::convertCharsets( IPSText::convertUnicode( $value ), "utf-8", IPS_DOC_CHAR_SET );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the character set of incoming AJAX data and optionally parse the value through the parseCleanValue routine
|
||||
*
|
||||
* @param string Raw input string
|
||||
* @param boolean Run through parse_incoming routine
|
||||
* @see IPSText::parseCleanValue
|
||||
* @return @e string
|
||||
*/
|
||||
public function convertAndMakeSafe( $value, $parse_incoming=true )
|
||||
{
|
||||
$value = rawurldecode( $value );
|
||||
|
||||
//-----------------------------------------
|
||||
// \ char is passed as %5C so it won't be double
|
||||
// escaped if magic quotes is on - do it manually
|
||||
// @link http://community.invisionpower.com/tracker/issue-24971-status-update-issue/
|
||||
//-----------------------------------------
|
||||
|
||||
if( IPS_MAGIC_QUOTES )
|
||||
{
|
||||
$value = str_replace( "\\", "\\\\", $value );
|
||||
}
|
||||
|
||||
$value = $this->convertUnicode( $value );
|
||||
$value = $this->convertHtmlEntities( $value );
|
||||
|
||||
if( $parse_incoming )
|
||||
{
|
||||
$value = IPSText::parseCleanValue( $value );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove hook comments and parse replacements
|
||||
*
|
||||
* @param string Output data
|
||||
* @return @e string
|
||||
*/
|
||||
public function cleanOutput( $string )
|
||||
{
|
||||
if ( ! IN_ACP )
|
||||
{
|
||||
$string = preg_replace( '#<!--hook\.([^\>]+?)-->#', '', $string );
|
||||
}
|
||||
|
||||
$string = ipsRegistry::getClass('output')->replaceMacros( $string );
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print a generic error message
|
||||
*
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnGenericError()
|
||||
{
|
||||
@header( "Content-type: text/xml" );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
$this->xml_output = $this->xml_header . "\r\n<errors>\r\n";
|
||||
$this->xml_output .= "<error><message>Вы должны быть залогинены для доступа к этой функции</message></error>\r\n";
|
||||
$this->xml_output .= "</errors>";
|
||||
|
||||
print $this->xml_output;
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a NULL XML result
|
||||
*
|
||||
* @param mixed Value to send
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnNull( $val=0 )
|
||||
{
|
||||
@header( "Content-type: text/xml" );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
$val = $this->parseAndCleanHooks( $val );
|
||||
|
||||
print $this->xml_header . "\r\n<null>{$val}</null>";
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string
|
||||
*
|
||||
* @param string String to output
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnString( $string )
|
||||
{
|
||||
@header( "Content-type: text/plain;charset=" . IPS_DOC_CHAR_SET );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
echo $this->parseAndCleanHooks( $string );
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON error message
|
||||
*
|
||||
* @param string Error message
|
||||
* @param string Content-type header to send
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnJsonError( $message, $header="application/json" )
|
||||
{
|
||||
/* Just alias it... */
|
||||
$this->returnJsonArray( array( 'error' => $message ), false, $header );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON object
|
||||
*
|
||||
* @param array Array of key => value fields
|
||||
* @param boolean Clean the data (used when passing HTML)
|
||||
* @param string Optional content-type header string (default application/json)
|
||||
* @param array Optional array (0 => template group, 1 => bit name) to pass JSON into a custom skin method
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnJsonArray( $json=array(), $cleanData=false, $header="application/json", $templateWrapper=array() )
|
||||
{
|
||||
@header( "Content-type: " . $header . ";charset=" . IPS_DOC_CHAR_SET );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
/* Always return as UTF-8 */
|
||||
array_walk_recursive( $json, array( 'IPSText', 'arrayWalkCallbackConvert' ) );
|
||||
|
||||
if ( $cleanData )
|
||||
{
|
||||
array_walk_recursive( $json, array( $this, 'cleanHtml' ) );
|
||||
}
|
||||
|
||||
$result = json_encode( $json );
|
||||
$result = IPSText::convertCharsets($result, "UTF-8", IPS_DOC_CHAR_SET);
|
||||
|
||||
/* Print via a wrapper? */
|
||||
if ( is_array( $templateWrapper ) AND count( $templateWrapper ) )
|
||||
{
|
||||
print ipsRegistry::getClass('output')->getTemplate( $templateWrapper[0] )->$templateWrapper[1]( $result );
|
||||
}
|
||||
else
|
||||
{
|
||||
print $result;
|
||||
}
|
||||
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML content
|
||||
*
|
||||
* @param string HTML to output
|
||||
* @param boolean Force returned output to UTF-8
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnHtml( $string, $returnAsUtf8=false )
|
||||
{
|
||||
if ( $string )
|
||||
{
|
||||
$this->cleanHtml( $string );
|
||||
}
|
||||
|
||||
/* Always return as UTF-8 */
|
||||
if ( $returnAsUtf8 )
|
||||
{
|
||||
$string = IPSText::convertCharsets( $string, IPS_DOC_CHAR_SET, "UTF-8" );
|
||||
}
|
||||
|
||||
@header( "Content-type: text/html;charset=" . IPS_DOC_CHAR_SET );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
print $string;
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute template hooks and remove hook comments
|
||||
*
|
||||
* @param string $string
|
||||
* @return @e string
|
||||
*/
|
||||
public function parseAndCleanHooks( $string )
|
||||
{
|
||||
$string = ipsRegistry::getClass('output')->templateHooks( $string );
|
||||
$string = preg_replace( '#<!--hook\.([^\>]+?)-->#', '', $string );
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print 200 OK and nocache headers
|
||||
*
|
||||
* @return @e void
|
||||
*/
|
||||
public function printNocacheHeaders()
|
||||
{
|
||||
if ( isset( $_SERVER['SERVER_PROTOCOL'] ) AND strstr( $_SERVER['SERVER_PROTOCOL'], '/1.0' ) )
|
||||
{
|
||||
header( "HTTP/1.0 200 OK" );
|
||||
}
|
||||
else
|
||||
{
|
||||
header( "HTTP/1.1 200 OK" );
|
||||
}
|
||||
|
||||
header( "Cache-Control: no-cache, must-revalidate, max-age=0" );
|
||||
header( "Expires: 0" );
|
||||
header( "Pragma: no-cache" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert AJAX unicode to standard char codes
|
||||
*
|
||||
* @deprecated This function no longer does anything
|
||||
* @param string Input to convert
|
||||
* @return @e string
|
||||
*/
|
||||
public function convertUnicode( $t )
|
||||
{
|
||||
/* This is called at various stages through different ajax files but its no longer required */
|
||||
/* The ajax class cleans up (converts via IPSText::convertUnicode()) the post get and input vars in the constructor now so we don't need to manually use it */
|
||||
|
||||
return $t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML entities into raw characters
|
||||
*
|
||||
* @param string Input to convert
|
||||
* @return @e string
|
||||
*/
|
||||
public function convertHtmlEntities($t)
|
||||
{
|
||||
//-----------------------------------------
|
||||
// Try and fix up HTML entities with missing ;
|
||||
//-----------------------------------------
|
||||
|
||||
$t = preg_replace( '/&#(\d+?)([^\d;])/i', "&#\\1;\\2", $t );
|
||||
|
||||
//-----------------------------------------
|
||||
// Continue...
|
||||
//-----------------------------------------
|
||||
|
||||
if ( strtolower(IPS_DOC_CHAR_SET) != 'iso-8859-1' && strtolower(IPS_DOC_CHAR_SET) != 'utf-8' )
|
||||
{
|
||||
if ( isset($this->decodeCharsets[ strtolower(IPS_DOC_CHAR_SET) ]) )
|
||||
{
|
||||
$IPS_DOC_CHAR_SET = $this->decodeCharsets[strtolower(IPS_DOC_CHAR_SET)];
|
||||
|
||||
$t = html_entity_decode( $t, ENT_NOQUOTES, IPS_DOC_CHAR_SET );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take a crack at entities in other character sets
|
||||
|
||||
$t = str_replace( "&#", "&#", $t );
|
||||
|
||||
// If mb functions available, we can knock out html entities for a few more char sets
|
||||
|
||||
if( function_exists('mb_list_encodings') )
|
||||
{
|
||||
$valid_encodings = array();
|
||||
$valid_encodings = mb_list_encodings();
|
||||
|
||||
if( count($valid_encodings) )
|
||||
{
|
||||
if( in_array( strtoupper(IPS_DOC_CHAR_SET), $valid_encodings ) )
|
||||
{
|
||||
$t = mb_convert_encoding( $t, strtoupper(IPS_DOC_CHAR_SET), 'HTML-ENTITIES' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an HTML string for output. Fixes some browser-specific bugs, parses replacements and executes hooks
|
||||
*
|
||||
* @param string $string
|
||||
* @param string Array key (only necessary when executed from an array_walk callback)
|
||||
* @return @e string
|
||||
*/
|
||||
public function cleanHtml( &$string, $key='' )
|
||||
{
|
||||
/* Is it really a string? */
|
||||
if ( is_string($string) )
|
||||
{
|
||||
// Fix IE bugs
|
||||
$string = str_ireplace( "§", "&sect", $string );
|
||||
|
||||
if ( strtolower( IPS_DOC_CHAR_SET ) == 'iso-8859-1' )
|
||||
{
|
||||
$string = str_replace( "ì", "“", $string );
|
||||
$string = str_replace( "î", "”", $string );
|
||||
}
|
||||
|
||||
// Other stuff
|
||||
$string = ipsRegistry::getClass('output')->replaceMacros( $string );
|
||||
$string = $this->parseAndCleanHooks( $string );
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
<?php
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.6
|
||||
* AJAX input parsing and handling
|
||||
* Last Updated: $Date: 2012-08-28 17:56:22 -0400 (Tue, 28 Aug 2012) $
|
||||
* </pre>
|
||||
*
|
||||
* @author $Author: bfarber $
|
||||
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/company/standards.php#license
|
||||
* @package IP.Board
|
||||
* @subpackage Kernel
|
||||
* @link http://www.invisionpower.com
|
||||
* @since Friday 19th May 2006 17:33
|
||||
* @version $Revision: 11296 $
|
||||
*/
|
||||
|
||||
|
||||
class classAjax
|
||||
{
|
||||
/**
|
||||
* XML output
|
||||
*
|
||||
* @var string Output
|
||||
*/
|
||||
public $xml_output;
|
||||
|
||||
/**
|
||||
* XML Header
|
||||
*
|
||||
* @var string XML doctype
|
||||
*/
|
||||
public $xml_header;
|
||||
|
||||
/**
|
||||
* Character sets
|
||||
*
|
||||
* @var array Charsets supported by html_entity_decode
|
||||
*/
|
||||
protected $decodeCharsets = array('iso-8859-1' => 'ISO-8859-1',
|
||||
'iso8859-1' => 'ISO-8859-1',
|
||||
'iso-8859-15' => 'ISO-8859-15',
|
||||
'iso8859-15' => 'ISO-8859-15',
|
||||
'utf-8' => 'UTF-8',
|
||||
'cp866' => 'cp866',
|
||||
'ibm866' => 'cp866',
|
||||
'cp1251' => 'windows-1251',
|
||||
'windows-1251' => 'windows-1251',
|
||||
'win-1251' => 'windows-1251',
|
||||
'cp1252' => 'windows-1252',
|
||||
'windows-1252' => 'windows-1252',
|
||||
'koi8-r' => 'KOI8-R',
|
||||
'koi8-ru' => 'KOI8-R',
|
||||
'koi8r' => 'KOI8-R',
|
||||
'big5' => 'BIG5',
|
||||
'gb2312' => 'GB2312',
|
||||
'big5-hkscs' => 'BIG5-HKSCS',
|
||||
'shift_jis' => 'Shift_JIS',
|
||||
'sjis' => 'Shift_JIS',
|
||||
'euc-jp' => 'EUC-JP',
|
||||
'eucjp' => 'EUC-JP' );
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return @e void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ( ! defined( 'IPS_DOC_CHAR_SET' ) )
|
||||
{
|
||||
define( 'IPS_DOC_CHAR_SET', 'UTF-8' );
|
||||
}
|
||||
|
||||
$this->xml_header = "<?xml version=\"1.0\" encoding=\"" . IPS_DOC_CHAR_SET . "\"?".'>';
|
||||
|
||||
/* Convert incoming $_POST fields */
|
||||
array_walk_recursive( $_POST, array( $this, 'arrayWalkConvert' ) );
|
||||
|
||||
//-----------------------------------------
|
||||
// Using this code allows characters that ARE supported
|
||||
// within the character set to be recoded properly, instead
|
||||
// of as HTML entities when submitted via AJAX. The problem is,
|
||||
// any characters NOT supported in the charset are corrupted. :-\
|
||||
//-----------------------------------------
|
||||
//array_walk_recursive( $_POST, create_function( '&$value, $key', '$value = IPSText::convertCharsets( IPSText::convertUnicode($value, true), "utf-8", "' . IPS_DOC_CHAR_SET . '" );' ) );
|
||||
|
||||
// We use $_REQUEST in a lot of places, so we might need to do this, but based on the below comments I'll leave this
|
||||
// commented out for now...
|
||||
//array_walk_recursive( $_REQUEST, create_function( '&$value, $key', '$value = IPSText::convertUnicode($value);' ) );
|
||||
|
||||
/* Risky converting $_GET because it calls rawurldecode which could allow crafty users to hide html entities */
|
||||
//array_walk_recursive( $_GET , create_function( '&$value, $key', '$value = IPSText::convertUnicode($value);' ) );
|
||||
//array_walk_recursive( ipsRegistry::$request, create_function( '&$value, $key', '$value = IPSText::convertUnicode($value);' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to convert unicode and charset for AJAX requests
|
||||
*
|
||||
* @param mixed Value
|
||||
* @param string Key
|
||||
* @return @e void
|
||||
*/
|
||||
public function arrayWalkConvert( &$value, $key )
|
||||
{
|
||||
if( is_string( $value ) )
|
||||
{
|
||||
$value = IPSText::convertCharsets( IPSText::convertUnicode( $value ), "utf-8", IPS_DOC_CHAR_SET );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the character set of incoming AJAX data and optionally parse the value through the parseCleanValue routine
|
||||
*
|
||||
* @param string Raw input string
|
||||
* @param boolean Run through parse_incoming routine
|
||||
* @see IPSText::parseCleanValue
|
||||
* @return @e string
|
||||
*/
|
||||
public function convertAndMakeSafe( $value, $parse_incoming=true )
|
||||
{
|
||||
$value = rawurldecode( $value );
|
||||
|
||||
//-----------------------------------------
|
||||
// \ char is passed as %5C so it won't be double
|
||||
// escaped if magic quotes is on - do it manually
|
||||
// @link http://community.invisionpower.com/tracker/issue-24971-status-update-issue/
|
||||
//-----------------------------------------
|
||||
|
||||
if( IPS_MAGIC_QUOTES )
|
||||
{
|
||||
$value = str_replace( "\\", "\\\\", $value );
|
||||
}
|
||||
|
||||
$value = $this->convertUnicode( $value );
|
||||
$value = $this->convertHtmlEntities( $value );
|
||||
|
||||
if( $parse_incoming )
|
||||
{
|
||||
$value = IPSText::parseCleanValue( $value );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove hook comments and parse replacements
|
||||
*
|
||||
* @param string Output data
|
||||
* @return @e string
|
||||
*/
|
||||
public function cleanOutput( $string )
|
||||
{
|
||||
if ( ! IN_ACP )
|
||||
{
|
||||
$string = preg_replace( '#<!--hook\.([^\>]+?)-->#', '', $string );
|
||||
}
|
||||
|
||||
$string = ipsRegistry::getClass('output')->replaceMacros( $string );
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print a generic error message
|
||||
*
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnGenericError()
|
||||
{
|
||||
@header( "Content-type: text/xml" );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
$this->xml_output = $this->xml_header . "\r\n<errors>\r\n";
|
||||
$this->xml_output .= "<error><message>You must be logged in to access this feature</message></error>\r\n";
|
||||
$this->xml_output .= "</errors>";
|
||||
|
||||
print $this->xml_output;
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a NULL XML result
|
||||
*
|
||||
* @param mixed Value to send
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnNull( $val=0 )
|
||||
{
|
||||
@header( "Content-type: text/xml" );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
$val = $this->parseAndCleanHooks( $val );
|
||||
|
||||
print $this->xml_header . "\r\n<null>{$val}</null>";
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string
|
||||
*
|
||||
* @param string String to output
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnString( $string )
|
||||
{
|
||||
@header( "Content-type: text/plain;charset=" . IPS_DOC_CHAR_SET );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
echo $this->parseAndCleanHooks( $string );
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON error message
|
||||
*
|
||||
* @param string Error message
|
||||
* @param string Content-type header to send
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnJsonError( $message, $header="application/json" )
|
||||
{
|
||||
/* Just alias it... */
|
||||
$this->returnJsonArray( array( 'error' => $message ), false, $header );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON object
|
||||
*
|
||||
* @param array Array of key => value fields
|
||||
* @param boolean Clean the data (used when passing HTML)
|
||||
* @param string Optional content-type header string (default application/json)
|
||||
* @param array Optional array (0 => template group, 1 => bit name) to pass JSON into a custom skin method
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnJsonArray( $json=array(), $cleanData=false, $header="application/json", $templateWrapper=array() )
|
||||
{
|
||||
@header( "Content-type: " . $header . ";charset=" . IPS_DOC_CHAR_SET );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
/* Always return as UTF-8 */
|
||||
array_walk_recursive( $json, array( 'IPSText', 'arrayWalkCallbackConvert' ) );
|
||||
|
||||
if ( $cleanData )
|
||||
{
|
||||
array_walk_recursive( $json, array( $this, 'cleanHtml' ) );
|
||||
}
|
||||
|
||||
$result = json_encode( $json );
|
||||
$result = IPSText::convertCharsets($result, "UTF-8", IPS_DOC_CHAR_SET);
|
||||
|
||||
/* Print via a wrapper? */
|
||||
if ( is_array( $templateWrapper ) AND count( $templateWrapper ) )
|
||||
{
|
||||
print ipsRegistry::getClass('output')->getTemplate( $templateWrapper[0] )->$templateWrapper[1]( $result );
|
||||
}
|
||||
else
|
||||
{
|
||||
print $result;
|
||||
}
|
||||
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML content
|
||||
*
|
||||
* @param string HTML to output
|
||||
* @param boolean Force returned output to UTF-8
|
||||
* @return @e void
|
||||
*/
|
||||
public function returnHtml( $string, $returnAsUtf8=false )
|
||||
{
|
||||
if ( $string )
|
||||
{
|
||||
$this->cleanHtml( $string );
|
||||
}
|
||||
|
||||
/* Always return as UTF-8 */
|
||||
if ( $returnAsUtf8 )
|
||||
{
|
||||
$string = IPSText::convertCharsets( $string, IPS_DOC_CHAR_SET, "UTF-8" );
|
||||
}
|
||||
|
||||
@header( "Content-type: text/html;charset=" . IPS_DOC_CHAR_SET );
|
||||
$this->printNocacheHeaders();
|
||||
|
||||
print $string;
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute template hooks and remove hook comments
|
||||
*
|
||||
* @param string $string
|
||||
* @return @e string
|
||||
*/
|
||||
public function parseAndCleanHooks( $string )
|
||||
{
|
||||
$string = ipsRegistry::getClass('output')->templateHooks( $string );
|
||||
$string = preg_replace( '#<!--hook\.([^\>]+?)-->#', '', $string );
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print 200 OK and nocache headers
|
||||
*
|
||||
* @return @e void
|
||||
*/
|
||||
public function printNocacheHeaders()
|
||||
{
|
||||
if ( isset( $_SERVER['SERVER_PROTOCOL'] ) AND strstr( $_SERVER['SERVER_PROTOCOL'], '/1.0' ) )
|
||||
{
|
||||
header( "HTTP/1.0 200 OK" );
|
||||
}
|
||||
else
|
||||
{
|
||||
header( "HTTP/1.1 200 OK" );
|
||||
}
|
||||
|
||||
header( "Cache-Control: no-cache, must-revalidate, max-age=0" );
|
||||
header( "Expires: 0" );
|
||||
header( "Pragma: no-cache" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert AJAX unicode to standard char codes
|
||||
*
|
||||
* @deprecated This function no longer does anything
|
||||
* @param string Input to convert
|
||||
* @return @e string
|
||||
*/
|
||||
public function convertUnicode( $t )
|
||||
{
|
||||
/* This is called at various stages through different ajax files but its no longer required */
|
||||
/* The ajax class cleans up (converts via IPSText::convertUnicode()) the post get and input vars in the constructor now so we don't need to manually use it */
|
||||
|
||||
return $t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML entities into raw characters
|
||||
*
|
||||
* @param string Input to convert
|
||||
* @return @e string
|
||||
*/
|
||||
public function convertHtmlEntities($t)
|
||||
{
|
||||
//-----------------------------------------
|
||||
// Try and fix up HTML entities with missing ;
|
||||
//-----------------------------------------
|
||||
|
||||
$t = preg_replace( '/&#(\d+?)([^\d;])/i', "&#\\1;\\2", $t );
|
||||
|
||||
//-----------------------------------------
|
||||
// Continue...
|
||||
//-----------------------------------------
|
||||
|
||||
if ( strtolower(IPS_DOC_CHAR_SET) != 'iso-8859-1' && strtolower(IPS_DOC_CHAR_SET) != 'utf-8' )
|
||||
{
|
||||
if ( isset($this->decodeCharsets[ strtolower(IPS_DOC_CHAR_SET) ]) )
|
||||
{
|
||||
$IPS_DOC_CHAR_SET = $this->decodeCharsets[strtolower(IPS_DOC_CHAR_SET)];
|
||||
|
||||
$t = html_entity_decode( $t, ENT_NOQUOTES, IPS_DOC_CHAR_SET );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take a crack at entities in other character sets
|
||||
|
||||
$t = str_replace( "&#", "&#", $t );
|
||||
|
||||
// If mb functions available, we can knock out html entities for a few more char sets
|
||||
|
||||
if( function_exists('mb_list_encodings') )
|
||||
{
|
||||
$valid_encodings = array();
|
||||
$valid_encodings = mb_list_encodings();
|
||||
|
||||
if( count($valid_encodings) )
|
||||
{
|
||||
if( in_array( strtoupper(IPS_DOC_CHAR_SET), $valid_encodings ) )
|
||||
{
|
||||
$t = mb_convert_encoding( $t, strtoupper(IPS_DOC_CHAR_SET), 'HTML-ENTITIES' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an HTML string for output. Fixes some browser-specific bugs, parses replacements and executes hooks
|
||||
*
|
||||
* @param string $string
|
||||
* @param string Array key (only necessary when executed from an array_walk callback)
|
||||
* @return @e string
|
||||
*/
|
||||
public function cleanHtml( &$string, $key='' )
|
||||
{
|
||||
/* Is it really a string? */
|
||||
if ( is_string($string) )
|
||||
{
|
||||
// Fix IE bugs
|
||||
$string = str_ireplace( "§", "&sect", $string );
|
||||
|
||||
if ( strtolower( IPS_DOC_CHAR_SET ) == 'iso-8859-1' )
|
||||
{
|
||||
$string = str_replace( "ì", "“", $string );
|
||||
$string = str_replace( "î", "”", $string );
|
||||
}
|
||||
|
||||
// Other stuff
|
||||
$string = ipsRegistry::getClass('output')->replaceMacros( $string );
|
||||
$string = $this->parseAndCleanHooks( $string );
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* This class can act as an API server, handling API requests
|
||||
* Last Updated: $Date: 2012-12-27 11:37:49 -0500 (Thu, 27 Dec 2012) $
|
||||
* </pre>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* This class acts as a cache layer, allowing you to store and retrieve data in
|
||||
* external cache sources such as memcache or APC
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* This class acts as a cache layer, allowing you to store and retrieve data in
|
||||
* external cache sources such as memcache or APC
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* This class acts as a cache layer, allowing you to store and retrieve data in
|
||||
* external cache sources such as memcache or APC
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* This class acts as a cache layer, allowing you to store and retrieve data in
|
||||
* external cache sources such as memcache or APC
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* This class acts as a cache layer, allowing you to store and retrieve data in
|
||||
* external cache sources such as memcache or APC
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* This class acts as a cache layer, allowing you to store and retrieve data in
|
||||
* external cache sources such as memcache or APC
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
|
||||
+101
-101
@@ -1,102 +1,102 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classCaptcha.php Provides methods to handle CAPTCHA abstraction - easily create, check and display CAPTHCA images
|
||||
*~TERABYTE_DOC_READY~
|
||||
* $Copyright: (c) 2001 - 2011 Invision Power Services, Inc.$
|
||||
* $License: http://www.invisionpower.com/company/standards.php#license$
|
||||
* $Author: bfarber $
|
||||
* @since Friday 19th May 2006 17:33
|
||||
* $LastChangedDate: 2012-02-10 20:05:52 -0500 (Fri, 10 Feb 2012) $
|
||||
* @version v3.4.5
|
||||
* $Revision: 10288 $
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @class classCaptcha
|
||||
* @brief Provides methods to handle CAPTCHA abstraction - easily create, check and display CAPTHCA images
|
||||
*
|
||||
*/
|
||||
class classCaptcha
|
||||
{
|
||||
/**
|
||||
* Registry Object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
public $registry;
|
||||
|
||||
/**
|
||||
* Settings array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $settings;
|
||||
|
||||
/**
|
||||
* Object that stored the plug in class
|
||||
*
|
||||
* @var $_plugInClass
|
||||
*/
|
||||
protected $_plugInClass;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object $registry Registry Object
|
||||
* @return @e void
|
||||
*/
|
||||
public function __construct( ipsRegistry $registry )
|
||||
{
|
||||
$this->registry = $registry;
|
||||
$this->settings =& $this->registry->fetchSettings();
|
||||
|
||||
$plugin = $this->settings['bot_antispam_type'];
|
||||
|
||||
if ( ! is_file( IPS_KERNEL_PATH . 'classCaptchaPlugin/' . $plugin . '.php' ) )
|
||||
{
|
||||
$plugin = 'default';
|
||||
}
|
||||
|
||||
require_once( IPS_KERNEL_PATH . 'classCaptchaPlugin/' . $plugin . '.php' );/*noLibHook*/
|
||||
$this->_plugInClass = new captchaPlugIn( $registry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic __call method
|
||||
*
|
||||
* @param string $method Method name
|
||||
* @param mixed $arguments Method arguments
|
||||
* @return @e mixed
|
||||
*/
|
||||
public function __call( $method, $arguments )
|
||||
{
|
||||
if ( method_exists( $this->_plugInClass, $method ) )
|
||||
{
|
||||
return $this->_plugInClass->$method( $arguments );
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error( $method . " не существует", E_USER_ERROR );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic __get method
|
||||
*
|
||||
* @param string $name Property name
|
||||
* @return @e mixed
|
||||
*/
|
||||
public function __get( $name )
|
||||
{
|
||||
if ( property_exists( $this->_plugInClass, $name ) )
|
||||
{
|
||||
return $this->_plugInClass->$name;
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error( $name . " не существует", E_USER_ERROR );
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classCaptcha.php Provides methods to handle CAPTCHA abstraction - easily create, check and display CAPTHCA images
|
||||
*~TERABYTE_DOC_READY~
|
||||
* $Copyright: (c) 2001 - 2011 Invision Power Services, Inc.$
|
||||
* $License: http://www.invisionpower.com/company/standards.php#license$
|
||||
* $Author: bfarber $
|
||||
* @since Friday 19th May 2006 17:33
|
||||
* $LastChangedDate: 2012-02-10 20:05:52 -0500 (Fri, 10 Feb 2012) $
|
||||
* @version v3.4.6
|
||||
* $Revision: 10288 $
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @class classCaptcha
|
||||
* @brief Provides methods to handle CAPTCHA abstraction - easily create, check and display CAPTHCA images
|
||||
*
|
||||
*/
|
||||
class classCaptcha
|
||||
{
|
||||
/**
|
||||
* Registry Object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
public $registry;
|
||||
|
||||
/**
|
||||
* Settings array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $settings;
|
||||
|
||||
/**
|
||||
* Object that stored the plug in class
|
||||
*
|
||||
* @var $_plugInClass
|
||||
*/
|
||||
protected $_plugInClass;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object $registry Registry Object
|
||||
* @return @e void
|
||||
*/
|
||||
public function __construct( ipsRegistry $registry )
|
||||
{
|
||||
$this->registry = $registry;
|
||||
$this->settings =& $this->registry->fetchSettings();
|
||||
|
||||
$plugin = $this->settings['bot_antispam_type'];
|
||||
|
||||
if ( ! is_file( IPS_KERNEL_PATH . 'classCaptchaPlugin/' . $plugin . '.php' ) )
|
||||
{
|
||||
$plugin = 'default';
|
||||
}
|
||||
|
||||
require_once( IPS_KERNEL_PATH . 'classCaptchaPlugin/' . $plugin . '.php' );/*noLibHook*/
|
||||
$this->_plugInClass = new captchaPlugIn( $registry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic __call method
|
||||
*
|
||||
* @param string $method Method name
|
||||
* @param mixed $arguments Method arguments
|
||||
* @return @e mixed
|
||||
*/
|
||||
public function __call( $method, $arguments )
|
||||
{
|
||||
if ( method_exists( $this->_plugInClass, $method ) )
|
||||
{
|
||||
return $this->_plugInClass->$method( $arguments );
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error( $method . " does not exist", E_USER_ERROR );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic __get method
|
||||
*
|
||||
* @param string $name Property name
|
||||
* @return @e mixed
|
||||
*/
|
||||
public function __get( $name )
|
||||
{
|
||||
if ( property_exists( $this->_plugInClass, $name ) )
|
||||
{
|
||||
return $this->_plugInClass->$name;
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error( $name . " does not exist", E_USER_ERROR );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
* $Author: bfarber $
|
||||
* @since Friday 19th May 2006 17:33
|
||||
* $LastChangedDate: 2012-02-10 20:05:52 -0500 (Fri, 10 Feb 2012) $
|
||||
* @version v3.4.5
|
||||
* @version v3.4.6
|
||||
* $Revision: 10288 $
|
||||
*/
|
||||
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -47,11 +47,11 @@ define("RECAPTCHA_VERIFY_SERVER", "http://www.google.com");
|
||||
*~TERABYTE_DOC_READY~
|
||||
* $Copyright: (c) 2001 - 2011 Invision Power Services, Inc.$
|
||||
* $License: http://www.invisionpower.com/company/standards.php#license$
|
||||
* $Author: mark $
|
||||
* $Author: rashbrook $
|
||||
* @since Friday 19th May 2006 17:33
|
||||
* $LastChangedDate: 2013-02-11 12:32:07 -0500 (Mon, 11 Feb 2013) $
|
||||
* @version v3.4.5
|
||||
* $Revision: 11975 $
|
||||
* $LastChangedDate: 2013-10-16 19:11:24 -0400 (Wed, 16 Oct 2013) $
|
||||
* @version v3.4.6
|
||||
* $Revision: 12381 $
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -158,9 +158,9 @@ class captchaPlugin
|
||||
};
|
||||
</script>";
|
||||
|
||||
$html .= '<script type="text/javascript" src="'. $server . '/challenge?k=' . $this->public_key . '"></script>
|
||||
$html .= '<script type="text/javascript" src="'. $server . '/challenge?k=' . $this->public_key . '&hl=' . $this->settings['recaptcha_language'] . '"></script>
|
||||
<noscript>
|
||||
<iframe src="'. $server . '/noscript?k=' . $this->public_key . '" height="300" width="500" frameborder="0"></iframe><br/>
|
||||
<iframe src="'. $server . '/noscript?k=' . $this->public_key . '&hl=' . $this->settings['recaptcha_language'] . '" height="300" width="500" frameborder="0"></iframe><br/>
|
||||
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
|
||||
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
|
||||
</noscript>';
|
||||
@@ -192,7 +192,15 @@ class captchaPlugin
|
||||
|
||||
$captcha_unique_id = $_REQUEST['recaptcha_challenge_field'];
|
||||
$captcha_input = $_REQUEST['recaptcha_response_field'];
|
||||
|
||||
|
||||
//-----------------------------------------
|
||||
// Path disclosure prevention
|
||||
//-----------------------------------------
|
||||
if ( is_array( $captcha_input ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $captcha_input == null || strlen($captcha_input) == 0 || $captcha_unique_id == null || strlen($captcha_unique_id) == 0)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* Character set conversion library
|
||||
* Last Updated: $Date: 2012-12-07 14:02:27 -0500 (Fri, 07 Dec 2012) $
|
||||
* </pre>
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+2035
-2035
File diff suppressed because it is too large.
Load diff
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* MySQL Database Driver :: Further loads mysql or mysqli client appropriately
|
||||
* Last Updated: $Date: 2012-09-17 11:58:03 -0400 (Mon, 17 Sep 2012) $
|
||||
* </pre>
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,436 +1,436 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* Compare and highlight differences between two strings or files
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
* </pre>
|
||||
*
|
||||
* @author $Author: bfarber $
|
||||
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/company/standards.php#license
|
||||
* @package IP.Board
|
||||
* @subpackage Kernel
|
||||
* @link http://www.invisionpower.com
|
||||
* @since Thursday 10th February 2005 (10:47)
|
||||
* @version $Revision: 10721 $
|
||||
*/
|
||||
|
||||
if ( ! defined( 'IPS_CLASSES_PATH' ) )
|
||||
{
|
||||
/**
|
||||
* Define classes path
|
||||
*/
|
||||
define( 'IPS_CLASSES_PATH', dirname(__FILE__) );
|
||||
}
|
||||
|
||||
class classDifference
|
||||
{
|
||||
/**
|
||||
* Shell command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $diff_command = 'diff';
|
||||
|
||||
/**
|
||||
* Type of diff to use
|
||||
*
|
||||
* @var string [EXEC, PHP]
|
||||
*/
|
||||
public $method = 'EXEC';
|
||||
|
||||
/**
|
||||
* Differences found?
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $diff_found = 0;
|
||||
|
||||
/**
|
||||
* Post process DIFF result?
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $post_process = 1;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return @e void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//-------------------------------
|
||||
// Server?
|
||||
//-------------------------------
|
||||
|
||||
if( strpos( strtolower( PHP_OS ), 'win' ) === 0 OR ( ! function_exists('exec') ) )
|
||||
{
|
||||
$this->method = 'PHP';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a text string showing the differences between the two supplied strings
|
||||
*
|
||||
* @param string Original string
|
||||
* @param string New string
|
||||
* @param string Inline or unified report (only supported by PHP method)
|
||||
* @return @e string
|
||||
*/
|
||||
public function getDifferences( $str1, $str2, $method='inline' )
|
||||
{
|
||||
$this->diff_found = 0;
|
||||
|
||||
if ( $this->method != 'PHP' )
|
||||
{
|
||||
$str1 = $this->_diffTagSpace($str1);
|
||||
$str2 = $this->_diffTagSpace($str2);
|
||||
$str1_lines = $this->_diffExplodeStringIntoWords($str1);
|
||||
$str2_lines = $this->_diffExplodeStringIntoWords($str2);
|
||||
}
|
||||
|
||||
if ( $this->method == 'PHP' )
|
||||
{
|
||||
$diff_res = $this->_getPhpDiff( $str1, $str2, $method );
|
||||
}
|
||||
else
|
||||
{
|
||||
$diff_res = $this->_getExecDiff( implode( chr(10), $str1_lines ) . chr(10), implode( chr(10), $str2_lines ) . chr(10) );
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// Post process?
|
||||
//-------------------------------
|
||||
|
||||
if ( $this->post_process )
|
||||
{
|
||||
if ( is_array($diff_res) )
|
||||
{
|
||||
reset($diff_res);
|
||||
$c = 0;
|
||||
$diff_res_array = array();
|
||||
|
||||
foreach( $diff_res as $l_val )
|
||||
{
|
||||
if ( intval($l_val) )
|
||||
{
|
||||
$c = intval($l_val);
|
||||
$diff_res_array[$c]['changeInfo'] = $l_val;
|
||||
}
|
||||
|
||||
if (substr($l_val,0,1) == '<')
|
||||
{
|
||||
$diff_res_array[$c]['old'][] = substr($l_val,2);
|
||||
}
|
||||
|
||||
if (substr($l_val,0,1) == '>')
|
||||
{
|
||||
$diff_res_array[$c]['new'][] = substr($l_val,2);
|
||||
}
|
||||
}
|
||||
|
||||
$out_str = '';
|
||||
$clr_buffer = '';
|
||||
|
||||
for ( $a = -1; $a < count($str1_lines); $a++ )
|
||||
{
|
||||
if ( is_array( $diff_res_array[$a+1] ) )
|
||||
{
|
||||
if ( strstr( $diff_res_array[$a+1]['changeInfo'], 'a') )
|
||||
{
|
||||
$this->diff_found = 1;
|
||||
$clr_buffer .= htmlspecialchars($str1_lines[$a]).' ';
|
||||
}
|
||||
|
||||
$out_str .= $clr_buffer;
|
||||
$clr_buffer = '';
|
||||
|
||||
if (is_array($diff_res_array[$a+1]['old']))
|
||||
{
|
||||
$this->diff_found = 1;
|
||||
$out_str.='<del style="-ips-match:1">'.htmlspecialchars(implode(' ',$diff_res_array[$a+1]['old'])).'</del> ';
|
||||
}
|
||||
|
||||
if (is_array($diff_res_array[$a+1]['new']))
|
||||
{
|
||||
$this->diff_found = 1;
|
||||
$out_str.='<ins style="-ips-match:1">'.htmlspecialchars(implode(' ',$diff_res_array[$a+1]['new'])).'</ins> ';
|
||||
}
|
||||
|
||||
$cip = explode(',',$diff_res_array[$a+1]['changeInfo']);
|
||||
|
||||
if ( ! strcmp( $cip[0], $a + 1 ) )
|
||||
{
|
||||
$new_line = intval($cip[1])-1;
|
||||
|
||||
if ( $new_line > $a )
|
||||
{
|
||||
$a = $new_line;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$clr_buffer .= htmlspecialchars($str1_lines[$a]).' ';
|
||||
}
|
||||
}
|
||||
|
||||
$out_str .= $clr_buffer;
|
||||
|
||||
$out_str = str_replace(' ',chr(10),$out_str);
|
||||
|
||||
$out_str = $this->_diffTagSpace($out_str,1);
|
||||
|
||||
return $out_str;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $diff_res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds space character after HTML tags
|
||||
*
|
||||
* @param string String
|
||||
* @param integer [Optional][0=reverse, 1=normal]
|
||||
* @return @e string
|
||||
*/
|
||||
protected function _diffTagSpace( $str, $rev=0 )
|
||||
{
|
||||
if ( $rev )
|
||||
{
|
||||
return str_replace(' <','<',str_replace('> ','>',$str) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return str_replace('<',' <',str_replace('>','> ',$str) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Explodes input string into words
|
||||
*
|
||||
* @access protected
|
||||
* @param string Input string
|
||||
* @return @e array
|
||||
*/
|
||||
protected function _diffExplodeStringIntoWords( $str )
|
||||
{
|
||||
$str_array = $this->_explodeTrim( chr(10), $str );
|
||||
$out_array = array();
|
||||
|
||||
reset($str_array);
|
||||
|
||||
foreach( $str_array as $low )
|
||||
{
|
||||
$all_words = $this->_explodeTrim( ' ', $low, 1 );
|
||||
$out_array = array_merge($out_array, $all_words);
|
||||
$out_array[] = '';
|
||||
$out_array[] = '';
|
||||
}
|
||||
|
||||
return $out_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode into array and trim
|
||||
*
|
||||
* @param string Delimiter
|
||||
* @param string String to check
|
||||
* @param integer [Optional] Remove blank lines
|
||||
* @return @e array
|
||||
*/
|
||||
protected function _explodeTrim( $delim, $str, $remove_blank=0 )
|
||||
{
|
||||
$tmp = explode( $delim, trim($str) );
|
||||
$final = array();
|
||||
|
||||
foreach( $tmp as $i )
|
||||
{
|
||||
if ( $remove_blank AND ( $i === '' OR $i === NULL ) ) //!$i AND $i !== 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$final[] = trim($i);
|
||||
}
|
||||
}
|
||||
|
||||
return $final;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce differences using PHP
|
||||
*
|
||||
* @param string comapre string 1
|
||||
* @param string comapre string 2
|
||||
* @return @e string
|
||||
*/
|
||||
protected function _getPhpDiff( $str1 , $str2, $method='inline' )
|
||||
{
|
||||
$str1 = explode( "\n", str_replace( "\r\n", "\n", $str1 ) );
|
||||
$str2 = explode( "\n", str_replace( "\r\n", "\n", $str2 ) );
|
||||
|
||||
/* Set include path.. */
|
||||
@set_include_path( IPS_KERNEL_PATH . 'PEAR/' );/*noLibHook*/
|
||||
|
||||
/* OMG.. too many PHP 5 errors under strict standards */
|
||||
$oldReportLevel = error_reporting( 0 );
|
||||
error_reporting( $oldReportLevel ^ E_STRICT );
|
||||
|
||||
require_once 'Text/Diff.php';/*noLibHook*/
|
||||
require_once 'Text/Diff/Renderer.php';/*noLibHook*/
|
||||
|
||||
$diff = new Text_Diff( 'auto', array( $str1, $str2 ) );
|
||||
|
||||
if ( $method == 'inline' )
|
||||
{
|
||||
require_once 'Text/Diff/Renderer/inline.php';/*noLibHook*/
|
||||
$renderer = new Text_Diff_Renderer_inline();
|
||||
}
|
||||
else
|
||||
{
|
||||
require_once 'Text/Diff/Renderer/unified.php';/*noLibHook*/
|
||||
$renderer = new Text_Diff_Renderer_unified();
|
||||
$renderer->_leading_context_lines = 10000;
|
||||
$renderer->_trailing_context_lines = 10000;
|
||||
}
|
||||
|
||||
$result = $renderer->render($diff);
|
||||
|
||||
/* Go back to old reporting level */
|
||||
error_reporting( $oldReportLevel | E_STRICT );
|
||||
|
||||
$result = str_replace( "<ins>", '<ins style="-ips-match:1">', $result );
|
||||
$result = str_replace( "<del>", '<del style="-ips-match:1">', $result );
|
||||
|
||||
# Got a match?
|
||||
if ( strstr( $result, 'style="-ips-match:1"' ) )
|
||||
{
|
||||
$this->diff_found = 1;
|
||||
}
|
||||
|
||||
# No post processing please
|
||||
$this->post_process = 0;
|
||||
|
||||
# Convert lines to a space, and two spaces to a single line
|
||||
//$result = str_replace(' ', chr(10), str_replace( "\n", " ", $result ) );
|
||||
//$result = $this->_diffTagSpace($result,1);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce differences using unix diff
|
||||
*
|
||||
* @param string comapre string 1
|
||||
* @param string comapre string 2
|
||||
* @return @e string
|
||||
*/
|
||||
protected function _getExecDiff( $str1, $str2 )
|
||||
{
|
||||
//-------------------------------
|
||||
// Write the tmp files
|
||||
//-------------------------------
|
||||
|
||||
$file1 = IPS_ROOT_PATH . 'uploads/'.time().'-1';
|
||||
$file2 = IPS_ROOT_PATH . 'uploads/'.time().'-2';
|
||||
|
||||
if ( $FH1 = @fopen( $file1, 'w' ) )
|
||||
{
|
||||
@fwrite( $FH1, $str1, strlen($str1) );
|
||||
@fclose( $FH1 );
|
||||
}
|
||||
|
||||
if ( $FH2 = @fopen( $file2, 'w' ) )
|
||||
{
|
||||
@fwrite( $FH2, $str2, strlen($str2) );
|
||||
@fclose( $FH2 );
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// Check
|
||||
//-------------------------------
|
||||
|
||||
if ( is_file( $file1 ) and is_file( $file2 ) )
|
||||
{
|
||||
exec( $this->diff_command.' '.$file1.' '.$file2, $result );
|
||||
|
||||
@unlink( $file1 );
|
||||
@unlink( $file2 );
|
||||
|
||||
return $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Ошибка, файлы не были записаны на диск";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format differences for output (common)
|
||||
*
|
||||
* @param string Differences report
|
||||
* @param string Format method (inline|unified)
|
||||
* @param bool Wrap in pre tags (true) or nl2br for output (false)
|
||||
* @return @e string
|
||||
*/
|
||||
public function formatDifferenceReport( $result, $method='inline', $pre=true )
|
||||
{
|
||||
if( $result )
|
||||
{
|
||||
if( $method == 'unified' )
|
||||
{
|
||||
$result = str_replace( array( "\r\n", "\r" ), "\n", $result );
|
||||
$result = preg_replace( '#(^|\n)(\-|\+)([^\n]+?)\n#', "\n\\1\\2\\3\n\n", $result );
|
||||
$result = htmlspecialchars( $result );
|
||||
$result = preg_replace( '#^@@([^@]+?)@@#m', '', $result );
|
||||
$result = preg_replace( '#(^|\n)\-([^\n]+?)\n#', "\\1<del>\\2</del>\n", $result );
|
||||
$result = preg_replace( '#(^|\n)\+([^\n]+?)\n#', "\\1<ins>\\2</ins>\n", $result );
|
||||
$result = str_replace( "</ins>\n\n", "</ins>\n", $result );
|
||||
$result = str_replace( "</del>\n", '</del>', $result );
|
||||
$result = str_replace( "\n\n<ins>", "\n<ins>", $result );
|
||||
$result = str_replace( "\n\n<del>", "\n<del>", $result );
|
||||
$result = str_replace( "\n+\n", "\n\n", $result );
|
||||
$result = str_replace( "\n-\n", "\n\n", $result );
|
||||
|
||||
if( $pre )
|
||||
{
|
||||
$result = '<pre>' . $result . '</pre>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = str_replace( "\t", " ", $result );
|
||||
$result = str_replace( ' ', ' ', $result );
|
||||
$result = nl2br( $result );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = str_replace( "\n", "<br>", $result );
|
||||
$result = str_replace( "><", ">\n<", $result );
|
||||
$result = preg_replace( "#(?<!(\<del|\<ins)) {1}(?!:style)#i", " ", $result );
|
||||
|
||||
if( $pre )
|
||||
{
|
||||
$result = '<pre>' . $result . '</pre>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = str_replace( "\t", " ", $result );
|
||||
$result = str_replace( ' ', ' ', $result );
|
||||
$result = nl2br( $result );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.6
|
||||
* Compare and highlight differences between two strings or files
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
* </pre>
|
||||
*
|
||||
* @author $Author: bfarber $
|
||||
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/company/standards.php#license
|
||||
* @package IP.Board
|
||||
* @subpackage Kernel
|
||||
* @link http://www.invisionpower.com
|
||||
* @since Thursday 10th February 2005 (10:47)
|
||||
* @version $Revision: 10721 $
|
||||
*/
|
||||
|
||||
if ( ! defined( 'IPS_CLASSES_PATH' ) )
|
||||
{
|
||||
/**
|
||||
* Define classes path
|
||||
*/
|
||||
define( 'IPS_CLASSES_PATH', dirname(__FILE__) );
|
||||
}
|
||||
|
||||
class classDifference
|
||||
{
|
||||
/**
|
||||
* Shell command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $diff_command = 'diff';
|
||||
|
||||
/**
|
||||
* Type of diff to use
|
||||
*
|
||||
* @var string [EXEC, PHP]
|
||||
*/
|
||||
public $method = 'EXEC';
|
||||
|
||||
/**
|
||||
* Differences found?
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $diff_found = 0;
|
||||
|
||||
/**
|
||||
* Post process DIFF result?
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $post_process = 1;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return @e void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//-------------------------------
|
||||
// Server?
|
||||
//-------------------------------
|
||||
|
||||
if( strpos( strtolower( PHP_OS ), 'win' ) === 0 OR ( ! function_exists('exec') ) )
|
||||
{
|
||||
$this->method = 'PHP';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a text string showing the differences between the two supplied strings
|
||||
*
|
||||
* @param string Original string
|
||||
* @param string New string
|
||||
* @param string Inline or unified report (only supported by PHP method)
|
||||
* @return @e string
|
||||
*/
|
||||
public function getDifferences( $str1, $str2, $method='inline' )
|
||||
{
|
||||
$this->diff_found = 0;
|
||||
|
||||
if ( $this->method != 'PHP' )
|
||||
{
|
||||
$str1 = $this->_diffTagSpace($str1);
|
||||
$str2 = $this->_diffTagSpace($str2);
|
||||
$str1_lines = $this->_diffExplodeStringIntoWords($str1);
|
||||
$str2_lines = $this->_diffExplodeStringIntoWords($str2);
|
||||
}
|
||||
|
||||
if ( $this->method == 'PHP' )
|
||||
{
|
||||
$diff_res = $this->_getPhpDiff( $str1, $str2, $method );
|
||||
}
|
||||
else
|
||||
{
|
||||
$diff_res = $this->_getExecDiff( implode( chr(10), $str1_lines ) . chr(10), implode( chr(10), $str2_lines ) . chr(10) );
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// Post process?
|
||||
//-------------------------------
|
||||
|
||||
if ( $this->post_process )
|
||||
{
|
||||
if ( is_array($diff_res) )
|
||||
{
|
||||
reset($diff_res);
|
||||
$c = 0;
|
||||
$diff_res_array = array();
|
||||
|
||||
foreach( $diff_res as $l_val )
|
||||
{
|
||||
if ( intval($l_val) )
|
||||
{
|
||||
$c = intval($l_val);
|
||||
$diff_res_array[$c]['changeInfo'] = $l_val;
|
||||
}
|
||||
|
||||
if (substr($l_val,0,1) == '<')
|
||||
{
|
||||
$diff_res_array[$c]['old'][] = substr($l_val,2);
|
||||
}
|
||||
|
||||
if (substr($l_val,0,1) == '>')
|
||||
{
|
||||
$diff_res_array[$c]['new'][] = substr($l_val,2);
|
||||
}
|
||||
}
|
||||
|
||||
$out_str = '';
|
||||
$clr_buffer = '';
|
||||
|
||||
for ( $a = -1; $a < count($str1_lines); $a++ )
|
||||
{
|
||||
if ( is_array( $diff_res_array[$a+1] ) )
|
||||
{
|
||||
if ( strstr( $diff_res_array[$a+1]['changeInfo'], 'a') )
|
||||
{
|
||||
$this->diff_found = 1;
|
||||
$clr_buffer .= htmlspecialchars($str1_lines[$a]).' ';
|
||||
}
|
||||
|
||||
$out_str .= $clr_buffer;
|
||||
$clr_buffer = '';
|
||||
|
||||
if (is_array($diff_res_array[$a+1]['old']))
|
||||
{
|
||||
$this->diff_found = 1;
|
||||
$out_str.='<del style="-ips-match:1">'.htmlspecialchars(implode(' ',$diff_res_array[$a+1]['old'])).'</del> ';
|
||||
}
|
||||
|
||||
if (is_array($diff_res_array[$a+1]['new']))
|
||||
{
|
||||
$this->diff_found = 1;
|
||||
$out_str.='<ins style="-ips-match:1">'.htmlspecialchars(implode(' ',$diff_res_array[$a+1]['new'])).'</ins> ';
|
||||
}
|
||||
|
||||
$cip = explode(',',$diff_res_array[$a+1]['changeInfo']);
|
||||
|
||||
if ( ! strcmp( $cip[0], $a + 1 ) )
|
||||
{
|
||||
$new_line = intval($cip[1])-1;
|
||||
|
||||
if ( $new_line > $a )
|
||||
{
|
||||
$a = $new_line;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$clr_buffer .= htmlspecialchars($str1_lines[$a]).' ';
|
||||
}
|
||||
}
|
||||
|
||||
$out_str .= $clr_buffer;
|
||||
|
||||
$out_str = str_replace(' ',chr(10),$out_str);
|
||||
|
||||
$out_str = $this->_diffTagSpace($out_str,1);
|
||||
|
||||
return $out_str;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $diff_res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds space character after HTML tags
|
||||
*
|
||||
* @param string String
|
||||
* @param integer [Optional][0=reverse, 1=normal]
|
||||
* @return @e string
|
||||
*/
|
||||
protected function _diffTagSpace( $str, $rev=0 )
|
||||
{
|
||||
if ( $rev )
|
||||
{
|
||||
return str_replace(' <','<',str_replace('> ','>',$str) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return str_replace('<',' <',str_replace('>','> ',$str) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Explodes input string into words
|
||||
*
|
||||
* @access protected
|
||||
* @param string Input string
|
||||
* @return @e array
|
||||
*/
|
||||
protected function _diffExplodeStringIntoWords( $str )
|
||||
{
|
||||
$str_array = $this->_explodeTrim( chr(10), $str );
|
||||
$out_array = array();
|
||||
|
||||
reset($str_array);
|
||||
|
||||
foreach( $str_array as $low )
|
||||
{
|
||||
$all_words = $this->_explodeTrim( ' ', $low, 1 );
|
||||
$out_array = array_merge($out_array, $all_words);
|
||||
$out_array[] = '';
|
||||
$out_array[] = '';
|
||||
}
|
||||
|
||||
return $out_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode into array and trim
|
||||
*
|
||||
* @param string Delimiter
|
||||
* @param string String to check
|
||||
* @param integer [Optional] Remove blank lines
|
||||
* @return @e array
|
||||
*/
|
||||
protected function _explodeTrim( $delim, $str, $remove_blank=0 )
|
||||
{
|
||||
$tmp = explode( $delim, trim($str) );
|
||||
$final = array();
|
||||
|
||||
foreach( $tmp as $i )
|
||||
{
|
||||
if ( $remove_blank AND ( $i === '' OR $i === NULL ) ) //!$i AND $i !== 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$final[] = trim($i);
|
||||
}
|
||||
}
|
||||
|
||||
return $final;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce differences using PHP
|
||||
*
|
||||
* @param string comapre string 1
|
||||
* @param string comapre string 2
|
||||
* @return @e string
|
||||
*/
|
||||
protected function _getPhpDiff( $str1 , $str2, $method='inline' )
|
||||
{
|
||||
$str1 = explode( "\n", str_replace( "\r\n", "\n", $str1 ) );
|
||||
$str2 = explode( "\n", str_replace( "\r\n", "\n", $str2 ) );
|
||||
|
||||
/* Set include path.. */
|
||||
@set_include_path( IPS_KERNEL_PATH . 'PEAR/' );/*noLibHook*/
|
||||
|
||||
/* OMG.. too many PHP 5 errors under strict standards */
|
||||
$oldReportLevel = error_reporting( 0 );
|
||||
error_reporting( $oldReportLevel ^ E_STRICT );
|
||||
|
||||
require_once 'Text/Diff.php';/*noLibHook*/
|
||||
require_once 'Text/Diff/Renderer.php';/*noLibHook*/
|
||||
|
||||
$diff = new Text_Diff( 'auto', array( $str1, $str2 ) );
|
||||
|
||||
if ( $method == 'inline' )
|
||||
{
|
||||
require_once 'Text/Diff/Renderer/inline.php';/*noLibHook*/
|
||||
$renderer = new Text_Diff_Renderer_inline();
|
||||
}
|
||||
else
|
||||
{
|
||||
require_once 'Text/Diff/Renderer/unified.php';/*noLibHook*/
|
||||
$renderer = new Text_Diff_Renderer_unified();
|
||||
$renderer->_leading_context_lines = 10000;
|
||||
$renderer->_trailing_context_lines = 10000;
|
||||
}
|
||||
|
||||
$result = $renderer->render($diff);
|
||||
|
||||
/* Go back to old reporting level */
|
||||
error_reporting( $oldReportLevel | E_STRICT );
|
||||
|
||||
$result = str_replace( "<ins>", '<ins style="-ips-match:1">', $result );
|
||||
$result = str_replace( "<del>", '<del style="-ips-match:1">', $result );
|
||||
|
||||
# Got a match?
|
||||
if ( strstr( $result, 'style="-ips-match:1"' ) )
|
||||
{
|
||||
$this->diff_found = 1;
|
||||
}
|
||||
|
||||
# No post processing please
|
||||
$this->post_process = 0;
|
||||
|
||||
# Convert lines to a space, and two spaces to a single line
|
||||
//$result = str_replace(' ', chr(10), str_replace( "\n", " ", $result ) );
|
||||
//$result = $this->_diffTagSpace($result,1);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce differences using unix diff
|
||||
*
|
||||
* @param string comapre string 1
|
||||
* @param string comapre string 2
|
||||
* @return @e string
|
||||
*/
|
||||
protected function _getExecDiff( $str1, $str2 )
|
||||
{
|
||||
//-------------------------------
|
||||
// Write the tmp files
|
||||
//-------------------------------
|
||||
|
||||
$file1 = IPS_ROOT_PATH . 'uploads/'.time().'-1';
|
||||
$file2 = IPS_ROOT_PATH . 'uploads/'.time().'-2';
|
||||
|
||||
if ( $FH1 = @fopen( $file1, 'w' ) )
|
||||
{
|
||||
@fwrite( $FH1, $str1, strlen($str1) );
|
||||
@fclose( $FH1 );
|
||||
}
|
||||
|
||||
if ( $FH2 = @fopen( $file2, 'w' ) )
|
||||
{
|
||||
@fwrite( $FH2, $str2, strlen($str2) );
|
||||
@fclose( $FH2 );
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// Check
|
||||
//-------------------------------
|
||||
|
||||
if ( is_file( $file1 ) and is_file( $file2 ) )
|
||||
{
|
||||
exec( $this->diff_command.' '.$file1.' '.$file2, $result );
|
||||
|
||||
@unlink( $file1 );
|
||||
@unlink( $file2 );
|
||||
|
||||
return $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Error, files not written to disk";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format differences for output (common)
|
||||
*
|
||||
* @param string Differences report
|
||||
* @param string Format method (inline|unified)
|
||||
* @param bool Wrap in pre tags (true) or nl2br for output (false)
|
||||
* @return @e string
|
||||
*/
|
||||
public function formatDifferenceReport( $result, $method='inline', $pre=true )
|
||||
{
|
||||
if( $result )
|
||||
{
|
||||
if( $method == 'unified' )
|
||||
{
|
||||
$result = str_replace( array( "\r\n", "\r" ), "\n", $result );
|
||||
$result = preg_replace( '#(^|\n)(\-|\+)([^\n]+?)\n#', "\n\\1\\2\\3\n\n", $result );
|
||||
$result = htmlspecialchars( $result );
|
||||
$result = preg_replace( '#^@@([^@]+?)@@#m', '', $result );
|
||||
$result = preg_replace( '#(^|\n)\-([^\n]+?)\n#', "\\1<del>\\2</del>\n", $result );
|
||||
$result = preg_replace( '#(^|\n)\+([^\n]+?)\n#', "\\1<ins>\\2</ins>\n", $result );
|
||||
$result = str_replace( "</ins>\n\n", "</ins>\n", $result );
|
||||
$result = str_replace( "</del>\n", '</del>', $result );
|
||||
$result = str_replace( "\n\n<ins>", "\n<ins>", $result );
|
||||
$result = str_replace( "\n\n<del>", "\n<del>", $result );
|
||||
$result = str_replace( "\n+\n", "\n\n", $result );
|
||||
$result = str_replace( "\n-\n", "\n\n", $result );
|
||||
|
||||
if( $pre )
|
||||
{
|
||||
$result = '<pre>' . $result . '</pre>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = str_replace( "\t", " ", $result );
|
||||
$result = str_replace( ' ', ' ', $result );
|
||||
$result = nl2br( $result );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = str_replace( "\n", "<br>", $result );
|
||||
$result = str_replace( "><", ">\n<", $result );
|
||||
$result = preg_replace( "#(?<!(\<del|\<ins)) {1}(?!:style)#i", " ", $result );
|
||||
|
||||
if( $pre )
|
||||
{
|
||||
$result = '<pre>' . $result . '</pre>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = str_replace( "\t", " ", $result );
|
||||
$result = str_replace( ' ', ' ', $result );
|
||||
$result = nl2br( $result );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* Send email using php mail() or SMTP
|
||||
* Last Updated: $Date: 2012-11-12 11:43:40 -0500 (Mon, 12 Nov 2012) $
|
||||
* </pre>
|
||||
@@ -672,7 +672,7 @@ class classEmail implements interfaceEmail
|
||||
|
||||
if( !is_dir( $this->temp_dump_path ) )
|
||||
{
|
||||
$this->_fatalError( "Включена отладка, но путь отладки не существует и не может быть создан" );
|
||||
$this->_fatalError( "Debugging enabled, but debug path does not exist and cannot be created" );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -703,7 +703,7 @@ class classEmail implements interfaceEmail
|
||||
{
|
||||
if ( ! @mail( $this->to, $this->subject, $this->message, $this->rfc_headers ) )
|
||||
{
|
||||
$this->_fatalError( "Невозможно отправить сообщение", "Ошибка функции 'mail'" );
|
||||
$this->_fatalError( "Could not send the email", "Failed at 'mail' command" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* FTP Class
|
||||
* Last Updated: $Date: 2013-02-06 10:51:28 -0500 (Wed, 06 Feb 2013) $ BY $Author: mark $
|
||||
* </pre>
|
||||
|
||||
+3082
-3082
File diff suppressed because it is too large.
Load diff
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* Image Handler: create thumbnails, apply watermarks and copyright tests, save or display final image
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
* </pre>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* Image Handler: GD2 Library
|
||||
* Last Updated: $Date: 2013-02-06 19:48:42 -0500 (Wed, 06 Feb 2013) $
|
||||
* </pre>
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* Image Handler: ImageMagick Library
|
||||
* Last Updated: $Date: 2013-02-20 19:45:47 -0500 (Wed, 20 Feb 2013) $
|
||||
* Last Updated: $Date: 2013-08-05 19:04:11 -0400 (Mon, 05 Aug 2013) $
|
||||
* </pre>
|
||||
*
|
||||
* @author $Author: bfarber $
|
||||
* @author $Author: AndyMillne $
|
||||
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/company/standards.php#license
|
||||
* @package IP.Board
|
||||
* @subpackage Kernel
|
||||
* @link http://www.invisionpower.com
|
||||
* @since Monday 5th May 2008 14:00
|
||||
* @version $Revision: 12007 $
|
||||
* @version $Revision: 12329 $
|
||||
*
|
||||
* ImageMagick Example
|
||||
* <code>
|
||||
@@ -26,12 +26,12 @@
|
||||
* 'im_path' => '/path/to/imagemagick/folder/',
|
||||
* 'temp_path' => '/tmp/',
|
||||
* ) );
|
||||
*
|
||||
*
|
||||
* if( $image->error )
|
||||
* {
|
||||
* print $image->error;exit;
|
||||
* }
|
||||
*
|
||||
*
|
||||
* Set max width and height
|
||||
* $image->resizeImage( 600, 480 );
|
||||
* // Add a watermark
|
||||
@@ -133,6 +133,8 @@ class classImageImagemagick extends classImage implements interfaceImage
|
||||
@unlink( $this->temp_file );
|
||||
}
|
||||
|
||||
@copy( $this->image_full, $this->temp_file );
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Get image extension
|
||||
//---------------------------------------------------------
|
||||
@@ -193,7 +195,7 @@ class classImageImagemagick extends classImage implements interfaceImage
|
||||
//$ratioOrig = 1;
|
||||
}
|
||||
|
||||
if ( $width / $height > $ratioOrig )
|
||||
if ( $width / $height > $ratioOrig )
|
||||
{
|
||||
$nheight = $width / $ratioOrig;
|
||||
$nwidth = $width;
|
||||
@@ -229,7 +231,7 @@ class classImageImagemagick extends classImage implements interfaceImage
|
||||
* @return @e array
|
||||
*/
|
||||
public function crop( $x1, $y1, $width, $height )
|
||||
{
|
||||
{
|
||||
$this->_cropX = $x1;
|
||||
$this->_cropY = $y1;
|
||||
|
||||
@@ -268,7 +270,7 @@ class classImageImagemagick extends classImage implements interfaceImage
|
||||
if( ! is_array($new_dims) OR !count($new_dims) OR !$new_dims['img_width'] )
|
||||
{
|
||||
if( ! $this->force_resize )
|
||||
{
|
||||
{
|
||||
return array( 'originalWidth' => $this->orig_dimensions['width'],
|
||||
'originalHeight' => $this->orig_dimensions['height'],
|
||||
'newWidth' => $this->orig_dimensions['width'],
|
||||
@@ -503,7 +505,7 @@ class classImageImagemagick extends classImage implements interfaceImage
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,7 +598,7 @@ class classImageImagemagick extends classImage implements interfaceImage
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* Three Way Merge Class
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $ BY $author$
|
||||
* </pre>
|
||||
|
||||
+1194
-1194
File diff suppressed because it is too large.
Load diff
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* Template Parser : Converts HTML "logic" into PHP code
|
||||
* Last Updated: $Date: 2012-10-18 10:27:08 -0400 (Thu, 18 Oct 2012) $
|
||||
* </pre>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* Upload handler : Handles $_FILES and checks for security
|
||||
* Last Updated: $Date: 2013-02-19 06:02:12 -0500 (Tue, 19 Feb 2013) $
|
||||
* </pre>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* XML Handler: Rewritten for PHP5
|
||||
* By Matt Mecham
|
||||
* Last Updated: $Date: 2012-07-27 11:43:25 -0400 (Fri, 27 Jul 2012) $
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* XML Archive Hanlder: Can create XML Archives (gzips) of multiple files, binary and ascii
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
* </pre>
|
||||
|
||||
+1054
-1054
File diff suppressed because it is too large.
Load diff
+1481
-1481
File diff suppressed because it is too large.
Load diff
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,7 +8,7 @@
|
||||
* $Author: AndyMillne $
|
||||
* @since Tuesday 1st March 2005 15:40
|
||||
* $LastChangedDate: 2013-05-07 11:14:15 -0400 (Tue, 07 May 2013) $
|
||||
* @version v3.4.5
|
||||
* @version v3.4.6
|
||||
* $Revision: 12235 $
|
||||
*/
|
||||
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* <pre>
|
||||
* Invision Power Services
|
||||
* IP.Board v3.4.5
|
||||
* IP.Board v3.4.6
|
||||
* This class acts as a cache layer, allowing you to store and retrieve data in
|
||||
* external cache sources such as memcache or APC
|
||||
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com/">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,6 @@
|
||||
<hr>
|
||||
You have reached this page in error, please use your back button to return to the forum.
|
||||
<hr>
|
||||
<a href="http://www.invisionpower.com">IP.Board</a>
|
||||
IP.Board
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,799 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The default Cache Lifetime (in seconds).
|
||||
*/
|
||||
define("OAUTH2_DEFAULT_EXPIRES_IN", 3600*60*60*24);
|
||||
|
||||
/**
|
||||
* The default Base domain for the Cookie.
|
||||
*/
|
||||
define("OAUTH2_DEFAULT_BASE_DOMAIN", '');
|
||||
|
||||
/**
|
||||
* OAuth2.0 draft v10 client-side implementation.
|
||||
*
|
||||
* @author Originally written by Naitik Shah <naitik@facebook.com>.
|
||||
* @author Update to draft v10 by Edison Wong <hswong3i@pantarei-design.com>.
|
||||
*
|
||||
* @sa <a href="https://github.com/facebook/php-sdk">Facebook PHP SDK</a>.
|
||||
*/
|
||||
abstract class OAuth2Client {
|
||||
|
||||
/**
|
||||
* Array of persistent variables stored.
|
||||
*/
|
||||
protected $conf = array();
|
||||
|
||||
/**
|
||||
* Returns a persistent variable.
|
||||
*
|
||||
* To avoid problems, always use lower case for persistent variable names.
|
||||
*
|
||||
* @param $name
|
||||
* The name of the variable to return.
|
||||
* @param $default
|
||||
* The default value to use if this variable has never been set.
|
||||
*
|
||||
* @return
|
||||
* The value of the variable.
|
||||
*/
|
||||
public function getVariable($name, $default = NULL) {
|
||||
return isset($this->conf[$name]) ? $this->conf[$name] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a persistent variable.
|
||||
*
|
||||
* To avoid problems, always use lower case for persistent variable names.
|
||||
*
|
||||
* @param $name
|
||||
* The name of the variable to set.
|
||||
* @param $value
|
||||
* The value to set.
|
||||
*/
|
||||
public function setVariable($name, $value) {
|
||||
$this->conf[$name] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Stuff that should get overridden by subclasses.
|
||||
//
|
||||
// I don't want to make these abstract, because then subclasses would have
|
||||
// to implement all of them, which is too much work.
|
||||
//
|
||||
// So they're just stubs. Override the ones you need.
|
||||
|
||||
/**
|
||||
* Initialize a Drupal OAuth2.0 Application.
|
||||
*
|
||||
* @param $config
|
||||
* An associative array as below:
|
||||
* - base_uri: The base URI for the OAuth2.0 endpoints.
|
||||
* - code: (optional) The authorization code.
|
||||
* - username: (optional) The username.
|
||||
* - password: (optional) The password.
|
||||
* - client_id: (optional) The application ID.
|
||||
* - client_secret: (optional) The application secret.
|
||||
* - authorize_uri: (optional) The end-user authorization endpoint URI.
|
||||
* - access_token_uri: (optional) The token endpoint URI.
|
||||
* - services_uri: (optional) The services endpoint URI.
|
||||
* - cookie_support: (optional) TRUE to enable cookie support.
|
||||
* - base_domain: (optional) The domain for the cookie.
|
||||
* - file_upload_support: (optional) TRUE if file uploads are enabled.
|
||||
*/
|
||||
public function __construct($config = array()) {
|
||||
// We must set base_uri first.
|
||||
$this->setVariable('base_uri', $config['base_uri']);
|
||||
unset($config['base_uri']);
|
||||
|
||||
// Use predefined OAuth2.0 params, or get it from $_REQUEST.
|
||||
foreach (array('code', 'username', 'password') as $name) {
|
||||
if (isset($config[$name]))
|
||||
$this->setVariable($name, $config[$name]);
|
||||
else if (isset($_REQUEST[$name]) && !empty($_REQUEST[$name]))
|
||||
$this->setVariable($name, $_REQUEST[$name]);
|
||||
unset($config[$name]);
|
||||
}
|
||||
|
||||
// Endpoint URIs.
|
||||
foreach (array('authorize_uri', 'access_token_uri', 'services_uri') as $name) {
|
||||
if (isset($config[$name]))
|
||||
if (substr($config[$name], 0, 4) == "http")
|
||||
$this->setVariable($name, $config[$name]);
|
||||
else
|
||||
$this->setVariable($name, $this->getVariable('base_uri') . $config[$name]);
|
||||
unset($config[$name]);
|
||||
}
|
||||
|
||||
// Other else configurations.
|
||||
foreach ($config as $name => $value) {
|
||||
$this->setVariable($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get session object from custom method.
|
||||
*
|
||||
* By default we generate session object based on access_token response, or
|
||||
* if it is provided from server with $_REQUEST. For sure, if it is provided
|
||||
* by server it should follow our session object format.
|
||||
*
|
||||
* Session object provided by server can ensure the correct expires and
|
||||
* base_domain setup as predefined in server, also you may get more useful
|
||||
* information for custom functionality, too. BTW, this may require for
|
||||
* additional remote call overhead.
|
||||
*
|
||||
* You may wish to override this function with your custom version due to
|
||||
* your own server-side implementation.
|
||||
*
|
||||
* @param $access_token
|
||||
* (optional) A valid access token in associative array as below:
|
||||
* - access_token: A valid access_token generated by OAuth2.0
|
||||
* authorization endpoint.
|
||||
* - expires_in: (optional) A valid expires_in generated by OAuth2.0
|
||||
* authorization endpoint.
|
||||
* - refresh_token: (optional) A valid refresh_token generated by OAuth2.0
|
||||
* authorization endpoint.
|
||||
* - scope: (optional) A valid scope generated by OAuth2.0
|
||||
* authorization endpoint.
|
||||
*
|
||||
* @return
|
||||
* A valid session object in associative array for setup cookie, and
|
||||
* NULL if not able to generate it with custom method.
|
||||
*/
|
||||
protected function getSessionObject($access_token = NULL) {
|
||||
$session = NULL;
|
||||
|
||||
// Try generate local version of session cookie.
|
||||
if (!empty($access_token) && isset($access_token['access_token'])) {
|
||||
$session['access_token'] = $access_token['access_token'];
|
||||
$session['base_domain'] = $this->getVariable('base_domain', OAUTH2_DEFAULT_BASE_DOMAIN);
|
||||
$session['expires'] = isset($access_token['expires_in']) ? time() + $access_token['expires_in'] : time() + $this->getVariable('expires_in', OAUTH2_DEFAULT_EXPIRES_IN);
|
||||
$session['refresh_token'] = isset($access_token['refresh_token']) ? $access_token['refresh_token'] : '';
|
||||
$session['scope'] = isset($access_token['scope']) ? $access_token['scope'] : '';
|
||||
$session['secret'] = md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid())));
|
||||
|
||||
// Provide our own signature.
|
||||
$sig = self::generateSignature(
|
||||
$session,
|
||||
$this->getVariable('client_secret')
|
||||
);
|
||||
$session['sig'] = $sig;
|
||||
}
|
||||
|
||||
// Try loading session from $_REQUEST.
|
||||
if (!$session && isset($_REQUEST['session'])) {
|
||||
$session = json_decode(
|
||||
get_magic_quotes_gpc()
|
||||
? stripslashes($_REQUEST['session'])
|
||||
: $_REQUEST['session'],
|
||||
TRUE
|
||||
);
|
||||
}
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an API call.
|
||||
*
|
||||
* Support both OAuth2.0 or normal GET/POST API call, with relative
|
||||
* or absolute URI.
|
||||
*
|
||||
* If no valid OAuth2.0 access token found in session object, this function
|
||||
* will automatically switch as normal remote API call without "oauth_token"
|
||||
* parameter.
|
||||
*
|
||||
* Assume server reply in JSON object and always decode during return. If
|
||||
* you hope to issue a raw query, please use makeRequest().
|
||||
*
|
||||
* @param $path
|
||||
* The target path, relative to base_path/service_uri or an absolute URI.
|
||||
* @param $method
|
||||
* (optional) The HTTP method (default 'GET').
|
||||
* @param $params
|
||||
* (optional The GET/POST parameters.
|
||||
*
|
||||
* @return
|
||||
* The JSON decoded response object.
|
||||
*
|
||||
* @throws OAuth2Exception
|
||||
*/
|
||||
public function api($path, $method = 'GET', $params = array()) {
|
||||
if (is_array($method) && empty($params)) {
|
||||
$params = $method;
|
||||
$method = 'GET';
|
||||
}
|
||||
|
||||
// json_encode all params values that are not strings.
|
||||
foreach ($params as $key => $value) {
|
||||
if (!is_string($value)) {
|
||||
$params[$key] = json_encode($value);
|
||||
}
|
||||
}
|
||||
|
||||
$result = json_decode($this->makeOAuth2Request(
|
||||
$this->getUri($path),
|
||||
$method,
|
||||
$params
|
||||
), TRUE);
|
||||
|
||||
// Results are returned, errors are thrown.
|
||||
if (is_array($result) && isset($result['error'])) {
|
||||
$e = new OAuth2Exception($result);
|
||||
switch ($e->getType()) {
|
||||
// OAuth 2.0 Draft 10 style.
|
||||
case 'invalid_token':
|
||||
$this->setSession(NULL);
|
||||
default:
|
||||
$this->setSession(NULL);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// End stuff that should get overridden.
|
||||
|
||||
/**
|
||||
* Default options for cURL.
|
||||
*/
|
||||
public static $CURL_OPTS = array(
|
||||
CURLOPT_CONNECTTIMEOUT => 10,
|
||||
CURLOPT_RETURNTRANSFER => TRUE,
|
||||
CURLOPT_HEADER => TRUE,
|
||||
CURLOPT_TIMEOUT => 60,
|
||||
CURLOPT_USERAGENT => 'oauth2-draft-v10',
|
||||
CURLOPT_HTTPHEADER => array("Accept: application/json"),
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the Session.
|
||||
*
|
||||
* @param $session
|
||||
* (optional) The session object to be set. NULL if hope to frush existing
|
||||
* session object.
|
||||
* @param $write_cookie
|
||||
* (optional) TRUE if a cookie should be written. This value is ignored
|
||||
* if cookie support has been disabled.
|
||||
*
|
||||
* @return
|
||||
* The current OAuth2.0 client-side instance.
|
||||
*/
|
||||
public function setSession($session = NULL, $write_cookie = TRUE) {
|
||||
$this->setVariable('_session', $this->validateSessionObject($session));
|
||||
$this->setVariable('_session_loaded', TRUE);
|
||||
if ($write_cookie) {
|
||||
$this->setCookieFromSession($this->getVariable('_session'));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the session object.
|
||||
*
|
||||
* This will automatically look for a signed session via custom method,
|
||||
* OAuth2.0 grant type with authorization_code, OAuth2.0 grant type with
|
||||
* password, or cookie that we had already setup.
|
||||
*
|
||||
* @return
|
||||
* The valid session object with OAuth2.0 infomration, and NULL if not
|
||||
* able to discover any cases.
|
||||
*/
|
||||
public function getSession() {
|
||||
if (!$this->getVariable('_session_loaded')) {
|
||||
$session = NULL;
|
||||
$write_cookie = TRUE;
|
||||
|
||||
// Try obtain login session by custom method.
|
||||
// $session = $this->getSessionObject(NULL);
|
||||
// $session = $this->validateSessionObject($session);
|
||||
|
||||
// grant_type == authorization_code.
|
||||
if (!$session && $this->getVariable('code')) {
|
||||
$access_token = $this->getAccessTokenFromAuthorizationCode($this->getVariable('code'));
|
||||
$session = $this->getSessionObject($access_token);
|
||||
$session = $this->validateSessionObject($session);
|
||||
}
|
||||
|
||||
// grant_type == password.
|
||||
if (!$session && $this->getVariable('username') && $this->getVariable('password')) {
|
||||
$access_token = $this->getAccessTokenFromPassword($this->getVariable('username'), $this->getVariable('password'));
|
||||
$session = $this->getSessionObject($access_token);
|
||||
$session = $this->validateSessionObject($session);
|
||||
}
|
||||
|
||||
// Try loading session from cookie if necessary.
|
||||
if (!$session && $this->getVariable('cookie_support')) {
|
||||
$cookie_name = $this->getSessionCookieName();
|
||||
if (isset($_COOKIE[$cookie_name])) {
|
||||
$session = array();
|
||||
parse_str(trim(
|
||||
get_magic_quotes_gpc()
|
||||
? stripslashes($_COOKIE[$cookie_name])
|
||||
: $_COOKIE[$cookie_name],
|
||||
'"'
|
||||
), $session);
|
||||
$session = $this->validateSessionObject($session);
|
||||
// Write only if we need to delete a invalid session cookie.
|
||||
$write_cookie = empty($session);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setSession($session, $write_cookie);
|
||||
}
|
||||
|
||||
return $this->getVariable('_session');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an OAuth2.0 access token from session.
|
||||
*
|
||||
* This will trigger getSession() and so we MUST initialize with required
|
||||
* configuration.
|
||||
*
|
||||
* @return
|
||||
* The valid OAuth2.0 access token, and NULL if not exists in session.
|
||||
*/
|
||||
public function getAccessToken() {
|
||||
$session = $this->getSession();
|
||||
return isset($session['access_token']) ? $session['access_token'] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access token from OAuth2.0 token endpoint with authorization code.
|
||||
*
|
||||
* This function will only be activated if both access token URI, client
|
||||
* identifier and client secret are setup correctly.
|
||||
*
|
||||
* @param $code
|
||||
* Authorization code issued by authorization server's authorization
|
||||
* endpoint.
|
||||
*
|
||||
* @return
|
||||
* A valid OAuth2.0 JSON decoded access token in associative array, and
|
||||
* NULL if not enough parameters or JSON decode failed.
|
||||
*/
|
||||
private function getAccessTokenFromAuthorizationCode($code) {
|
||||
if ($this->getVariable('access_token_uri') && $this->getVariable('client_id') && $this->getVariable('client_secret')) {
|
||||
$result = json_decode($this->makeRequest(
|
||||
$this->getVariable('access_token_uri'),
|
||||
'POST',
|
||||
array(
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => $this->getVariable('client_id'),
|
||||
'client_secret' => $this->getVariable('client_secret'),
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->getVariable( 'authorize_callback_uri') //$this->getCurrentUri(),
|
||||
)
|
||||
), TRUE);
|
||||
return $result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access token from OAuth2.0 token endpoint with basic user
|
||||
* credentials.
|
||||
*
|
||||
* This function will only be activated if both username and password
|
||||
* are setup correctly.
|
||||
*
|
||||
* @param $username
|
||||
* Username to be check with.
|
||||
* @param $password
|
||||
* Password to be check with.
|
||||
*
|
||||
* @return
|
||||
* A valid OAuth2.0 JSON decoded access token in associative array, and
|
||||
* NULL if not enough parameters or JSON decode failed.
|
||||
*/
|
||||
private function getAccessTokenFromPassword($username, $password) {
|
||||
if ($this->getVariable('access_token_uri') && $this->getVariable('client_id') && $this->getVariable('client_secret')) {
|
||||
return json_decode($this->makeRequest(
|
||||
$this->getVariable('access_token_uri'),
|
||||
'POST',
|
||||
array(
|
||||
'grant_type' => 'password',
|
||||
'client_id' => $this->getVariable('client_id'),
|
||||
'client_secret' => $this->getVariable('client_secret'),
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
)
|
||||
), TRUE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an OAuth2.0 Request.
|
||||
*
|
||||
* Automatically append "oauth_token" in query parameters if not yet
|
||||
* exists and able to discover a valid access token from session. Otherwise
|
||||
* just ignore setup with "oauth_token" and handle the API call AS-IS, and
|
||||
* so may issue a plain API call without OAuth2.0 protection.
|
||||
*
|
||||
* @param $path
|
||||
* The target path, relative to base_path/service_uri or an absolute URI.
|
||||
* @param $method
|
||||
* (optional) The HTTP method (default 'GET').
|
||||
* @param $params
|
||||
* (optional The GET/POST parameters.
|
||||
*
|
||||
* @return
|
||||
* The JSON decoded response object.
|
||||
*
|
||||
* @throws OAuth2Exception
|
||||
*/
|
||||
protected function makeOAuth2Request($path, $method = 'GET', $params = array()) {
|
||||
if ((!isset($params['oauth_token']) || empty($params['oauth_token'])) && $oauth_token = $this->getAccessToken()) {
|
||||
$params['oauth_token'] = $oauth_token;
|
||||
}
|
||||
return $this->makeRequest($path, $method, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an HTTP request.
|
||||
*
|
||||
* This method can be overriden by subclasses if developers want to do
|
||||
* fancier things or use something other than cURL to make the request.
|
||||
*
|
||||
* @param $path
|
||||
* The target path, relative to base_path/service_uri or an absolute URI.
|
||||
* @param $method
|
||||
* (optional) The HTTP method (default 'GET').
|
||||
* @param $params
|
||||
* (optional The GET/POST parameters.
|
||||
* @param $ch
|
||||
* (optional) An initialized curl handle
|
||||
*
|
||||
* @return
|
||||
* The JSON decoded response object.
|
||||
*/
|
||||
protected function makeRequest($path, $method = 'GET', $params = array(), $ch = NULL) {
|
||||
if (!$ch)
|
||||
$ch = curl_init();
|
||||
|
||||
$opts = self::$CURL_OPTS;
|
||||
if ($params) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$path .= '?' . http_build_query($params, NULL, '&');
|
||||
break;
|
||||
// Method override as we always do a POST.
|
||||
default:
|
||||
if ($this->getVariable('file_upload_support')) {
|
||||
$opts[CURLOPT_POSTFIELDS] = $params;
|
||||
}
|
||||
else {
|
||||
$opts[CURLOPT_POSTFIELDS] = http_build_query($params, NULL, '&');
|
||||
}
|
||||
}
|
||||
}
|
||||
$opts[CURLOPT_URL] = $path;
|
||||
|
||||
// Disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
|
||||
// for 2 seconds if the server does not support this header.
|
||||
if (isset($opts[CURLOPT_HTTPHEADER])) {
|
||||
$existing_headers = $opts[CURLOPT_HTTPHEADER];
|
||||
$existing_headers[] = 'Expect:';
|
||||
$opts[CURLOPT_HTTPHEADER] = $existing_headers;
|
||||
}
|
||||
else {
|
||||
$opts[CURLOPT_HTTPHEADER] = array('Expect:');
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, $opts);
|
||||
$result = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT
|
||||
error_log('Invalid or no certificate authority found, using bundled information');
|
||||
curl_setopt($ch, CURLOPT_CAINFO,
|
||||
dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
|
||||
$result = curl_exec($ch);
|
||||
}
|
||||
|
||||
if ($result === FALSE) {
|
||||
$e = new OAuth2Exception(array(
|
||||
'code' => curl_errno($ch),
|
||||
'message' => curl_error($ch),
|
||||
));
|
||||
curl_close($ch);
|
||||
throw $e;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
// Split the HTTP response into header and body.
|
||||
list($headers, $body) = explode("\r\n\r\n", $result);
|
||||
$headers = explode("\r\n", $headers);
|
||||
|
||||
// We catch HTTP/1.1 4xx or HTTP/1.1 5xx error response.
|
||||
if (strpos($headers[0], 'HTTP/1.1 4') !== FALSE || strpos($headers[0], 'HTTP/1.1 5') !== FALSE) {
|
||||
$result = array(
|
||||
'code' => 0,
|
||||
'message' => '',
|
||||
);
|
||||
|
||||
if (preg_match('/^HTTP\/1.1 ([0-9]{3,3}) (.*)$/', $headers[0], $matches)) {
|
||||
$result['code'] = $matches[1];
|
||||
$result['message'] = $matches[2];
|
||||
}
|
||||
|
||||
// In case retrun with WWW-Authenticate replace the description.
|
||||
foreach ($headers as $header) {
|
||||
if (preg_match("/^WWW-Authenticate:.*error='(.*)'/", $header, $matches)) {
|
||||
$result['error'] = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the cookie that contains the session object.
|
||||
*
|
||||
* @return
|
||||
* The cookie name.
|
||||
*/
|
||||
private function getSessionCookieName() {
|
||||
return 'oauth2_' . $this->getVariable('client_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a JS Cookie based on the _passed in_ session.
|
||||
*
|
||||
* It does not use the currently stored session - you need to explicitly
|
||||
* pass it in.
|
||||
*
|
||||
* @param $session
|
||||
* The session to use for setting the cookie.
|
||||
*/
|
||||
protected function setCookieFromSession($session = NULL) {
|
||||
if (!$this->getVariable('cookie_support'))
|
||||
return;
|
||||
|
||||
$cookie_name = $this->getSessionCookieName();
|
||||
$value = 'deleted';
|
||||
$expires = time() - 3600;
|
||||
$base_domain = $this->getVariable('base_domain', OAUTH2_DEFAULT_BASE_DOMAIN);
|
||||
|
||||
if ($session) {
|
||||
$value = '"' . http_build_query($session, NULL, '&') . '"';
|
||||
$base_domain = isset($session['base_domain']) ? $session['base_domain'] : $base_domain;
|
||||
$expires = isset($session['expires']) ? $session['expires'] : time() + $this->getVariable('expires_in', OAUTH2_DEFAULT_EXPIRES_IN);
|
||||
}
|
||||
|
||||
// Prepend dot if a domain is found.
|
||||
if ($base_domain)
|
||||
$base_domain = '.' . $base_domain;
|
||||
|
||||
// If an existing cookie is not set, we dont need to delete it.
|
||||
if ($value == 'deleted' && empty($_COOKIE[$cookie_name]))
|
||||
return;
|
||||
|
||||
if (headers_sent())
|
||||
error_log('Could not set cookie. Headers already sent.');
|
||||
else
|
||||
setcookie($cookie_name, $value, $expires, '/', $base_domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a session_version = 3 style session object.
|
||||
*
|
||||
* @param $session
|
||||
* The session object.
|
||||
*
|
||||
* @return
|
||||
* The session object if it validates, NULL otherwise.
|
||||
*/
|
||||
protected function validateSessionObject($session) {
|
||||
// Make sure some essential fields exist.
|
||||
if (is_array($session) && isset($session['access_token']) && isset($session['sig'])) {
|
||||
// Validate the signature.
|
||||
$session_without_sig = $session;
|
||||
unset($session_without_sig['sig']);
|
||||
|
||||
$expected_sig = self::generateSignature(
|
||||
$session_without_sig,
|
||||
$this->getVariable('client_secret')
|
||||
);
|
||||
|
||||
if ($session['sig'] != $expected_sig) {
|
||||
error_log('Got invalid session signature in cookie.');
|
||||
$session = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$session = NULL;
|
||||
}
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since $_SERVER['REQUEST_URI'] is only available on Apache, we
|
||||
* generate an equivalent using other environment variables.
|
||||
*/
|
||||
function getRequestUri() {
|
||||
if (isset($_SERVER['REQUEST_URI'])) {
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
else {
|
||||
if (isset($_SERVER['argv'])) {
|
||||
$uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['argv'][0];
|
||||
}
|
||||
elseif (isset($_SERVER['QUERY_STRING'])) {
|
||||
$uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
|
||||
}
|
||||
else {
|
||||
$uri = $_SERVER['SCRIPT_NAME'];
|
||||
}
|
||||
}
|
||||
// Prevent multiple slashes to avoid cross site requests via the Form API.
|
||||
$uri = '/' . ltrim($uri, '/');
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Current URL.
|
||||
*
|
||||
* @return
|
||||
* The current URL.
|
||||
*/
|
||||
protected function getCurrentUri() {
|
||||
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'
|
||||
? 'https://'
|
||||
: 'http://';
|
||||
$current_uri = $protocol . $_SERVER['HTTP_HOST'] . $this->getRequestUri();
|
||||
$parts = parse_url($current_uri);
|
||||
|
||||
$query = '';
|
||||
if (!empty($parts['query'])) {
|
||||
$params = array();
|
||||
parse_str($parts['query'], $params);
|
||||
$params = array_filter($params);
|
||||
if (!empty($params)) {
|
||||
$query = '?' . http_build_query($params, NULL, '&');
|
||||
}
|
||||
}
|
||||
|
||||
// Use port if non default.
|
||||
$port = isset($parts['port']) &&
|
||||
(($protocol === 'http://' && $parts['port'] !== 80) || ($protocol === 'https://' && $parts['port'] !== 443))
|
||||
? ':' . $parts['port'] : '';
|
||||
|
||||
// Rebuild.
|
||||
return $protocol . $parts['host'] . $port . $parts['path'] . $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the URL for given path and parameters.
|
||||
*
|
||||
* @param $path
|
||||
* (optional) The path.
|
||||
* @param $params
|
||||
* (optional) The query parameters in associative array.
|
||||
*
|
||||
* @return
|
||||
* The URL for the given parameters.
|
||||
*/
|
||||
protected function getUri($path = '', $params = array()) {
|
||||
$url = $this->getVariable('services_uri') ? $this->getVariable('services_uri') : $this->getVariable('base_uri');
|
||||
|
||||
if (!empty($path))
|
||||
if (substr($path, 0, 4) == "http")
|
||||
$url = $path;
|
||||
else
|
||||
$url = rtrim($url, '/') . '/' . ltrim($path, '/');
|
||||
|
||||
if (!empty($params))
|
||||
$url .= '?' . http_build_query($params, NULL, '&');
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a signature for the given params and secret.
|
||||
*
|
||||
* @param $params
|
||||
* The parameters to sign.
|
||||
* @param $secret
|
||||
* The secret to sign with.
|
||||
*
|
||||
* @return
|
||||
* The generated signature
|
||||
*/
|
||||
protected function generateSignature($params, $secret) {
|
||||
// Work with sorted data.
|
||||
ksort($params);
|
||||
|
||||
// Generate the base string.
|
||||
$base_string = '';
|
||||
foreach ($params as $key => $value) {
|
||||
$base_string .= $key . '=' . $value;
|
||||
}
|
||||
$base_string .= $secret;
|
||||
|
||||
return md5($base_string);
|
||||
}
|
||||
}
|
||||
|
||||
class OAuth2Exception extends Exception {
|
||||
|
||||
/**
|
||||
* The result from the API server that represents the exception information.
|
||||
*/
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* Make a new API Exception with the given result.
|
||||
*
|
||||
* @param $result
|
||||
* The result from the API server.
|
||||
*/
|
||||
public function __construct($result) {
|
||||
$this->result = $result;
|
||||
|
||||
$code = isset($result['code']) ? $result['code'] : 0;
|
||||
|
||||
if (isset($result['error'])) {
|
||||
// OAuth 2.0 Draft 10 style
|
||||
$message = $result['error'];
|
||||
}
|
||||
elseif (isset($result['message'])) {
|
||||
// cURL style
|
||||
$message = $result['message'];
|
||||
}
|
||||
else {
|
||||
$message = 'Unknown Error. Check getResult()';
|
||||
}
|
||||
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated result object returned by the API server.
|
||||
*
|
||||
* @returns
|
||||
* The result from the API server.
|
||||
*/
|
||||
public function getResult() {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated type for the error. This will default to
|
||||
* 'Exception' when a type is not available.
|
||||
*
|
||||
* @return
|
||||
* The type for the error.
|
||||
*/
|
||||
public function getType() {
|
||||
if (isset($this->result['error'])) {
|
||||
$message = $this->result['error'];
|
||||
if (is_string($message)) {
|
||||
// OAuth 2.0 Draft 10 style
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
return 'Exception';
|
||||
}
|
||||
|
||||
/**
|
||||
* To make debugging easier.
|
||||
*
|
||||
* @returns
|
||||
* The string representation of the error.
|
||||
*/
|
||||
public function __toString() {
|
||||
$str = $this->getType() . ': ';
|
||||
if ($this->code != 0) {
|
||||
$str .= $this->code . ': ';
|
||||
}
|
||||
return $str . $this->message;
|
||||
}
|
||||
}
|
||||
@@ -1,802 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The default Cache Lifetime (in seconds).
|
||||
*/
|
||||
define("OAUTH2_DEFAULT_EXPIRES_IN", 3600*60*60*24);
|
||||
|
||||
/**
|
||||
* The default Base domain for the Cookie.
|
||||
*/
|
||||
define("OAUTH2_DEFAULT_BASE_DOMAIN", '');
|
||||
|
||||
/**
|
||||
* OAuth2.0 draft v10 client-side implementation.
|
||||
*
|
||||
* @author Originally written by Naitik Shah <naitik@facebook.com>.
|
||||
* @author Update to draft v10 by Edison Wong <hswong3i@pantarei-design.com>.
|
||||
*
|
||||
* @sa <a href="https://github.com/facebook/php-sdk">Facebook PHP SDK</a>.
|
||||
*/
|
||||
abstract class OAuth2Client {
|
||||
|
||||
/**
|
||||
* Array of persistent variables stored.
|
||||
*/
|
||||
protected $conf = array();
|
||||
|
||||
/**
|
||||
* Returns a persistent variable.
|
||||
*
|
||||
* To avoid problems, always use lower case for persistent variable names.
|
||||
*
|
||||
* @param $name
|
||||
* The name of the variable to return.
|
||||
* @param $default
|
||||
* The default value to use if this variable has never been set.
|
||||
*
|
||||
* @return
|
||||
* The value of the variable.
|
||||
*/
|
||||
public function getVariable($name, $default = NULL) {
|
||||
return isset($this->conf[$name]) ? $this->conf[$name] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a persistent variable.
|
||||
*
|
||||
* To avoid problems, always use lower case for persistent variable names.
|
||||
*
|
||||
* @param $name
|
||||
* The name of the variable to set.
|
||||
* @param $value
|
||||
* The value to set.
|
||||
*/
|
||||
public function setVariable($name, $value) {
|
||||
$this->conf[$name] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Stuff that should get overridden by subclasses.
|
||||
//
|
||||
// I don't want to make these abstract, because then subclasses would have
|
||||
// to implement all of them, which is too much work.
|
||||
//
|
||||
// So they're just stubs. Override the ones you need.
|
||||
|
||||
/**
|
||||
* Initialize a Drupal OAuth2.0 Application.
|
||||
*
|
||||
* @param $config
|
||||
* An associative array as below:
|
||||
* - base_uri: The base URI for the OAuth2.0 endpoints.
|
||||
* - code: (optional) The authorization code.
|
||||
* - username: (optional) The username.
|
||||
* - password: (optional) The password.
|
||||
* - client_id: (optional) The application ID.
|
||||
* - client_secret: (optional) The application secret.
|
||||
* - authorize_uri: (optional) The end-user authorization endpoint URI.
|
||||
* - access_token_uri: (optional) The token endpoint URI.
|
||||
* - services_uri: (optional) The services endpoint URI.
|
||||
* - cookie_support: (optional) TRUE to enable cookie support.
|
||||
* - base_domain: (optional) The domain for the cookie.
|
||||
* - file_upload_support: (optional) TRUE if file uploads are enabled.
|
||||
*/
|
||||
public function __construct($config = array()) {
|
||||
// We must set base_uri first.
|
||||
$this->setVariable('base_uri', $config['base_uri']);
|
||||
unset($config['base_uri']);
|
||||
|
||||
// Use predefined OAuth2.0 params, or get it from $_REQUEST.
|
||||
foreach (array('code', 'username', 'password') as $name) {
|
||||
if (isset($config[$name]))
|
||||
$this->setVariable($name, $config[$name]);
|
||||
else if (isset($_REQUEST[$name]) && !empty($_REQUEST[$name]))
|
||||
$this->setVariable($name, $_REQUEST[$name]);
|
||||
unset($config[$name]);
|
||||
}
|
||||
|
||||
// Endpoint URIs.
|
||||
foreach (array('authorize_uri', 'access_token_uri', 'services_uri') as $name) {
|
||||
if (isset($config[$name]))
|
||||
if (substr($config[$name], 0, 4) == "http")
|
||||
$this->setVariable($name, $config[$name]);
|
||||
else
|
||||
$this->setVariable($name, $this->getVariable('base_uri') . $config[$name]);
|
||||
unset($config[$name]);
|
||||
}
|
||||
|
||||
// Other else configurations.
|
||||
foreach ($config as $name => $value) {
|
||||
$this->setVariable($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get session object from custom method.
|
||||
*
|
||||
* By default we generate session object based on access_token response, or
|
||||
* if it is provided from server with $_REQUEST. For sure, if it is provided
|
||||
* by server it should follow our session object format.
|
||||
*
|
||||
* Session object provided by server can ensure the correct expires and
|
||||
* base_domain setup as predefined in server, also you may get more useful
|
||||
* information for custom functionality, too. BTW, this may require for
|
||||
* additional remote call overhead.
|
||||
*
|
||||
* You may wish to override this function with your custom version due to
|
||||
* your own server-side implementation.
|
||||
*
|
||||
* @param $access_token
|
||||
* (optional) A valid access token in associative array as below:
|
||||
* - access_token: A valid access_token generated by OAuth2.0
|
||||
* authorization endpoint.
|
||||
* - expires_in: (optional) A valid expires_in generated by OAuth2.0
|
||||
* authorization endpoint.
|
||||
* - refresh_token: (optional) A valid refresh_token generated by OAuth2.0
|
||||
* authorization endpoint.
|
||||
* - scope: (optional) A valid scope generated by OAuth2.0
|
||||
* authorization endpoint.
|
||||
*
|
||||
* @return
|
||||
* A valid session object in associative array for setup cookie, and
|
||||
* NULL if not able to generate it with custom method.
|
||||
*/
|
||||
protected function getSessionObject($access_token = NULL) {
|
||||
$session = NULL;
|
||||
|
||||
// Try generate local version of session cookie.
|
||||
if (!empty($access_token) && isset($access_token['access_token'])) {
|
||||
$session['access_token'] = $access_token['access_token'];
|
||||
$session['base_domain'] = $this->getVariable('base_domain', OAUTH2_DEFAULT_BASE_DOMAIN);
|
||||
$session['expires'] = isset($access_token['expires_in']) ? time() + $access_token['expires_in'] : time() + $this->getVariable('expires_in', OAUTH2_DEFAULT_EXPIRES_IN);
|
||||
$session['refresh_token'] = isset($access_token['refresh_token']) ? $access_token['refresh_token'] : '';
|
||||
$session['scope'] = isset($access_token['scope']) ? $access_token['scope'] : '';
|
||||
$session['secret'] = md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid())));
|
||||
|
||||
// Provide our own signature.
|
||||
$sig = self::generateSignature(
|
||||
$session,
|
||||
$this->getVariable('client_secret')
|
||||
);
|
||||
$session['sig'] = $sig;
|
||||
}
|
||||
|
||||
// Try loading session from $_REQUEST.
|
||||
if (!$session && isset($_REQUEST['session'])) {
|
||||
$session = json_decode(
|
||||
get_magic_quotes_gpc()
|
||||
? stripslashes($_REQUEST['session'])
|
||||
: $_REQUEST['session'],
|
||||
TRUE
|
||||
);
|
||||
}
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an API call.
|
||||
*
|
||||
* Support both OAuth2.0 or normal GET/POST API call, with relative
|
||||
* or absolute URI.
|
||||
*
|
||||
* If no valid OAuth2.0 access token found in session object, this function
|
||||
* will automatically switch as normal remote API call without "oauth_token"
|
||||
* parameter.
|
||||
*
|
||||
* Assume server reply in JSON object and always decode during return. If
|
||||
* you hope to issue a raw query, please use makeRequest().
|
||||
*
|
||||
* @param $path
|
||||
* The target path, relative to base_path/service_uri or an absolute URI.
|
||||
* @param $method
|
||||
* (optional) The HTTP method (default 'GET').
|
||||
* @param $params
|
||||
* (optional The GET/POST parameters.
|
||||
*
|
||||
* @return
|
||||
* The JSON decoded response object.
|
||||
*
|
||||
* @throws OAuth2Exception
|
||||
*/
|
||||
public function api($path, $method = 'GET', $params = array()) {
|
||||
if (is_array($method) && empty($params)) {
|
||||
$params = $method;
|
||||
$method = 'GET';
|
||||
}
|
||||
|
||||
// json_encode all params values that are not strings.
|
||||
foreach ($params as $key => $value) {
|
||||
if (!is_string($value)) {
|
||||
$params[$key] = json_encode($value);
|
||||
}
|
||||
}
|
||||
|
||||
$result = json_decode($this->makeOAuth2Request(
|
||||
$this->getUri($path),
|
||||
$method,
|
||||
$params
|
||||
), TRUE);
|
||||
|
||||
// Results are returned, errors are thrown.
|
||||
if (is_array($result) && isset($result['error'])) {
|
||||
$e = new OAuth2Exception($result);
|
||||
switch ($e->getType()) {
|
||||
// OAuth 2.0 Draft 10 style.
|
||||
case 'invalid_token':
|
||||
$this->setSession(NULL);
|
||||
default:
|
||||
$this->setSession(NULL);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// End stuff that should get overridden.
|
||||
|
||||
/**
|
||||
* Default options for cURL.
|
||||
*/
|
||||
public static $CURL_OPTS = array(
|
||||
CURLOPT_CONNECTTIMEOUT => 10,
|
||||
CURLOPT_RETURNTRANSFER => TRUE,
|
||||
CURLOPT_HEADER => TRUE,
|
||||
CURLOPT_TIMEOUT => 60,
|
||||
CURLOPT_USERAGENT => 'oauth2-draft-v10',
|
||||
CURLOPT_HTTPHEADER => array("Accept: application/json"),
|
||||
CURLOPT_SSL_VERIFYPEER => FALSE,
|
||||
CURLOPT_SSL_VERIFYHOST => FALSE
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the Session.
|
||||
*
|
||||
* @param $session
|
||||
* (optional) The session object to be set. NULL if hope to frush existing
|
||||
* session object.
|
||||
* @param $write_cookie
|
||||
* (optional) TRUE if a cookie should be written. This value is ignored
|
||||
* if cookie support has been disabled.
|
||||
*
|
||||
* @return
|
||||
* The current OAuth2.0 client-side instance.
|
||||
*/
|
||||
public function setSession($session = NULL, $write_cookie = TRUE) {
|
||||
$this->setVariable('_session', $this->validateSessionObject($session));
|
||||
$this->setVariable('_session_loaded', TRUE);
|
||||
if ($write_cookie) {
|
||||
$this->setCookieFromSession($this->getVariable('_session'));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the session object.
|
||||
*
|
||||
* This will automatically look for a signed session via custom method,
|
||||
* OAuth2.0 grant type with authorization_code, OAuth2.0 grant type with
|
||||
* password, or cookie that we had already setup.
|
||||
*
|
||||
* @return
|
||||
* The valid session object with OAuth2.0 infomration, and NULL if not
|
||||
* able to discover any cases.
|
||||
*/
|
||||
public function getSession() {
|
||||
if (!$this->getVariable('_session_loaded')) {
|
||||
$session = NULL;
|
||||
$write_cookie = TRUE;
|
||||
|
||||
// Try obtain login session by custom method.
|
||||
// $session = $this->getSessionObject(NULL);
|
||||
// $session = $this->validateSessionObject($session);
|
||||
|
||||
// grant_type == authorization_code.
|
||||
if (!$session && $this->getVariable('code')) {
|
||||
$access_token = $this->getAccessTokenFromAuthorizationCode($this->getVariable('code'));
|
||||
$session = $this->getSessionObject($access_token);
|
||||
$session = $this->validateSessionObject($session);
|
||||
}
|
||||
|
||||
// grant_type == password.
|
||||
if (!$session && $this->getVariable('username') && $this->getVariable('password')) {
|
||||
$access_token = $this->getAccessTokenFromPassword($this->getVariable('username'), $this->getVariable('password'));
|
||||
$session = $this->getSessionObject($access_token);
|
||||
$session = $this->validateSessionObject($session);
|
||||
}
|
||||
|
||||
// Try loading session from cookie if necessary.
|
||||
if (!$session && $this->getVariable('cookie_support')) {
|
||||
$cookie_name = $this->getSessionCookieName();
|
||||
if (isset($_COOKIE[$cookie_name])) {
|
||||
$session = array();
|
||||
parse_str(trim(
|
||||
get_magic_quotes_gpc()
|
||||
? stripslashes($_COOKIE[$cookie_name])
|
||||
: $_COOKIE[$cookie_name],
|
||||
'"'
|
||||
), $session);
|
||||
$session = $this->validateSessionObject($session);
|
||||
// Write only if we need to delete a invalid session cookie.
|
||||
$write_cookie = empty($session);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setSession($session, $write_cookie);
|
||||
}
|
||||
|
||||
return $this->getVariable('_session');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an OAuth2.0 access token from session.
|
||||
*
|
||||
* This will trigger getSession() and so we MUST initialize with required
|
||||
* configuration.
|
||||
*
|
||||
* @return
|
||||
* The valid OAuth2.0 access token, and NULL if not exists in session.
|
||||
*/
|
||||
public function getAccessToken() {
|
||||
$session = $this->getSession();
|
||||
return isset($session['access_token']) ? $session['access_token'] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access token from OAuth2.0 token endpoint with authorization code.
|
||||
*
|
||||
* This function will only be activated if both access token URI, client
|
||||
* identifier and client secret are setup correctly.
|
||||
*
|
||||
* @param $code
|
||||
* Authorization code issued by authorization server's authorization
|
||||
* endpoint.
|
||||
*
|
||||
* @return
|
||||
* A valid OAuth2.0 JSON decoded access token in associative array, and
|
||||
* NULL if not enough parameters or JSON decode failed.
|
||||
*/
|
||||
private function getAccessTokenFromAuthorizationCode($code) {
|
||||
if ($this->getVariable('access_token_uri') && $this->getVariable('client_id') && $this->getVariable('client_secret')) {
|
||||
$result = json_decode($this->makeRequest(
|
||||
$this->getVariable('access_token_uri'),
|
||||
'POST',
|
||||
array(
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => $this->getVariable('client_id'),
|
||||
'client_secret' => $this->getVariable('client_secret'),
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->getVariable( 'authorize_callback_uri') //$this->getCurrentUri(),
|
||||
)
|
||||
), TRUE);
|
||||
return $result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access token from OAuth2.0 token endpoint with basic user
|
||||
* credentials.
|
||||
*
|
||||
* This function will only be activated if both username and password
|
||||
* are setup correctly.
|
||||
*
|
||||
* @param $username
|
||||
* Username to be check with.
|
||||
* @param $password
|
||||
* Password to be check with.
|
||||
*
|
||||
* @return
|
||||
* A valid OAuth2.0 JSON decoded access token in associative array, and
|
||||
* NULL if not enough parameters or JSON decode failed.
|
||||
*/
|
||||
private function getAccessTokenFromPassword($username, $password) {
|
||||
if ($this->getVariable('access_token_uri') && $this->getVariable('client_id') && $this->getVariable('client_secret')) {
|
||||
return json_decode($this->makeRequest(
|
||||
$this->getVariable('access_token_uri'),
|
||||
'POST',
|
||||
array(
|
||||
'grant_type' => 'password',
|
||||
'client_id' => $this->getVariable('client_id'),
|
||||
'client_secret' => $this->getVariable('client_secret'),
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
)
|
||||
), TRUE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an OAuth2.0 Request.
|
||||
*
|
||||
* Automatically append "oauth_token" in query parameters if not yet
|
||||
* exists and able to discover a valid access token from session. Otherwise
|
||||
* just ignore setup with "oauth_token" and handle the API call AS-IS, and
|
||||
* so may issue a plain API call without OAuth2.0 protection.
|
||||
*
|
||||
* @param $path
|
||||
* The target path, relative to base_path/service_uri or an absolute URI.
|
||||
* @param $method
|
||||
* (optional) The HTTP method (default 'GET').
|
||||
* @param $params
|
||||
* (optional The GET/POST parameters.
|
||||
*
|
||||
* @return
|
||||
* The JSON decoded response object.
|
||||
*
|
||||
* @throws OAuth2Exception
|
||||
*/
|
||||
protected function makeOAuth2Request($path, $method = 'GET', $params = array()) {
|
||||
if ((!isset($params['oauth_token']) || empty($params['oauth_token'])) && $oauth_token = $this->getAccessToken()) {
|
||||
$params['oauth_token'] = $oauth_token;
|
||||
}
|
||||
return $this->makeRequest($path, $method, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an HTTP request.
|
||||
*
|
||||
* This method can be overriden by subclasses if developers want to do
|
||||
* fancier things or use something other than cURL to make the request.
|
||||
*
|
||||
* @param $path
|
||||
* The target path, relative to base_path/service_uri or an absolute URI.
|
||||
* @param $method
|
||||
* (optional) The HTTP method (default 'GET').
|
||||
* @param $params
|
||||
* (optional The GET/POST parameters.
|
||||
* @param $ch
|
||||
* (optional) An initialized curl handle
|
||||
*
|
||||
* @return
|
||||
* The JSON decoded response object.
|
||||
*/
|
||||
protected function makeRequest($path, $method = 'GET', $params = array(), $ch = NULL) {
|
||||
if (!$ch)
|
||||
$ch = curl_init();
|
||||
|
||||
$opts = self::$CURL_OPTS;
|
||||
if ($params) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$path .= '?' . http_build_query($params, NULL, '&');
|
||||
break;
|
||||
// Method override as we always do a POST.
|
||||
default:
|
||||
if ($this->getVariable('file_upload_support')) {
|
||||
$opts[CURLOPT_POSTFIELDS] = $params;
|
||||
}
|
||||
else {
|
||||
$opts[CURLOPT_POSTFIELDS] = http_build_query($params, NULL, '&');
|
||||
}
|
||||
}
|
||||
}
|
||||
$opts[CURLOPT_URL] = $path;
|
||||
|
||||
// Disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
|
||||
// for 2 seconds if the server does not support this header.
|
||||
if (isset($opts[CURLOPT_HTTPHEADER])) {
|
||||
$existing_headers = $opts[CURLOPT_HTTPHEADER];
|
||||
$existing_headers[] = 'Expect:';
|
||||
$opts[CURLOPT_HTTPHEADER] = $existing_headers;
|
||||
}
|
||||
else {
|
||||
$opts[CURLOPT_HTTPHEADER] = array('Expect:');
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, $opts);
|
||||
$result = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT
|
||||
error_log('Invalid or no certificate authority found, using bundled information');
|
||||
curl_setopt($ch, CURLOPT_CAINFO,
|
||||
dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
|
||||
$result = curl_exec($ch);
|
||||
}
|
||||
|
||||
if ($result === FALSE) {
|
||||
$e = new OAuth2Exception(array(
|
||||
'code' => curl_errno($ch),
|
||||
'message' => curl_error($ch),
|
||||
));
|
||||
curl_close($ch);
|
||||
throw $e;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
// Split the HTTP response into header and body.
|
||||
list($headers, $body) = explode("\r\n\r\n", $result);
|
||||
$headers = explode("\r\n", $headers);
|
||||
|
||||
// We catch HTTP/1.1 4xx or HTTP/1.1 5xx error response.
|
||||
if (strpos($headers[0], 'HTTP/1.1 4') !== FALSE || strpos($headers[0], 'HTTP/1.1 5') !== FALSE) {
|
||||
$result = array(
|
||||
'code' => 0,
|
||||
'message' => '',
|
||||
);
|
||||
|
||||
if (preg_match('/^HTTP\/1.1 ([0-9]{3,3}) (.*)$/', $headers[0], $matches)) {
|
||||
$result['code'] = $matches[1];
|
||||
$result['message'] = $matches[2];
|
||||
}
|
||||
|
||||
// In case retrun with WWW-Authenticate replace the description.
|
||||
foreach ($headers as $header) {
|
||||
if (preg_match("/^WWW-Authenticate:.*error='(.*)'/", $header, $matches)) {
|
||||
$result['error'] = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the cookie that contains the session object.
|
||||
*
|
||||
* @return
|
||||
* The cookie name.
|
||||
*/
|
||||
private function getSessionCookieName() {
|
||||
return 'oauth2_' . $this->getVariable('client_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a JS Cookie based on the _passed in_ session.
|
||||
*
|
||||
* It does not use the currently stored session - you need to explicitly
|
||||
* pass it in.
|
||||
*
|
||||
* @param $session
|
||||
* The session to use for setting the cookie.
|
||||
*/
|
||||
protected function setCookieFromSession($session = NULL) {
|
||||
if (!$this->getVariable('cookie_support'))
|
||||
return;
|
||||
|
||||
$cookie_name = $this->getSessionCookieName();
|
||||
$value = 'deleted';
|
||||
$expires = time() - 3600;
|
||||
$base_domain = $this->getVariable('base_domain', OAUTH2_DEFAULT_BASE_DOMAIN);
|
||||
|
||||
if ($session) {
|
||||
$value = '"' . http_build_query($session, NULL, '&') . '"';
|
||||
$base_domain = isset($session['base_domain']) ? $session['base_domain'] : $base_domain;
|
||||
$expires = isset($session['expires']) ? $session['expires'] : time() + $this->getVariable('expires_in', OAUTH2_DEFAULT_EXPIRES_IN);
|
||||
}
|
||||
|
||||
// Prepend dot if a domain is found.
|
||||
if ($base_domain)
|
||||
$base_domain = '.' . $base_domain;
|
||||
|
||||
// If an existing cookie is not set, we dont need to delete it.
|
||||
if ($value == 'deleted' && empty($_COOKIE[$cookie_name]))
|
||||
return;
|
||||
|
||||
if (headers_sent())
|
||||
error_log('Could not set cookie. Headers already sent.');
|
||||
else
|
||||
setcookie($cookie_name, $value, $expires, '/', $base_domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a session_version = 3 style session object.
|
||||
*
|
||||
* @param $session
|
||||
* The session object.
|
||||
*
|
||||
* @return
|
||||
* The session object if it validates, NULL otherwise.
|
||||
*/
|
||||
protected function validateSessionObject($session) {
|
||||
// Make sure some essential fields exist.
|
||||
if (is_array($session) && isset($session['access_token']) && isset($session['sig'])) {
|
||||
// Validate the signature.
|
||||
$session_without_sig = $session;
|
||||
unset($session_without_sig['sig']);
|
||||
|
||||
$expected_sig = self::generateSignature(
|
||||
$session_without_sig,
|
||||
$this->getVariable('client_secret')
|
||||
);
|
||||
|
||||
if ($session['sig'] != $expected_sig) {
|
||||
error_log('Got invalid session signature in cookie.');
|
||||
$session = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$session = NULL;
|
||||
}
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since $_SERVER['REQUEST_URI'] is only available on Apache, we
|
||||
* generate an equivalent using other environment variables.
|
||||
*/
|
||||
function getRequestUri() {
|
||||
if (isset($_SERVER['REQUEST_URI'])) {
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
else {
|
||||
if (isset($_SERVER['argv'])) {
|
||||
$uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['argv'][0];
|
||||
}
|
||||
elseif (isset($_SERVER['QUERY_STRING'])) {
|
||||
$uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
|
||||
}
|
||||
else {
|
||||
$uri = $_SERVER['SCRIPT_NAME'];
|
||||
}
|
||||
}
|
||||
// Prevent multiple slashes to avoid cross site requests via the Form API.
|
||||
$uri = '/' . ltrim($uri, '/');
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Current URL.
|
||||
*
|
||||
* @return
|
||||
* The current URL.
|
||||
*/
|
||||
protected function getCurrentUri() {
|
||||
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'
|
||||
? 'https://'
|
||||
: 'http://';
|
||||
$current_uri = $protocol . $_SERVER['HTTP_HOST'] . $this->getRequestUri();
|
||||
$parts = parse_url($current_uri);
|
||||
|
||||
$query = '';
|
||||
if (!empty($parts['query'])) {
|
||||
$params = array();
|
||||
parse_str($parts['query'], $params);
|
||||
$params = array_filter($params);
|
||||
if (!empty($params)) {
|
||||
$query = '?' . http_build_query($params, NULL, '&');
|
||||
}
|
||||
}
|
||||
|
||||
// Use port if non default.
|
||||
$port = isset($parts['port']) &&
|
||||
(($protocol === 'http://' && $parts['port'] !== 80) || ($protocol === 'https://' && $parts['port'] !== 443))
|
||||
? ':' . $parts['port'] : '';
|
||||
|
||||
// Rebuild.
|
||||
return $protocol . $parts['host'] . $port . $parts['path'] . $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the URL for given path and parameters.
|
||||
*
|
||||
* @param $path
|
||||
* (optional) The path.
|
||||
* @param $params
|
||||
* (optional) The query parameters in associative array.
|
||||
*
|
||||
* @return
|
||||
* The URL for the given parameters.
|
||||
*/
|
||||
protected function getUri($path = '', $params = array()) {
|
||||
$url = $this->getVariable('services_uri') ? $this->getVariable('services_uri') : $this->getVariable('base_uri');
|
||||
|
||||
if (!empty($path))
|
||||
if (substr($path, 0, 4) == "http")
|
||||
$url = $path;
|
||||
else
|
||||
$url = rtrim($url, '/') . '/' . ltrim($path, '/');
|
||||
|
||||
if (!empty($params))
|
||||
$url .= '?' . http_build_query($params, NULL, '&');
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a signature for the given params and secret.
|
||||
*
|
||||
* @param $params
|
||||
* The parameters to sign.
|
||||
* @param $secret
|
||||
* The secret to sign with.
|
||||
*
|
||||
* @return
|
||||
* The generated signature
|
||||
*/
|
||||
protected function generateSignature($params, $secret) {
|
||||
// Work with sorted data.
|
||||
ksort($params);
|
||||
|
||||
// Generate the base string.
|
||||
$base_string = '';
|
||||
foreach ($params as $key => $value) {
|
||||
$base_string .= $key . '=' . $value;
|
||||
}
|
||||
$base_string .= $secret;
|
||||
|
||||
return md5($base_string);
|
||||
}
|
||||
}
|
||||
|
||||
class OAuth2Exception extends Exception {
|
||||
|
||||
/**
|
||||
* The result from the API server that represents the exception information.
|
||||
*/
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* Make a new API Exception with the given result.
|
||||
*
|
||||
* @param $result
|
||||
* The result from the API server.
|
||||
*/
|
||||
public function __construct($result) {
|
||||
$this->result = $result;
|
||||
|
||||
$code = isset($result['code']) ? $result['code'] : 0;
|
||||
|
||||
if (isset($result['error'])) {
|
||||
// OAuth 2.0 Draft 10 style
|
||||
$message = $result['error'];
|
||||
}
|
||||
elseif (isset($result['message'])) {
|
||||
// cURL style
|
||||
$message = $result['message'];
|
||||
}
|
||||
else {
|
||||
$message = 'Unknown Error. Check getResult()';
|
||||
}
|
||||
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated result object returned by the API server.
|
||||
*
|
||||
* @returns
|
||||
* The result from the API server.
|
||||
*/
|
||||
public function getResult() {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated type for the error. This will default to
|
||||
* 'Exception' when a type is not available.
|
||||
*
|
||||
* @return
|
||||
* The type for the error.
|
||||
*/
|
||||
public function getType() {
|
||||
if (isset($this->result['error'])) {
|
||||
$message = $this->result['error'];
|
||||
if (is_string($message)) {
|
||||
// OAuth 2.0 Draft 10 style
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
return 'Exception';
|
||||
}
|
||||
|
||||
/**
|
||||
* To make debugging easier.
|
||||
*
|
||||
* @returns
|
||||
* The string representation of the error.
|
||||
*/
|
||||
public function __toString() {
|
||||
$str = $this->getType() . ': ';
|
||||
if ($this->code != 0) {
|
||||
$str .= $this->code . ': ';
|
||||
}
|
||||
return $str . $this->message;
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
require_once( dirname(__FILE__) . '/OAuth2Client.php' );
|
||||
|
||||
class vkClient extends OAuth2Client
|
||||
{
|
||||
|
||||
private $_allowed_scopes = array(
|
||||
'notify', // Пользователь разрешил отправлять ему уведомления.
|
||||
'friends', // Доступ к друзьям.
|
||||
'photos', // Доступ к фотографиям.
|
||||
'audio', // Доступ к аудиозаписям.
|
||||
'video', // Доступ к видеозаписям.
|
||||
'notes', // Доступ заметкам пользователя.
|
||||
'pages', // Доступ к wiki-страницам.
|
||||
'offers', // Доступ к предложениям (устаревшие методы).
|
||||
'questions', // Доступ к вопросам (устаревшие методы).
|
||||
'wall', // Доступ к обычным и расширенным методам работы со стеной.
|
||||
'messages', // (для Standalone-приложений) Доступ к расширенным методам работы с сообщениями.
|
||||
'offline', // Доступ к API в любое время со стороннего сервера.
|
||||
);
|
||||
|
||||
public function __construct($config = array())
|
||||
{
|
||||
$configured_scopes = array( 'offline' );
|
||||
|
||||
if ( isset($config['scope']) )
|
||||
{
|
||||
$config_scopes = array_map( 'trim', explode(',', $config['scope']) );
|
||||
|
||||
foreach( $config_scopes as $scope )
|
||||
{
|
||||
if ( in_array( $scope, $this->_allowed_scopes ) )
|
||||
{
|
||||
$configured_scopes[] = $scope;
|
||||
}
|
||||
}
|
||||
|
||||
unset( $config['scope'] );
|
||||
}
|
||||
|
||||
$this->setVariable( 'scope', implode(',', $configured_scopes) );
|
||||
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение ссылки на авторизацию
|
||||
*
|
||||
* @link http://vk.com/developers.php?o=-1&p=%C0%E2%F2%EE%F0%E8%E7%E0%F6%E8%FF%20%F1%E0%E9%F2%EE%E2
|
||||
*/
|
||||
public function getAuthorizeUrl($params = array())
|
||||
{
|
||||
$params = array_merge(
|
||||
array(
|
||||
'client_id' => $this->getVariable('client_id'),
|
||||
// здесь возможно нужен urlencode + уникальный ключ пользователя
|
||||
'redirect_uri' => $this->getVariable('authorize_callback_uri'),
|
||||
'response_type' => ( $this->getVariable('logintype') == 'client' ) ? 'token' : 'code',
|
||||
'scope' => $this->getVariable( 'scope' ),
|
||||
), $params);
|
||||
|
||||
return $this->getUri( $this->getVariable('authorize_uri'), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Авторизационный сервер vkontakte нам какбы отвечает
|
||||
* {"access_token":"533bacf01e11f55b536a565b57531ac114461ae8736d6506a3", "expires_in":43200, "user_id":6492}
|
||||
*
|
||||
* @link http://vk.com/developers.php?o=-1&p=%C0%E2%F2%EE%F0%E8%E7%E0%F6%E8%FF%20%F1%E0%E9%F2%EE%E2
|
||||
*/
|
||||
protected function getSessionObject($access_token = NULL)
|
||||
{
|
||||
$session = NULL;
|
||||
|
||||
// Готовим данные для куки
|
||||
if (!empty($access_token) && isset($access_token['access_token'])) {
|
||||
$session['access_token'] = $access_token['access_token'];
|
||||
$session['expires'] = ( isset($access_token['expires_in']) && $access_token['expires_in'] ) ? time() + $access_token['expires_in'] : time() + $this->getVariable('expires_in', OAUTH2_DEFAULT_EXPIRES_IN);
|
||||
$session['refresh_token'] = isset($access_token['refresh_token']) ? $access_token['refresh_token'] : '';
|
||||
$session['user_id'] = isset($access_token['user_id']) ? $access_token['user_id'] : 0;
|
||||
|
||||
$sig = self::generateSignature(
|
||||
$session,
|
||||
$this->getVariable('client_secret')
|
||||
);
|
||||
$session['sig'] = $sig;
|
||||
}
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* У vkontakte вместо oauth_token имеем access_token
|
||||
*
|
||||
* @link http://vk.com/developers.php?o=-1&p=%C2%FB%EF%EE%EB%ED%E5%ED%E8%E5%20%E7%E0%EF%F0%EE%F1%EE%E2%20%EA%20API
|
||||
*/
|
||||
protected function makeOAuth2Request($path, $method = 'GET', $params = array())
|
||||
{
|
||||
if ((!isset($params['access_token']) || empty($params['access_token'])) && $oauth_token = $this->getAccessToken())
|
||||
{
|
||||
$params['access_token'] = $oauth_token;
|
||||
}
|
||||
return $this->makeRequest($path, $method, $params);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user