Authored by whb
Commit 3499daa8b2335315bda5dd2c9072f65a88f63e51 1 parent 19b359bf master ... develop feature/4LevelAddr feature/birthCoupon feature/cartEvent feature/colorLength feature/commentImgShow feature/deleteMark feature/favShopDelAll feature/help feature/jitTip feature/paySuccess feature/seoUrl feature/shoppingCart feature/wholesaleFrom5.3 gray hotfix/firefoxCart hotfix/govLink hotfix/newPy hotfix/serviceSwitch hotfix/studentSwitch hotfix/yas2.1.2 release/5.3.1 release/5.4 release/5.4.1 release/5.5 5.4.3 5.4.2 5.4.1 5.4.0 5.3.8 5.3.7 5.3.6 5.3.5 5.3.4 5.3.3 5.3.2 5.3.1 5.3.0 5.2.4 5.2.3 5.2.2 5.2.1 5.2.0 5.1.5 5.1.4 5.1.2 5.1.1 5.1.0 5.0.4 5.0.3 5.0.2 5.0.1 5.0.0.before 4.9.24 4.9.23 4.9.22 4.9.21 4.9.20 4.9.19 4.9.18 4.9.17.encryBugsFenliu 4.9.16 4.9.15 4.9.15.pinyou 4.9.14 4.9.14.icon 4.9.13 4.9.12 4.9.11 4.9.10 4.9.1.1 4.9.1.0 4.9.1 4.8.15 4.8.13 4.8.12 4.8.8.2 4.8.8.1 4.8.8 4.8.5 4.8.3 4.8.2 4.8.bak 4.7.2 4.6.2.1 4.6.2 4.6 4 1.3.22 1.3.21 1.3.20 1.3.19 1.3.18 wap.3.2.5 wap.1.4.22 wap.1.4.21 wap.1.4.20 wap.1.4.19 wap.1.4.18 wap.1.4.17 wap.1.4.16.3 wap.1.4.16.2 wap.1.4.16.1 wap.1.4.16 wap.1.4.15 wap.1.4.14 wap.1.4.13 wap.1.4.12 wap.1.4.11 wap.1.4.10 wap.1.4.9 wap.1.4.8 wap.1.4.7 wap.1.4.6 wap.1.4.5 wap.1.4.4 wap.1.4.3 wap.1.4.2 wap.1.4.1 wap.1.4.0 pchttps pc4.8.9 pc4.5 pc.1.4.24 pc.1.4.23 pc.1.4.22 pc.1.4.21 pc.1.4.20 pc.1.4.19 pc.1.4.18 pc.1.4.17 pc.1.4.16 pc.1.4.15 pc.1.4.14 pc.1.4.13 pc.1.4.12 pc.1.4.11 pc.1.4.10 pc.1.4.9 pc.1.4.8 pc.1.4.7 pc.1.4.6 pc.1.0.7 pc.1.0.6 pc.1.0.5 pc.1.0.4 pc.1.0.3 pc.1.0.2 pc.1.0.1 pc.1.0.0 list fix-ip-login-limit fix-ip-limit

PC重构

Too many changes to show.

To preserve performance only 15 of 15+ files are displayed.

<?php
namespace Plugin;
/**
* LightnCandy static class for compiled template runtime methods.
*/
class LCRun3
{
const DEBUG_ERROR_LOG = 1;
const DEBUG_ERROR_EXCEPTION = 2;
const DEBUG_TAGS = 4;
const DEBUG_TAGS_ANSI = 12;
const DEBUG_TAGS_HTML = 20;
/**
* LightnCandy runtime method for output debug info.
*
* @param string $v expression
* @param string $f runtime function name
* @param array<string,array|string|integer> $cx render time context
*
* @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS), 'lcrun' => 'LCRun3'), ''
* @expect '<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->' when input '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML), 'lcrun' => 'LCRun3'), false, false, function () {return 'A';}
*/
public static function debug($v, $f, $cx)
{
$params = array_slice(func_get_args(), 2);
$r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "{$cx['lcrun']}::$f"), $params);
if ($cx['flags']['debug'] & self::DEBUG_TAGS) {
$ansi = $cx['flags']['debug'] & (self::DEBUG_TAGS_ANSI - self::DEBUG_TAGS);
$html = $cx['flags']['debug'] & (self::DEBUG_TAGS_HTML - self::DEBUG_TAGS);
$cs = ($html ? (($r !== '') ? '<!!--OK((-->' : '<!--MISSED((-->') : '')
. ($ansi ? (($r !== '') ? "\033[0;32m" : "\033[0;31m") : '');
$ce = ($html ? '<!--))-->' : '')
. ($ansi ? "\033[0m" : '');
switch ($f) {
case 'sec':
case 'ifv':
case 'unl':
case 'wi':
if ($r == '') {
if ($ansi) {
$r = "\033[0;33mSKIPPED\033[0m";
}
if ($html) {
$r = '<!--SKIPPED-->';
}
}
return "$cs{{#{$v}}}$ce{$r}$cs{{/{$v}}}$ce";
default:
return "$cs{{{$v}}}$ce";
}
} else {
return $r;
}
}
/**
* LightnCandy runtime method for missing data error.
*
* @param array<string,array|string|integer> $cx render time context
* @param string $v expression
*/
public static function miss($cx, $v)
{
$e = "LCRun3: $v is not exist";
if ($cx['flags']['debug'] & self::DEBUG_ERROR_LOG) {
error_log($e);
return;
}
if ($cx['flags']['debug'] & self::DEBUG_ERROR_EXCEPTION) {
throw new Exception($e);
}
}
/**
* LightnCandy runtime method for variable lookup. It is slower and only be used for instance property or method detection.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer> $base current variable context
* @param array<string|integer> $path array of names for path
*
* @return null|string Return the value or null when not found
*
* @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), 0, array('a', 'b')
* @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0), 'mustlok' => 0), array('a' => array('b' => 3)), array('a', 'b')
* @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), (Object) array('a' => array('b' => 3)), array('a', 'b')
* @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 1, 'method' => 0, 'mustlok' => 0)), (Object) array('a' => array('b' => 3)), array('a', 'b')
*/
public static function v($cx, $base, $path)
{
$count = count($cx['scopes']);
while ($base) {
$v = $base;
foreach ($path as $name) {
if (is_array($v) && isset($v[$name])) {
$v = $v[$name];
continue;
}
if (is_object($v)) {
if ($cx['flags']['prop'] && isset($v->$name)) {
$v = $v->$name;
continue;
}
if ($cx['flags']['method'] && is_callable(array($v, $name))) {
$v = $v->$name();
continue;
}
}
if ($cx['flags']['mustlok']) {
unset($v);
break;
}
return null;
}
if (isset($v)) {
return $v;
}
$count--;
switch ($count) {
case -1:
$base = $cx['sp_vars']['root'];
break;
case -2:
return null;
default:
$base = $cx['scopes'][$count];
}
}
}
/**
* LightnCandy runtime method for {{#if var}}.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be tested
*
* @return boolean Return true when the value is not null nor false.
*
* @expect false when input array(), null
* @expect false when input array(), 0
* @expect false when input array(), false
* @expect true when input array(), true
* @expect true when input array(), 1
* @expect false when input array(), ''
* @expect false when input array(), array()
* @expect true when input array(), array('')
* @expect true when input array(), array(0)
*/
public static function ifvar($cx, $v)
{
return !is_null($v) && ($v !== false) && ($v !== 0) && ($v !== 0.0) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
}
/**
* LightnCandy runtime method for {{#if var}} when {{../var}} used.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be tested
* @param array<array|string|integer> $in input data with current scope
* @param Closure|null $truecb callback function when test result is true
* @param Closure|null $falsecb callback function when test result is false
*
* @return string The rendered string of the section
*
* @expect '' when input array('scopes' => array()), null, array(), null
* @expect '' when input array('scopes' => array()), null, array(), function () {return 'Y';}
* @expect 'Y' when input array('scopes' => array()), 1, array(), function () {return 'Y';}
* @expect 'N' when input array('scopes' => array()), null, array(), function () {return 'Y';}, function () {return 'N';}
*/
public static function ifv($cx, $v, $in, $truecb, $falsecb = null)
{
$ret = '';
if (self::ifvar($cx, $v)) {
if ($truecb) {
$cx['scopes'][] = $in;
$ret = $truecb($cx, $in);
array_pop($cx['scopes']);
}
} else {
if ($falsecb) {
$cx['scopes'][] = $in;
$ret = $falsecb($cx, $in);
array_pop($cx['scopes']);
}
}
return $ret;
}
/**
* LightnCandy runtime method for {{#unless var}} when {{../var}} used.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $var value be tested
* @param array<array|string|integer>|string|integer|null $in input data with current scope
* @param Closure $truecb callback function when test result is true
* @param Closure|null $falsecb callback function when test result is false
*
* @return string Return rendered string when the value is not null nor false.
*
* @expect '' when input array('scopes' => array()), null, array(), null
* @expect 'Y' when input array('scopes' => array()), null, array(), function () {return 'Y';}
* @expect '' when input array('scopes' => array()), 1, array(), function () {return 'Y';}
* @expect 'Y' when input array('scopes' => array()), null, array(), function () {return 'Y';}, function () {return 'N';}
* @expect 'N' when input array('scopes' => array()), true, array(), function () {return 'Y';}, function () {return 'N';}
*/
public static function unl($cx, $var, $in, $truecb, $falsecb = null)
{
return self::ifv($cx, $var, $in, $falsecb, $truecb);
}
/**
* LightnCandy runtime method for {{^var}} inverted section.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be tested
*
* @return boolean Return true when the value is not null nor false.
*
* @expect true when input array(), null
* @expect false when input array(), 0
* @expect true when input array(), false
* @expect false when input array(), 'false'
* @expect true when input array(), array()
* @expect false when input array(), array('1')
*/
public static function isec($cx, $v)
{
return is_null($v) || ($v === false) || (is_array($v) && (count($v) === 0));
}
/**
* LightnCandy runtime method for {{{var}}} .
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be output
*
* @return string The raw value of the specified variable
*
* @expect true when input array('flags' => array('jstrue' => 0)), true
* @expect 'true' when input array('flags' => array('jstrue' => 1)), true
* @expect '' when input array('flags' => array('jstrue' => 0)), false
* @expect 'false' when input array('flags' => array('jstrue' => 1)), false
* @expect 'false' when input array('flags' => array('jstrue' => 1)), false, true
* @expect 'Array' when input array('flags' => array('jstrue' => 1, 'jsobj' => 0)), array('a', 'b')
* @expect 'a,b' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a', 'b')
* @expect '[object Object]' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a', 'c' => 'b')
* @expect '[object Object]' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('c' => 'b')
* @expect 'a,true' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a', true)
* @expect 'a,1' when input array('flags' => array('jstrue' => 0, 'jsobj' => 1)), array('a',true)
* @expect 'a,' when input array('flags' => array('jstrue' => 0, 'jsobj' => 1)), array('a',false)
* @expect 'a,false' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a',false)
*/
public static function raw($cx, $v)
{
if ($v === true) {
if ($cx['flags']['jstrue']) {
return 'true';
}
}
if (($v === false)) {
if ($cx['flags']['jstrue']) {
return 'false';
}
}
if (is_array($v)) {
if ($cx['flags']['jsobj']) {
if (count(array_diff_key($v, array_keys(array_keys($v)))) > 0) {
return '[object Object]';
} else {
$ret = array();
foreach ($v as $k => $vv) {
$ret[] = self::raw($cx, $vv);
}
return join(',', $ret);
}
} else {
return 'Array';
}
}
return "$v";
}
/**
* LightnCandy runtime method for {{var}} .
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $var value to be htmlencoded
*
* @return string The htmlencoded value of the specified variable
*
* @expect 'a' when input array(), 'a'
* @expect 'a&amp;b' when input array(), 'a&b'
* @expect 'a&#039;b' when input array(), 'a\'b'
*/
public static function enc($cx, $var)
{
return htmlentities(self::raw($cx, $var), ENT_QUOTES, 'UTF-8');
}
/**
* LightnCandy runtime method for {{var}} , and deal with single quote to same as handlebars.js .
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $var value to be htmlencoded
*
* @return string The htmlencoded value of the specified variable
*
* @expect 'a' when input array(), 'a'
* @expect 'a&amp;b' when input array(), 'a&b'
* @expect 'a&#x27;b' when input array(), 'a\'b'
* @expect '&#x60;a&#x27;b' when input array(), '`a\'b'
*/
public static function encq($cx, $var)
{
return preg_replace('/`/', '&#x60;', preg_replace('/&#039;/', '&#x27;', htmlentities(self::raw($cx, $var), ENT_QUOTES, 'UTF-8')));
}
/**
* LightnCandy runtime method for {{#var}} section.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value for the section
* @param array<array|string|integer>|string|integer|null $in input data with current scope
* @param boolean $each true when rendering #each
* @param Closure $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the section
*
* @expect '' when input array('flags' => array('spvar' => 0)), false, false, false, function () {return 'A';}
* @expect '' when input array('flags' => array('spvar' => 0)), null, null, false, function () {return 'A';}
* @expect 'A' when input array('flags' => array('spvar' => 0)), true, true, false, function () {return 'A';}
* @expect 'A' when input array('flags' => array('spvar' => 0)), 0, 0, false, function () {return 'A';}
* @expect '-a=' when input array('flags' => array('spvar' => 0)), array('a'), array('a'), false, function ($c, $i) {return "-$i=";}
* @expect '-a=-b=' when input array('flags' => array('spvar' => 0)), array('a','b'), array('a','b'), false, function ($c, $i) {return "-$i=";}
* @expect '' when input array('flags' => array('spvar' => 0)), 'abc', 'abc', true, function ($c, $i) {return "-$i=";}
* @expect '-b=' when input array('flags' => array('spvar' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
* @expect '1' when input array('flags' => array('spvar' => 0)), 'b', 'b', false, function ($c, $i) {return count($i);}
* @expect '1' when input array('flags' => array('spvar' => 0)), 1, 1, false, function ($c, $i) {return print_r($i, true);}
* @expect '0' when input array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return print_r($i, true);}
* @expect '{"b":"c"}' when input array('flags' => array('spvar' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), array(), 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), array(), 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), false, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), false, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), '', 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'cb' when input array('flags' => array('spvar' => 0)), '', 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), 0, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'cb' when input array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), new stdClass, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'cb' when input array('flags' => array('spvar' => 0)), new stdClass, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect '268' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
* @expect '038' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
*/
public static function sec($cx, $v, $in, $each, $cb, $else = null)
{
$isAry = is_array($v) || ($v instanceof ArrayObject);
$isTrav = $v instanceof Traversable;
$loop = $each;
$keys = null;
$last = null;
$isObj = false;
if ($isAry && $else !== null && count($v) === 0) {
$cx['scopes'][] = $in;
$ret = $else($cx, $in);
array_pop($cx['scopes']);
return $ret;
}
// #var, detect input type is object or not
if (!$loop && $isAry) {
$keys = array_keys($v);
$loop = (count(array_diff_key($v, array_keys($keys))) == 0);
$isObj = !$loop;
}
if (($loop && $isAry) || $isTrav) {
if ($each && !$isTrav) {
// Detect input type is object or not when never done once
if ($keys == null) {
$keys = array_keys($v);
$isObj = (count(array_diff_key($v, array_keys($keys))) > 0);
}
}
$ret = array();
$cx['scopes'][] = $in;
$i = 0;
if ($cx['flags']['spvar']) {
$old_spvar = $cx['sp_vars'];
$cx['sp_vars'] = array(
'_parent' => $old_spvar,
'root' => $old_spvar['root'],
);
if (!$isTrav) {
$last = count($keys) - 1;
}
}
foreach ($v as $index => $raw) {
if ($cx['flags']['spvar']) {
$cx['sp_vars']['first'] = ($i === 0);
$cx['sp_vars']['last'] = ($i == $last);
$cx['sp_vars']['key'] = $index;
$cx['sp_vars']['index'] = $i;
$i++;
}
$ret[] = $cb($cx, $raw);
}
if ($cx['flags']['spvar']) {
if ($isObj) {
unset($cx['sp_vars']['key']);
} else {
unset($cx['sp_vars']['last']);
}
unset($cx['sp_vars']['index']);
unset($cx['sp_vars']['first']);
$cx['sp_vars'] = $old_spvar;
}
array_pop($cx['scopes']);
return join('', $ret);
}
if ($each) {
if ($else !== null) {
$cx['scopes'][] = $in;
$ret = $else($cx, $v);
array_pop($cx['scopes']);
return $ret;
}
return '';
}
if ($isAry) {
$cx['scopes'][] = $in;
$ret = $cb($cx, $v);
array_pop($cx['scopes']);
return $ret;
}
if ($v === true) {
return $cb($cx, $in);
}
if (!is_null($v) && ($v !== false)) {
return $cb($cx, $v);
}
if ($else !== null) {
$cx['scopes'][] = $in;
$ret = $else($cx, $in);
array_pop($cx['scopes']);
return $ret;
}
return '';
}
/**
* LightnCandy runtime method for {{#with var}} .
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be the new context
* @param array<array|string|integer>|string|integer|null $in input data with current scope
* @param Closure $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the token
*
* @expect '' when input array(), false, false, function () {return 'A';}
* @expect '' when input array(), null, null, function () {return 'A';}
* @expect '{"a":"b"}' when input array(), array('a'=>'b'), array('a'=>'c'), function ($c, $i) {return json_encode($i);}
* @expect '-b=' when input array(), 'b', array('a'=>'b'), function ($c, $i) {return "-$i=";}
*/
public static function wi($cx, $v, $in, $cb, $else = null)
{
if (($v === false) || ($v === null)) {
return $else ? $else($cx, $in) : '';
}
$cx['scopes'][] = $in;
$ret = $cb($cx, $v);
array_pop($cx['scopes']);
return $ret;
}
/**
* LightnCandy runtime method for {{> partial}} .
*
* @param array<string,array|string|integer> $cx render time context
* @param string $p partial name
* @param array<array|string|integer>|string|integer|null $v value to be the new context
*
* @return string The rendered string of the partial
*
*/
public static function p($cx, $p, $v, $sp = '')
{
$param = $v[0][0];
if (is_array($v[1])) {
if (is_array($v[0][0])) {
$param = array_merge($v[0][0], $v[1]);
} else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($v[0][0])) {
foreach ($v[1] as $i => $v) {
$param->$i = $v;
}
}
}
return call_user_func($cx['partials'][$p], $cx, $param, $sp);
}
/**
* LightnCandy runtime method for custom helpers.
*
* @param array<string,array|string|integer> $cx render time context
* @param string $ch the name of custom helper to be executed
* @param array<array> $vars variables for the helper
* @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
*
* @return string The rendered string of the token
*
* @expect '=-=' when input array('helpers' => array('a' => function ($i) {return "=$i[0]=";})), 'a', array(array('-'),array()), 'raw'
* @expect '=&amp;=' when input array('helpers' => array('a' => function ($i) {return "=$i[0]=";})), 'a', array(array('&'),array()), 'enc'
* @expect '=&#x27;=' when input array('helpers' => array('a' => function ($i) {return "=$i[0]=";})), 'a', array(array('\''),array()), 'encq'
* @expect '=b=' when input array('helpers' => array('a' => function ($i,$j) {return "={$j['a']}=";})), 'a', array(array(),array('a' => 'b')), 'raw'
*/
public static function ch($cx, $ch, $vars, $op)
{
return self::chret(call_user_func_array($cx['helpers'][$ch], $vars), $op);
}
/**
* LightnCandy runtime method to handle response of custom helpers.
*
* @param string|array<string,array|string|integer> $ret return value from custom helper
* @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
*
* @return string The rendered string of the token
*
* @expect '=&=' when input '=&=', 'raw'
* @expect '=&amp;&#039;=' when input '=&\'=', 'enc'
* @expect '=&amp;&#x27;=' when input '=&\'=', 'encq'
* @expect '=&amp;&#039;=' when input array('=&\'='), 'enc'
* @expect '=&amp;&#x27;=' when input array('=&\'='), 'encq'
* @expect '=&amp;=' when input array('=&=', false), 'enc'
* @expect '=&=' when input array('=&=', false), 'raw'
* @expect '=&=' when input array('=&=', 'raw'), 'enc'
* @expect '=&amp;&#x27;=' when input array('=&\'=', 'encq'), 'raw'
*/
public static function chret($ret, $op)
{
if (is_array($ret)) {
if (isset($ret[1]) && $ret[1]) {
$op = $ret[1];
}
$ret = $ret[0];
}
switch ($op) {
case 'enc':
return htmlentities($ret, ENT_QUOTES, 'UTF-8');
case 'encq':
return preg_replace('/&#039;/', '&#x27;', htmlentities($ret, ENT_QUOTES, 'UTF-8'));
}
return $ret;
}
/**
* LightnCandy runtime method for Handlebars.js style custom helpers.
*
* @param array<string,array|string|integer> $cx render time context
* @param string $ch the name of custom helper to be executed
* @param array<array|string|integer>|string|integer|null $vars variables for the helper
* @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
* @param boolean $inverted the logic will be inverted
* @param Closure|null $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the token
*/
public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null)
{
$isBlock = (is_object($cb) && ($cb instanceof Closure));
$args = $vars[0];
$options = array(
'name' => $ch,
'hash' => $vars[1],
'_this' => $isBlock ? $op : $inverted,
);
// $invert the logic
if ($inverted) {
$tmp = $else;
$else = $cb;
$cb = $tmp;
}
if ($isBlock) {
$options['fn'] = function ($context = '_NO_INPUT_HERE_') use ($cx, $op, $cb) {
if ($cx['flags']['echo']) {
ob_start();
}
if ($context === '_NO_INPUT_HERE_') {
$cx['scopes'][] = $op;
$ret = $cb($cx, $op);
} else {
$cx['scopes'][] = $op;
$ret = $cb($cx, $context);
}
array_pop($cx['scopes']);
return $cx['flags']['echo'] ? ob_get_clean() : $ret;
};
}
if ($else) {
$options['inverse'] = function ($context = '_NO_INPUT_HERE_') use ($cx, $op, $else) {
if ($cx['flags']['echo']) {
ob_start();
}
if ($context === '_NO_INPUT_HERE_') {
$ret = $else($cx, $op);
} else {
$cx['scopes'][] = $op;
$ret = $else($cx, $context);
array_pop($cx['scopes']);
}
return $cx['flags']['echo'] ? ob_get_clean() : $ret;
};
}
// prepare $options['data']
if ($cx['flags']['spvar']) {
$options['data'] = $cx['sp_vars'];
}
$args[] = $options;
$e = null;
$r = true;
try {
$r = call_user_func_array($cx['hbhelpers'][$ch], $args);
} catch (Exception $E) {
$e = "LCRun3: call custom helper '$ch' error: " . $E->getMessage();
}
if ($e !== null) {
if ($cx['flags']['debug'] & self::DEBUG_ERROR_LOG) {
error_log($e);
}
if ($cx['flags']['debug'] & self::DEBUG_ERROR_EXCEPTION) {
throw new Exception($e);
}
}
return self::chret($r, $isBlock ? 'raw' : $op);
}
/**
* LightnCandy runtime method for block custom helpers.
*
* @param array<string,array|string|integer> $cx render time context
* @param string $ch the name of custom helper to be executed
* @param array<array|string|integer>|string|integer|null $vars variables for the helper
* @param array<array|string|integer>|string|integer|null $in input data with current scope
* @param boolean $inverted the logic will be inverted
* @param Closure $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the token
*
* @expect '4.2.3' when input array('blockhelpers' => array('a' => function ($cx) {return array($cx,2,3);})), 'a', array(0, 0), 4, false, function($cx, $i) {return implode('.', $i);}
* @expect '2.6.5' when input array('blockhelpers' => array('a' => function ($cx,$in) {return array($cx,$in[0],5);})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
* @expect '' when input array('blockhelpers' => array('a' => function ($cx,$in) {})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
*/
public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = null)
{
$r = call_user_func($cx['blockhelpers'][$ch], $in, $vars[0], $vars[1]);
// $invert the logic
if ($inverted) {
$tmp = $else;
$else = $cb;
$cb = $tmp;
}
$ret = '';
if (is_null($r)) {
if ($else) {
$cx['scopes'][] = $in;
$ret = $else($cx, $r);
array_pop($cx['scopes']);
}
} else {
if ($cb) {
$cx['scopes'][] = $in;
$ret = $cb($cx, $r);
array_pop($cx['scopes']);
}
}
return $ret;
}
}
<?php
namespace Plugin;
/**
* LightnCandy static class for compiled template runtime methods.
*/
class LCRun3 {
const DEBUG_ERROR_LOG = 1;
const DEBUG_ERROR_EXCEPTION = 2;
const DEBUG_TAGS = 4;
const DEBUG_TAGS_ANSI = 12;
const DEBUG_TAGS_HTML = 20;
/**
* LightnCandy runtime method for output debug info.
*
* @param string $v expression
* @param string $f runtime function name
* @param array<string,array|string|integer> $cx render time context
*
* @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS), 'lcrun' => 'LCRun3'), ''
* @expect '<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->' when input '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML), 'lcrun' => 'LCRun3'), false, false, function () {return 'A';}
*/
public static function debug($v, $f, $cx) {
$params = array_slice(func_get_args(), 2);
$r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "{$cx['lcrun']}::$f"), $params);
if ($cx['flags']['debug'] & self::DEBUG_TAGS) {
$ansi = $cx['flags']['debug'] & (self::DEBUG_TAGS_ANSI - self::DEBUG_TAGS);
$html = $cx['flags']['debug'] & (self::DEBUG_TAGS_HTML - self::DEBUG_TAGS);
$cs = ($html ? (($r !== '') ? '<!!--OK((-->' : '<!--MISSED((-->') : '')
. ($ansi ? (($r !== '') ? "\033[0;32m" : "\033[0;31m") : '');
$ce = ($html ? '<!--))-->' : '')
. ($ansi ? "\033[0m" : '');
switch ($f) {
case 'sec':
case 'ifv':
case 'unl':
case 'wi':
if ($r == '') {
if ($ansi) {
$r = "\033[0;33mSKIPPED\033[0m";
}
if ($html) {
$r = '<!--SKIPPED-->';
}
}
return "$cs{{#{$v}}}$ce{$r}$cs{{/{$v}}}$ce";
default:
return "$cs{{{$v}}}$ce";
}
} else {
return $r;
}
}
/**
* LightnCandy runtime method for missing data error.
*
* @param array<string,array|string|integer> $cx render time context
* @param string $v expression
*/
public static function miss($cx, $v) {
$e = "LCRun3: $v is not exist";
if ($cx['flags']['debug'] & self::DEBUG_ERROR_LOG) {
error_log($e);
return;
}
if ($cx['flags']['debug'] & self::DEBUG_ERROR_EXCEPTION) {
throw new Exception($e);
}
}
/**
* LightnCandy runtime method for variable lookup. It is slower and only be used for instance property or method detection.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer> $base current variable context
* @param array<string|integer> $path array of names for path
*
* @return null|string Return the value or null when not found
*
* @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), 0, array('a', 'b')
* @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0), 'mustlok' => 0), array('a' => array('b' => 3)), array('a', 'b')
* @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), (Object) array('a' => array('b' => 3)), array('a', 'b')
* @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 1, 'method' => 0, 'mustlok' => 0)), (Object) array('a' => array('b' => 3)), array('a', 'b')
*/
public static function v($cx, $base, $path) {
$count = count($cx['scopes']);
while ($base) {
$v = $base;
foreach ($path as $name) {
if (is_array($v) && isset($v[$name])) {
$v = $v[$name];
continue;
}
if (is_object($v)) {
if ($cx['flags']['prop'] && isset($v->$name)) {
$v = $v->$name;
continue;
}
if ($cx['flags']['method'] && is_callable(array($v, $name))) {
$v = $v->$name();
continue;
}
}
if ($cx['flags']['mustlok']) {
unset($v);
break;
}
return null;
}
if (isset($v)) {
return $v;
}
$count--;
switch ($count) {
case -1:
$base = $cx['sp_vars']['root'];
break;
case -2:
return null;
default:
$base = $cx['scopes'][$count];
}
}
}
/**
* LightnCandy runtime method for {{#if var}}.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be tested
*
* @return boolean Return true when the value is not null nor false.
*
* @expect false when input array(), null
* @expect false when input array(), 0
* @expect false when input array(), false
* @expect true when input array(), true
* @expect true when input array(), 1
* @expect false when input array(), ''
* @expect false when input array(), array()
* @expect true when input array(), array('')
* @expect true when input array(), array(0)
*/
public static function ifvar($cx, $v) {
return !is_null($v) && ($v !== false) && ($v !== 0) && ($v !== 0.0) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
}
/**
* LightnCandy runtime method for {{#if var}} when {{../var}} used.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be tested
* @param array<array|string|integer> $in input data with current scope
* @param Closure|null $truecb callback function when test result is true
* @param Closure|null $falsecb callback function when test result is false
*
* @return string The rendered string of the section
*
* @expect '' when input array('scopes' => array()), null, array(), null
* @expect '' when input array('scopes' => array()), null, array(), function () {return 'Y';}
* @expect 'Y' when input array('scopes' => array()), 1, array(), function () {return 'Y';}
* @expect 'N' when input array('scopes' => array()), null, array(), function () {return 'Y';}, function () {return 'N';}
*/
public static function ifv($cx, $v, $in, $truecb, $falsecb = null) {
$ret = '';
if (self::ifvar($cx, $v)) {
if ($truecb) {
$cx['scopes'][] = $in;
$ret = $truecb($cx, $in);
array_pop($cx['scopes']);
}
} else {
if ($falsecb) {
$cx['scopes'][] = $in;
$ret = $falsecb($cx, $in);
array_pop($cx['scopes']);
}
}
return $ret;
}
/**
* LightnCandy runtime method for {{#unless var}} when {{../var}} used.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $var value be tested
* @param array<array|string|integer>|string|integer|null $in input data with current scope
* @param Closure $truecb callback function when test result is true
* @param Closure|null $falsecb callback function when test result is false
*
* @return string Return rendered string when the value is not null nor false.
*
* @expect '' when input array('scopes' => array()), null, array(), null
* @expect 'Y' when input array('scopes' => array()), null, array(), function () {return 'Y';}
* @expect '' when input array('scopes' => array()), 1, array(), function () {return 'Y';}
* @expect 'Y' when input array('scopes' => array()), null, array(), function () {return 'Y';}, function () {return 'N';}
* @expect 'N' when input array('scopes' => array()), true, array(), function () {return 'Y';}, function () {return 'N';}
*/
public static function unl($cx, $var, $in, $truecb, $falsecb = null) {
return self::ifv($cx, $var, $in, $falsecb, $truecb);
}
/**
* LightnCandy runtime method for {{^var}} inverted section.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be tested
*
* @return boolean Return true when the value is not null nor false.
*
* @expect true when input array(), null
* @expect false when input array(), 0
* @expect true when input array(), false
* @expect false when input array(), 'false'
* @expect true when input array(), array()
* @expect false when input array(), array('1')
*/
public static function isec($cx, $v) {
return is_null($v) || ($v === false) || (is_array($v) && (count($v) === 0));
}
/**
* LightnCandy runtime method for {{{var}}} .
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be output
*
* @return string The raw value of the specified variable
*
* @expect true when input array('flags' => array('jstrue' => 0)), true
* @expect 'true' when input array('flags' => array('jstrue' => 1)), true
* @expect '' when input array('flags' => array('jstrue' => 0)), false
* @expect 'false' when input array('flags' => array('jstrue' => 1)), false
* @expect 'false' when input array('flags' => array('jstrue' => 1)), false, true
* @expect 'Array' when input array('flags' => array('jstrue' => 1, 'jsobj' => 0)), array('a', 'b')
* @expect 'a,b' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a', 'b')
* @expect '[object Object]' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a', 'c' => 'b')
* @expect '[object Object]' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('c' => 'b')
* @expect 'a,true' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a', true)
* @expect 'a,1' when input array('flags' => array('jstrue' => 0, 'jsobj' => 1)), array('a',true)
* @expect 'a,' when input array('flags' => array('jstrue' => 0, 'jsobj' => 1)), array('a',false)
* @expect 'a,false' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a',false)
*/
public static function raw($cx, $v) {
if ($v === true) {
if ($cx['flags']['jstrue']) {
return 'true';
}
}
if (($v === false)) {
if ($cx['flags']['jstrue']) {
return 'false';
}
}
if (is_array($v)) {
if ($cx['flags']['jsobj']) {
if (count(array_diff_key($v, array_keys(array_keys($v)))) > 0) {
return '[object Object]';
} else {
$ret = array();
foreach ($v as $k => $vv) {
$ret[] = self::raw($cx, $vv);
}
return join(',', $ret);
}
} else {
return 'Array';
}
}
return "$v";
}
/**
* LightnCandy runtime method for {{var}} .
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $var value to be htmlencoded
*
* @return string The htmlencoded value of the specified variable
*
* @expect 'a' when input array(), 'a'
* @expect 'a&amp;b' when input array(), 'a&b'
* @expect 'a&#039;b' when input array(), 'a\'b'
*/
public static function enc($cx, $var) {
return htmlentities(self::raw($cx, $var), ENT_QUOTES, 'UTF-8');
}
/**
* LightnCandy runtime method for {{var}} , and deal with single quote to same as handlebars.js .
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $var value to be htmlencoded
*
* @return string The htmlencoded value of the specified variable
*
* @expect 'a' when input array(), 'a'
* @expect 'a&amp;b' when input array(), 'a&b'
* @expect 'a&#x27;b' when input array(), 'a\'b'
* @expect '&#x60;a&#x27;b' when input array(), '`a\'b'
*/
public static function encq($cx, $var) {
return preg_replace('/`/', '&#x60;', preg_replace('/&#039;/', '&#x27;', htmlentities(self::raw($cx, $var), ENT_QUOTES, 'UTF-8')));
}
/**
* LightnCandy runtime method for {{#var}} section.
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value for the section
* @param array<array|string|integer>|string|integer|null $in input data with current scope
* @param boolean $each true when rendering #each
* @param Closure $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the section
*
* @expect '' when input array('flags' => array('spvar' => 0)), false, false, false, function () {return 'A';}
* @expect '' when input array('flags' => array('spvar' => 0)), null, null, false, function () {return 'A';}
* @expect 'A' when input array('flags' => array('spvar' => 0)), true, true, false, function () {return 'A';}
* @expect 'A' when input array('flags' => array('spvar' => 0)), 0, 0, false, function () {return 'A';}
* @expect '-a=' when input array('flags' => array('spvar' => 0)), array('a'), array('a'), false, function ($c, $i) {return "-$i=";}
* @expect '-a=-b=' when input array('flags' => array('spvar' => 0)), array('a','b'), array('a','b'), false, function ($c, $i) {return "-$i=";}
* @expect '' when input array('flags' => array('spvar' => 0)), 'abc', 'abc', true, function ($c, $i) {return "-$i=";}
* @expect '-b=' when input array('flags' => array('spvar' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
* @expect '1' when input array('flags' => array('spvar' => 0)), 'b', 'b', false, function ($c, $i) {return count($i);}
* @expect '1' when input array('flags' => array('spvar' => 0)), 1, 1, false, function ($c, $i) {return print_r($i, true);}
* @expect '0' when input array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return print_r($i, true);}
* @expect '{"b":"c"}' when input array('flags' => array('spvar' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), array(), 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), array(), 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), false, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), false, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), '', 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'cb' when input array('flags' => array('spvar' => 0)), '', 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), 0, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'cb' when input array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), new stdClass, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'cb' when input array('flags' => array('spvar' => 0)), new stdClass, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect '268' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
* @expect '038' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
*/
public static function sec($cx, $v, $in, $each, $cb, $else = null) {
$isAry = is_array($v) || ($v instanceof ArrayObject);
$isTrav = $v instanceof Traversable;
$loop = $each;
$keys = null;
$last = null;
$isObj = false;
if ($isAry && $else !== null && count($v) === 0) {
$cx['scopes'][] = $in;
$ret = $else($cx, $in);
array_pop($cx['scopes']);
return $ret;
}
// #var, detect input type is object or not
if (!$loop && $isAry) {
$keys = array_keys($v);
$loop = (count(array_diff_key($v, array_keys($keys))) == 0);
$isObj = !$loop;
}
if (($loop && $isAry) || $isTrav) {
if ($each && !$isTrav) {
// Detect input type is object or not when never done once
if ($keys == null) {
$keys = array_keys($v);
$isObj = (count(array_diff_key($v, array_keys($keys))) > 0);
}
}
$ret = array();
$cx['scopes'][] = $in;
$i = 0;
if ($cx['flags']['spvar']) {
$old_spvar = $cx['sp_vars'];
$cx['sp_vars'] = array(
'_parent' => $old_spvar,
'root' => $old_spvar['root'],
);
if (!$isTrav) {
$last = count($keys) - 1;
}
}
foreach ($v as $index => $raw) {
if ($cx['flags']['spvar']) {
$cx['sp_vars']['first'] = ($i === 0);
$cx['sp_vars']['last'] = ($i == $last);
$cx['sp_vars']['key'] = $index;
$cx['sp_vars']['index'] = $i;
$i++;
}
$ret[] = $cb($cx, $raw);
}
if ($cx['flags']['spvar']) {
if ($isObj) {
unset($cx['sp_vars']['key']);
} else {
unset($cx['sp_vars']['last']);
}
unset($cx['sp_vars']['index']);
unset($cx['sp_vars']['first']);
$cx['sp_vars'] = $old_spvar;
}
array_pop($cx['scopes']);
return join('', $ret);
}
if ($each) {
if ($else !== null) {
$cx['scopes'][] = $in;
$ret = $else($cx, $v);
array_pop($cx['scopes']);
return $ret;
}
return '';
}
if ($isAry) {
$cx['scopes'][] = $in;
$ret = $cb($cx, $v);
array_pop($cx['scopes']);
return $ret;
}
if ($v === true) {
return $cb($cx, $in);
}
if (!is_null($v) && ($v !== false)) {
return $cb($cx, $v);
}
if ($else !== null) {
$cx['scopes'][] = $in;
$ret = $else($cx, $in);
array_pop($cx['scopes']);
return $ret;
}
return '';
}
/**
* LightnCandy runtime method for {{#with var}} .
*
* @param array<string,array|string|integer> $cx render time context
* @param array<array|string|integer>|string|integer|null $v value to be the new context
* @param array<array|string|integer>|string|integer|null $in input data with current scope
* @param Closure $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the token
*
* @expect '' when input array(), false, false, function () {return 'A';}
* @expect '' when input array(), null, null, function () {return 'A';}
* @expect '{"a":"b"}' when input array(), array('a'=>'b'), array('a'=>'c'), function ($c, $i) {return json_encode($i);}
* @expect '-b=' when input array(), 'b', array('a'=>'b'), function ($c, $i) {return "-$i=";}
*/
public static function wi($cx, $v, $in, $cb, $else = null) {
if (($v === false) || ($v === null)) {
return $else ? $else($cx, $in) : '';
}
$cx['scopes'][] = $in;
$ret = $cb($cx, $v);
array_pop($cx['scopes']);
return $ret;
}
/**
* LightnCandy runtime method for {{> partial}} .
*
* @param array<string,array|string|integer> $cx render time context
* @param string $p partial name
* @param array<array|string|integer>|string|integer|null $v value to be the new context
*
* @return string The rendered string of the partial
*
*/
public static function p($cx, $p, $v, $sp = '') {
$param = $v[0][0];
if (is_array($v[1])) {
if (is_array($v[0][0])) {
$param = array_merge($v[0][0], $v[1]);
} else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($v[0][0])) {
foreach ($v[1] as $i => $v) {
$param->$i = $v;
}
}
}
return call_user_func($cx['partials'][$p], $cx, $param, $sp);
}
/**
* LightnCandy runtime method for custom helpers.
*
* @param array<string,array|string|integer> $cx render time context
* @param string $ch the name of custom helper to be executed
* @param array<array> $vars variables for the helper
* @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
*
* @return string The rendered string of the token
*
* @expect '=-=' when input array('helpers' => array('a' => function ($i) {return "=$i[0]=";})), 'a', array(array('-'),array()), 'raw'
* @expect '=&amp;=' when input array('helpers' => array('a' => function ($i) {return "=$i[0]=";})), 'a', array(array('&'),array()), 'enc'
* @expect '=&#x27;=' when input array('helpers' => array('a' => function ($i) {return "=$i[0]=";})), 'a', array(array('\''),array()), 'encq'
* @expect '=b=' when input array('helpers' => array('a' => function ($i,$j) {return "={$j['a']}=";})), 'a', array(array(),array('a' => 'b')), 'raw'
*/
public static function ch($cx, $ch, $vars, $op) {
return self::chret(call_user_func_array($cx['helpers'][$ch], $vars), $op);
}
/**
* LightnCandy runtime method to handle response of custom helpers.
*
* @param string|array<string,array|string|integer> $ret return value from custom helper
* @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
*
* @return string The rendered string of the token
*
* @expect '=&=' when input '=&=', 'raw'
* @expect '=&amp;&#039;=' when input '=&\'=', 'enc'
* @expect '=&amp;&#x27;=' when input '=&\'=', 'encq'
* @expect '=&amp;&#039;=' when input array('=&\'='), 'enc'
* @expect '=&amp;&#x27;=' when input array('=&\'='), 'encq'
* @expect '=&amp;=' when input array('=&=', false), 'enc'
* @expect '=&=' when input array('=&=', false), 'raw'
* @expect '=&=' when input array('=&=', 'raw'), 'enc'
* @expect '=&amp;&#x27;=' when input array('=&\'=', 'encq'), 'raw'
*/
public static function chret($ret, $op) {
if (is_array($ret)) {
if (isset($ret[1]) && $ret[1]) {
$op = $ret[1];
}
$ret = $ret[0];
}
switch ($op) {
case 'enc':
return htmlentities($ret, ENT_QUOTES, 'UTF-8');
case 'encq':
return preg_replace('/&#039;/', '&#x27;', htmlentities($ret, ENT_QUOTES, 'UTF-8'));
}
return $ret;
}
/**
* LightnCandy runtime method for Handlebars.js style custom helpers.
*
* @param array<string,array|string|integer> $cx render time context
* @param string $ch the name of custom helper to be executed
* @param array<array|string|integer>|string|integer|null $vars variables for the helper
* @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
* @param boolean $inverted the logic will be inverted
* @param Closure|null $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the token
*/
public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null) {
$isBlock = (is_object($cb) && ($cb instanceof Closure));
$args = $vars[0];
$options = array(
'name' => $ch,
'hash' => $vars[1],
'_this' => $isBlock ? $op : $inverted,
);
// $invert the logic
if ($inverted) {
$tmp = $else;
$else = $cb;
$cb = $tmp;
}
if ($isBlock) {
$options['fn'] = function ($context = '_NO_INPUT_HERE_') use ($cx, $op, $cb) {
if ($cx['flags']['echo']) {
ob_start();
}
if ($context === '_NO_INPUT_HERE_') {
$cx['scopes'][] = $op;
$ret = $cb($cx, $op);
} else {
$cx['scopes'][] = $op;
$ret = $cb($cx, $context);
}
array_pop($cx['scopes']);
return $cx['flags']['echo'] ? ob_get_clean() : $ret;
};
}
if ($else) {
$options['inverse'] = function ($context = '_NO_INPUT_HERE_') use ($cx, $op, $else) {
if ($cx['flags']['echo']) {
ob_start();
}
if ($context === '_NO_INPUT_HERE_') {
$ret = $else($cx, $op);
} else {
$cx['scopes'][] = $op;
$ret = $else($cx, $context);
array_pop($cx['scopes']);
}
return $cx['flags']['echo'] ? ob_get_clean() : $ret;
};
}
// prepare $options['data']
if ($cx['flags']['spvar']) {
$options['data'] = $cx['sp_vars'];
}
$args[] = $options;
$e = null;
$r = true;
try {
$r = call_user_func_array($cx['hbhelpers'][$ch], $args);
} catch (Exception $E) {
$e = "LCRun3: call custom helper '$ch' error: " . $E->getMessage();
}
if($e !== null) {
if ($cx['flags']['debug'] & self::DEBUG_ERROR_LOG) {
error_log($e);
}
if ($cx['flags']['debug'] & self::DEBUG_ERROR_EXCEPTION) {
throw new Exception($e);
}
}
return self::chret($r, $isBlock ? 'raw' : $op);
}
/**
* LightnCandy runtime method for block custom helpers.
*
* @param array<string,array|string|integer> $cx render time context
* @param string $ch the name of custom helper to be executed
* @param array<array|string|integer>|string|integer|null $vars variables for the helper
* @param array<array|string|integer>|string|integer|null $in input data with current scope
* @param boolean $inverted the logic will be inverted
* @param Closure $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the token
*
* @expect '4.2.3' when input array('blockhelpers' => array('a' => function ($cx) {return array($cx,2,3);})), 'a', array(0, 0), 4, false, function($cx, $i) {return implode('.', $i);}
* @expect '2.6.5' when input array('blockhelpers' => array('a' => function ($cx,$in) {return array($cx,$in[0],5);})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
* @expect '' when input array('blockhelpers' => array('a' => function ($cx,$in) {})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
*/
public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = null) {
$r = call_user_func($cx['blockhelpers'][$ch], $in, $vars[0], $vars[1]);
// $invert the logic
if ($inverted) {
$tmp = $else;
$else = $cb;
$cb = $tmp;
}
$ret = '';
if (is_null($r)) {
if ($else) {
$cx['scopes'][] = $in;
$ret = $else($cx, $r);
array_pop($cx['scopes']);
}
} else {
if ($cb) {
$cx['scopes'][] = $in;
$ret = $cb($cx, $r);
array_pop($cx['scopes']);
}
}
return $ret;
}
}
\ No newline at end of file
... ...
<?php
/**
* Created by PhpStorm.
* User: liuziyang
* Date: 14-1-12
* Time: 16:32
*/
namespace Plugin;
use Yaf\View_Interface;
use Yaf\View;
use Yaf\Application;
class Layout implements View_Interface
{
public $breadcrumb = array();
public $engine;
protected $options = array();
protected $layout_path;
protected $layout;
protected $content;
protected $tpl_vars = array();
protected $tpl_dir;
public function __construct($path, $options = array())
{
$this->layout_path = $path;
$this->options = $options;
}
protected function engine()
{
$this->engine = $this->engine ? : new View\Simple(
$this->tpl_dir, $this->options
);
return $this->engine;
}
public function setScriptPath($path)
{
if (is_readable($path)) {
$this->tpl_dir = $path;
$this->engine()->setScriptPath($path);
$this->layout_path = $path . "/../layouts";
return true;
}
throw new Exception("Invalid path: {$path}");
}
public function getScriptPath()
{
return $this->engine()->getScriptPath();
}
public function setLayout($name)
{
$this->layout = $name;
}
public function getLayout()
{
return $this->layout;
}
public function setLayoutPath($path)
{
$this->layout_path = $path;
return $this;
}
public function getLayoutPath()
{
$config = Application::app()->getConfig()->get('application');
return $this->layout_path . "/" . $this->layout . ".{$config->view->ext}";
}
public function __set($name, $value)
{
$this->assign($name, $value);
}
public function __isset($name)
{
return (null !== $this->engine()->$name);
}
public function __unset($name)
{
$this->engine()->clear($name);
}
public function assign($name, $value = null)
{
$this->tpl_vars[$name] = $value;
$this->engine()->assign($name, $value);
}
public function assignRef($name, &$value)
{
$this->tpl_vars[$name] = $value;
$this->engine()->assignRef($name, $value);
}
public function clearVars($name)
{
$this->tpl_vars = array();
$this->engine()->clear($name);
}
public function render($tpl, $tpl_vars = array())
{
$tpl_vars = array_merge($this->tpl_vars, $tpl_vars);
$this->content = $this->engine()->render($tpl, $tpl_vars);
if (null == $this->layout) {
return $this->content;
}
$ref = new \ReflectionClass($this->engine());
$prop = $ref->getProperty('_tpl_vars');
$prop->setAccessible(true);
$view_vars = $prop->getValue($this->engine());
$tpl_vars = array_merge($tpl_vars, $view_vars);
$tpl_vars['content'] = $this->content;
$this->engine()->assign('breadcrumb', $this->breadcrumb);
return $this->engine()->render(
$this->getLayoutPath(), $tpl_vars
);
}
public function display($tpl, $tpl_vars = array())
{
echo $this->render($tpl, $tpl_vars);
}
}
<?php
/**
* Created by PhpStorm.
* User: liuziyang
* Date: 14-1-12
* Time: 16:32
*/
namespace Plugin;
use Yaf\View_Interface;
use Yaf\View;
use Yaf\Application;
class Layout implements View_Interface
{
public $breadcrumb = array();
public $engine;
protected $options = array();
protected $layout_path;
protected $layout;
protected $content;
protected $tpl_vars = array();
protected $tpl_dir;
public function __construct($path, $options = array())
{
$this->layout_path = $path;
$this->options = $options;
}
protected function engine()
{
$this->engine = $this->engine ?: new View\Simple(
$this->tpl_dir,
$this->options
);
return $this->engine;
}
public function setScriptPath($path)
{
if (is_readable($path)) {
$this->tpl_dir = $path;
$this->engine()->setScriptPath($path);
$this->layout_path = $path . "/../layouts";
return true;
}
throw new Exception("Invalid path: {$path}");
}
public function getScriptPath()
{
return $this->engine()->getScriptPath();
}
public function setLayout($name)
{
$this->layout = $name;
}
public function getLayout()
{
return $this->layout;
}
public function setLayoutPath($path)
{
$this->layout_path = $path;
return $this;
}
public function getLayoutPath()
{
$config = Application::app()->getConfig()->get('application');
return $this->layout_path . "/" . $this->layout . ".{$config->view->ext}";
}
public function __set($name, $value)
{
$this->assign($name, $value);
}
public function __isset($name)
{
return (null !== $this->engine()->$name);
}
public function __unset($name)
{
$this->engine()->clear($name);
}
public function assign($name, $value = null)
{
$this->tpl_vars[$name] = $value;
$this->engine()->assign($name, $value);
}
public function assignRef($name, &$value)
{
$this->tpl_vars[$name] = $value;
$this->engine()->assignRef($name, $value);
}
public function clearVars($name)
{
$this->tpl_vars = array();
$this->engine()->clear($name);
}
public function render($tpl, $tpl_vars = array())
{
$tpl_vars = array_merge($this->tpl_vars, $tpl_vars);
$this->content = $this->engine()->render($tpl, $tpl_vars);
if (null == $this->layout) {
return $this->content;
}
$ref = new \ReflectionClass($this->engine());
$prop = $ref->getProperty('_tpl_vars');
$prop->setAccessible(true);
$view_vars = $prop->getValue($this->engine());
$tpl_vars = array_merge($tpl_vars, $view_vars);
$tpl_vars['content'] = $this->content;
$this->engine()->assign('breadcrumb', $this->breadcrumb);
return $this->engine()->render(
$this->getLayoutPath(),
$tpl_vars
);
}
public function display($tpl, $tpl_vars = array())
{
echo $this->render($tpl, $tpl_vars);
}
}
... ...
This diff could not be displayed because it is too large.
<?php
namespace Plugin\Partner;
isset($_SESSION) || session_start();
defined('DS') || define('DS', '/');
/**
* 抽象类: 第三方接口都会继承该类
*
* @name Factory
* @package library/Plugin/Partner
* @copyright yoho.inc
* @version 1.0 (2015-10-10 17:11:10)
* @author fei.hong <fei.hong@yoho.cn>
*/
abstract class Factory
{
/**
* 接口名称
*
* @var string
*/
protected $apiName = '';
/**
* 接口配置
*
* @var array
*/
protected $apiConfig = array();
/**
* 接口对象
*
* @var array
*/
protected static $apiObjs = array();
/**
* 单例模式: 实例化需要调用的接口对象
*
* @param string $apiName 接口名称
* @return object
*/
public static function create($apiName)
{
$apiName = strtolower($apiName);
if (!isset(self::$apiObjs[$apiName])) {
// require dirname(__FILE__) . DS . $apiName . DS . 'Call.class.php';
//$apiNameCase = ucfirst($apiName);
$apiClass = "Plugin\Partner\\{$apiName}\Call";
self::$apiObjs[$apiName] = new $apiClass();
self::$apiObjs[$apiName]->apiName = $apiName;
self::$apiObjs[$apiName]->configure();
self::$apiObjs[$apiName]->init();
}
return self::$apiObjs[$apiName];
}
/**
* 应用的配置
*
* @return void
*/
protected function configure()
{
$this->apiConfig = require(dirname(__FILE__) . DS . $this->apiName . DS . 'Config.inc.php');
}
/* * 初始化 */
abstract protected function init();
/* * 获取接口 */
abstract public function getAuthorizeUrl();
abstract public function getAccessToken();
abstract public function getUserInfo($token);
abstract public function getFriends($token, $params);
/* * 同步分享 */
abstract public function syncShare($token, $content, $image, $link);
}
<?php
namespace Plugin\Partner;
isset($_SESSION) || session_start();
defined('DS') || define('DS', '/');
/**
* 抽象类: 第三方接口都会继承该类
*
* @name Factory
* @package library/Plugin/Partner
* @copyright yoho.inc
* @version 1.0 (2015-10-10 17:11:10)
* @author fei.hong <fei.hong@yoho.cn>
*/
abstract class Factory
{
/**
* 接口名称
*
* @var string
*/
protected $apiName = '';
/**
* 接口配置
*
* @var array
*/
protected $apiConfig = array();
/**
* 接口对象
*
* @var array
*/
protected static $apiObjs = array();
/**
* 单例模式: 实例化需要调用的接口对象
*
* @param string $apiName 接口名称
* @return object
*/
public static function create($apiName)
{
$apiName = strtolower($apiName);
if (!isset(self::$apiObjs[$apiName]))
{
// require dirname(__FILE__) . DS . $apiName . DS . 'Call.class.php';
//$apiNameCase = ucfirst($apiName);
$apiClass = "Plugin\Partner\\{$apiName}\Call";
self::$apiObjs[$apiName] = new $apiClass();
self::$apiObjs[$apiName]->apiName = $apiName;
self::$apiObjs[$apiName]->configure();
self::$apiObjs[$apiName]->init();
}
return self::$apiObjs[$apiName];
}
/**
* 应用的配置
*
* @return void
*/
protected function configure()
{
$this->apiConfig = require(dirname(__FILE__) . DS . $this->apiName . DS . 'Config.inc.php');
}
/**初始化*/
abstract protected function init();
/**获取接口*/
abstract public function getAuthorizeUrl();
abstract public function getAccessToken();
abstract public function getUserInfo($token);
abstract public function getFriends($token, $params);
/**同步分享*/
abstract public function syncShare($token, $content, $image, $link);
}
\ No newline at end of file
... ...
<?php
namespace Plugin\Partner\alipay;
use Plugin\Partner\Factory;
define('TB_CLASS_PATH', dirname(__FILE__) . '/class');
require TB_CLASS_PATH . '/lib/alipay.function.php';
require TB_CLASS_PATH . '/AlipaySubmit.class.php';
require TB_CLASS_PATH . '/AlipayNotify.class.php';
/**
* 支付宝快捷的调用接口
*
* @name Call
* @package Plugin/Partner/alipay
* @copyright yoho.inc
* @version 1.0 (2015-10-10 17:56:42)
* @author fei.hong <fei.hong@yoho.cn>
*/
class Call extends Factory
{
protected $alipaySubmit;
protected $alipayNotify;
/**
* 初始化
*/
protected function init()
{
$this->alipaySubmit = new \AlipaySubmit($this->apiConfig);
$this->alipayNotify = new \AlipayNotify($this->apiConfig);
}
/**
* 获取授权URL
*
* @return string
*/
public function getAuthorizeUrl()
{
$parameter = array(
'service' => 'alipay.auth.authorize',
'partner' => $this->apiConfig['partner'],
'target_service' => 'user.auth.quick.login',
'return_url' => $this->apiConfig['return_url'],
'anti_phishing_key' => $this->alipaySubmit->query_timestamp(),
'exter_invoke_ip' => '',
'_input_charset' => $this->apiConfig['input_charset']
);
echo '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>支付宝快捷登录</title></head><body>',
$this->alipaySubmit->buildRequestForm($parameter, 'get'),
'</body></html>';
exit();
}
/**
* 获取授权的TOKEN
*
* @return array
*/
public function getAccessToken()
{
$token = array();
$verify = $this->alipayNotify->verifyReturn();
if ($verify) {
$token['access_token'] = isset($_GET['token']) ? $_GET['token'] : null;
$token['user_id'] = isset($_GET['user_id']) ? $_GET['user_id'] : null;
}
return $token;
}
/**
* 获取当前用户的基本资料
*
* @param array $token 授权成功的TOKEN, 默认为NULL
* @return array
*/
public function getUserInfo($token)
{
$parameter = array(
'_input_charset' => $this->apiConfig['input_charset'],
'service' => 'mobile.common.login.userInfo.query',
'partner' => $this->apiConfig['partner'],
'token' => $token,
'timestamp' => date('Y-m-d H:i:s'),
);
$result = $this->alipaySubmit->getUserInfoByToken($parameter, $token);
return $result;
}
/**
* 获取当前用户的偶像(关注)列表
*
* 备注:此接口暂未开放
*
* @param array $token 访问令牌
* @param array $params 参数列表
* @return array
*/
public function getFriends($token, $params)
{
return array();
}
/**
* 同步分享
*
* 备注:此接口暂未开放
*
* @param object $token 访问令牌
* @param String $image 新鲜事图片地址
* @param String $content 新鲜事主体内容 注意:最多200个字符。
* @param String $link 新鲜事标题和图片指向的链接
* @return Long 发布新鲜事的ID
*/
public function syncShare($token, $content, $image, $link)
{
return true;
}
}
<?php
namespace Plugin\Partner\alipay;
use Plugin\Partner\Factory;
define('TB_CLASS_PATH', dirname(__FILE__).'/class');
require TB_CLASS_PATH . '/lib/alipay.function.php';
require TB_CLASS_PATH . '/AlipaySubmit.class.php';
require TB_CLASS_PATH . '/AlipayNotify.class.php';
/**
* 支付宝快捷的调用接口
*
* @name Call
* @package Plugin/Partner/alipay
* @copyright yoho.inc
* @version 1.0 (2015-10-10 17:56:42)
* @author fei.hong <fei.hong@yoho.cn>
*/
class Call extends Factory
{
protected $alipaySubmit;
protected $alipayNotify;
/**
* 初始化
*/
protected function init()
{
$this->alipaySubmit = new \AlipaySubmit($this->apiConfig);
$this->alipayNotify = new \AlipayNotify($this->apiConfig);
}
/**
* 获取授权URL
*
* @return string
*/
public function getAuthorizeUrl()
{
$parameter = array(
'service' => 'alipay.auth.authorize',
'partner' => $this->apiConfig['partner'],
'target_service' => 'user.auth.quick.login',
'return_url' => $this->apiConfig['return_url'],
'anti_phishing_key' => $this->alipaySubmit->query_timestamp(),
'exter_invoke_ip' => '',
'_input_charset' => $this->apiConfig['input_charset']
);
echo '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>支付宝快捷登录</title></head><body>',
$this->alipaySubmit->buildRequestForm($parameter, 'get'),
'</body></html>';
exit();
}
/**
* 获取授权的TOKEN
*
* @return array
*/
public function getAccessToken()
{
$token = array();
$verify = $this->alipayNotify->verifyReturn();
if ($verify)
{
$token['access_token'] = isset($_GET['token']) ? $_GET['token'] : null;
$token['user_id'] = isset($_GET['user_id']) ? $_GET['user_id'] : null;
}
return $token;
}
/**
* 获取当前用户的基本资料
*
* @param array $token 授权成功的TOKEN, 默认为NULL
* @return array
*/
public function getUserInfo($token)
{
$parameter = array(
'_input_charset' => $this->apiConfig['input_charset'],
'service' => 'mobile.common.login.userInfo.query',
'partner' => $this->apiConfig['partner'],
'token' => $token,
'timestamp' => date('Y-m-d H:i:s'),
);
$result = $this->alipaySubmit->getUserInfoByToken($parameter, $token);
return $result;
}
/**
* 获取当前用户的偶像(关注)列表
*
* 备注:此接口暂未开放
*
* @param array $token 访问令牌
* @param array $params 参数列表
* @return array
*/
public function getFriends($token, $params)
{
return array();
}
/**
* 同步分享
*
* 备注:此接口暂未开放
*
* @param object $token 访问令牌
* @param String $image 新鲜事图片地址
* @param String $content 新鲜事主体内容 注意:最多200个字符。
* @param String $link 新鲜事标题和图片指向的链接
* @return Long 发布新鲜事的ID
*/
public function syncShare($token, $content, $image, $link)
{
return true;
}
}
\ No newline at end of file
... ...
<?php
defined('SITE_MAIN') || define('SITE_MAIN', $_SERVER['HTTP_HOST']);
return array(
// 合作身份者id,以2088开头的16位纯数字
'partner' => '2088701661478015',
// 安全检验码,以数字和字母组成的32位字符
'key' => 'kcxawi9bb07mzh0aq2wcirsf9znusobw',
// 签名方式,不需要修改
'sign_type' => 'MD5',
// 字符编码格式 目前支持 gbk 或 utf-8
'input_charset' => 'utf-8',
// ca证书路径地址,用于curl中ssl校验 (请保证cacert.pem文件在当前文件夹目录中)
'cacert' => dirname(__FILE__) . '/cacert.pem',
// 访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
'transport' => 'http',
// 页面跳转同步通知页面路径 (需http://格式的完整路径,不允许加?id=123这类自定义参数)
'return_url' => SITE_MAIN . '/passport/login/alipaycallback',
);
<?php
defined('SITE_MAIN') || define('SITE_MAIN', $_SERVER['HTTP_HOST']);
return array(
// 合作身份者id,以2088开头的16位纯数字
'partner' => '2088701661478015',
// 安全检验码,以数字和字母组成的32位字符
'key' => 'kcxawi9bb07mzh0aq2wcirsf9znusobw',
// 签名方式,不需要修改
'sign_type' => 'MD5',
// 字符编码格式 目前支持 gbk 或 utf-8
'input_charset' => 'utf-8',
// ca证书路径地址,用于curl中ssl校验 (请保证cacert.pem文件在当前文件夹目录中)
'cacert' => dirname(__FILE__) .'/cacert.pem',
// 访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
'transport' => 'http',
// 页面跳转同步通知页面路径 (需http://格式的完整路径,不允许加?id=123这类自定义参数)
'return_url' => SITE_MAIN . '/passport/login/alipaycallback',
);
... ...
<?php
/**
* 支付宝通知处理类
*
* 调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常
*
* @name AlipayNotify
* @package lib/partner/alipay
* @copyright yoho.inc
* @version 5.0 (2014-03-06 16:41:20)
* @author fei.hong <fei.hong@yoho.cn>
*/
class AlipayNotify
{
/**
* HTTPS形式消息验证地址
*/
var $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&';
/**
* HTTP形式消息验证地址
*/
var $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?';
/**
* 支付宝配置
*/
var $alipay_config = array();
function __construct($alipay_config)
{
$this->alipay_config = $alipay_config;
}
function AlipayNotify($alipay_config)
{
$this->__construct($alipay_config);
}
/**
* 针对notify_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
function verifyNotify()
{
if (empty($_POST)) { //判断POST来的数组是否为空
return false;
} else {
//生成签名结果
$isSign = $this->getSignVeryfy($_POST, $_POST["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'true';
if (!empty($_POST["notify_id"])) {
$responseTxt = $this->getResponse($_POST["notify_id"]);
}
//写日志记录
//if ($isSign) {
// $isSignStr = 'true';
//}
//else {
// $isSignStr = 'false';
//}
//$log_text = "responseTxt=".$responseTxt."\n notify_url_log:isSign=".$isSignStr.",";
//$log_text = $log_text.createLinkString($_POST);
//logResult($log_text);
//验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i", $responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
}
/**
* 针对return_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
function verifyReturn()
{
if (empty($_GET)) {//判断POST来的数组是否为空
return false;
} else {
//生成签名结果
$isSign = $this->getSignVeryfy($_GET, $_GET["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'true';
if (!empty($_GET["notify_id"])) {
$responseTxt = $this->getResponse($_GET["notify_id"]);
}
//写日志记录
//if ($isSign) {
// $isSignStr = 'true';
//}
//else {
// $isSignStr = 'false';
//}
//$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.",";
//$log_text = $log_text.createLinkString($_GET);
//logResult($log_text);
//验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i", $responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
}
/**
* 获取返回时的签名验证结果
* @param $para_temp 通知返回来的参数数组
* @param $sign 返回的签名结果
* @return 签名验证结果
*/
function getSignVeryfy($para_temp, $sign)
{
//除去待签名参数数组中的空值和签名参数
$para_filter = paraFilter($para_temp);
//对待签名参数数组排序
$para_sort = argSort($para_filter);
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = createLinkstring($para_sort);
$isSgin = false;
switch ($this->alipay_config['sign_type']) {
case "MD5" :
$isSgin = md5Verify($prestr, $sign, $this->alipay_config['key']);
break;
default :
$isSgin = false;
}
return $isSgin;
}
/**
* 获取远程服务器ATN结果,验证返回URL
* @param $notify_id 通知校验ID
* @return 服务器ATN结果
* 验证结果集:
* invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
* true 返回正确信息
* false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
*/
function getResponse($notify_id)
{
$transport = $this->alipay_config['transport'];
$partner = $this->alipay_config['partner'];
$veryfy_url = '';
if ($transport == 'https') {
$veryfy_url = $this->https_verify_url;
} else {
$veryfy_url = $this->http_verify_url;
}
$veryfy_url = $veryfy_url . "partner=" . $partner . "&notify_id=" . $notify_id;
$responseTxt = getHttpResponseGET($veryfy_url, $this->alipay_config['cacert']);
return $responseTxt;
}
}
?>
<?php
/**
* 支付宝通知处理类
*
* 调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常
*
* @name AlipayNotify
* @package lib/partner/alipay
* @copyright yoho.inc
* @version 5.0 (2014-03-06 16:41:20)
* @author fei.hong <fei.hong@yoho.cn>
*/
class AlipayNotify {
/**
* HTTPS形式消息验证地址
*/
var $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&';
/**
* HTTP形式消息验证地址
*/
var $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?';
/**
* 支付宝配置
*/
var $alipay_config = array();
function __construct($alipay_config){
$this->alipay_config = $alipay_config;
}
function AlipayNotify($alipay_config) {
$this->__construct($alipay_config);
}
/**
* 针对notify_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
function verifyNotify(){
if (empty($_POST)) { //判断POST来的数组是否为空
return false;
} else {
//生成签名结果
$isSign = $this->getSignVeryfy($_POST, $_POST["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'true';
if (! empty($_POST["notify_id"])) {$responseTxt = $this->getResponse($_POST["notify_id"]);}
//写日志记录
//if ($isSign) {
// $isSignStr = 'true';
//}
//else {
// $isSignStr = 'false';
//}
//$log_text = "responseTxt=".$responseTxt."\n notify_url_log:isSign=".$isSignStr.",";
//$log_text = $log_text.createLinkString($_POST);
//logResult($log_text);
//验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i",$responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
}
/**
* 针对return_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
function verifyReturn(){
if(empty($_GET)) {//判断POST来的数组是否为空
return false;
}
else {
//生成签名结果
$isSign = $this->getSignVeryfy($_GET, $_GET["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'true';
if (! empty($_GET["notify_id"])) {$responseTxt = $this->getResponse($_GET["notify_id"]);}
//写日志记录
//if ($isSign) {
// $isSignStr = 'true';
//}
//else {
// $isSignStr = 'false';
//}
//$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.",";
//$log_text = $log_text.createLinkString($_GET);
//logResult($log_text);
//验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i",$responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
}
/**
* 获取返回时的签名验证结果
* @param $para_temp 通知返回来的参数数组
* @param $sign 返回的签名结果
* @return 签名验证结果
*/
function getSignVeryfy($para_temp, $sign) {
//除去待签名参数数组中的空值和签名参数
$para_filter = paraFilter($para_temp);
//对待签名参数数组排序
$para_sort = argSort($para_filter);
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = createLinkstring($para_sort);
$isSgin = false;
switch ($this->alipay_config['sign_type']) {
case "MD5" :
$isSgin = md5Verify($prestr, $sign, $this->alipay_config['key']);
break;
default :
$isSgin = false;
}
return $isSgin;
}
/**
* 获取远程服务器ATN结果,验证返回URL
* @param $notify_id 通知校验ID
* @return 服务器ATN结果
* 验证结果集:
* invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
* true 返回正确信息
* false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
*/
function getResponse($notify_id) {
$transport = $this->alipay_config['transport'];
$partner = $this->alipay_config['partner'];
$veryfy_url = '';
if($transport == 'https') {
$veryfy_url = $this->https_verify_url;
}
else {
$veryfy_url = $this->http_verify_url;
}
$veryfy_url = $veryfy_url."partner=" . $partner . "&notify_id=" . $notify_id;
$responseTxt = getHttpResponseGET($veryfy_url, $this->alipay_config['cacert']);
return $responseTxt;
}
}
?>
... ...
<?php
/**
* 支付宝各接口请求提交类
*
* @name AlipaySubmit
* @package lib/partner/alipay
* @copyright yoho.inc
* @version 5.0 (2014-03-06 16:23:47)
* @author fei.hong <fei.hong@yoho.cn>
*/
class AlipaySubmit
{
/**
* 支付宝配置
*/
var $alipay_config = array();
/**
* 支付宝网关地址(新)
*/
var $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?';
function __construct($alipay_config)
{
$this->alipay_config = $alipay_config;
}
function AlipaySubmit($alipay_config)
{
$this->__construct($alipay_config);
}
/**
* 生成签名结果
* @param $para_sort 已排序要签名的数组
* return 签名结果字符串
*/
function buildRequestMysign($para_sort)
{
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = createLinkstring($para_sort);
$mysign = '';
switch ($this->alipay_config['sign_type']) {
case 'MD5' :
$mysign = md5Sign($prestr, $this->alipay_config['key']);
break;
default :
$mysign = '';
}
return $mysign;
}
/**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组
*/
function buildRequestPara($para_temp)
{
//除去待签名参数数组中的空值和签名参数
$para_filter = paraFilter($para_temp);
//对待签名参数数组排序
$para_sort = argSort($para_filter);
//生成签名结果
$mysign = $this->buildRequestMysign($para_sort);
//签名结果与签名方式加入请求提交参数组中
$para_sort['sign'] = $mysign;
$para_sort['sign_type'] = $this->alipay_config['sign_type'];
return $para_sort;
}
/**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组字符串
*/
function buildRequestParaToString($para_temp)
{
//待请求参数数组
$para = $this->buildRequestPara($para_temp);
//把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
$request_data = createLinkstringUrlencode($para);
return $request_data;
}
/**
* 建立请求,以表单HTML形式构造(默认)
* @param $para_temp 请求参数数组
* @param $method 提交方式。两个值可选:post、get
* @param $button_name 确认按钮显示文字
* @return 提交表单HTML文本
*/
function buildRequestForm($para_temp, $method)
{
//待请求参数数组
$para = $this->buildRequestPara($para_temp);
$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->alipay_gateway_new . "_input_charset=" . $this->alipay_config['input_charset'] . "' method='" . $method . "'>";
while (list ($key, $val) = each($para)) {
$sHtml.= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
}
$sHtml = $sHtml . "<script>document.forms['alipaysubmit'].submit();</script>";
return $sHtml;
}
/**
* 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
* @param $para_temp 请求参数数组
* @return 支付宝处理结果
*/
function buildRequestHttp($para_temp)
{
$sResult = '';
//待请求参数数组字符串
$request_data = $this->buildRequestPara($para_temp);
//远程获取数据
$sResult = getHttpResponsePOST($this->alipay_gateway_new, $this->alipay_config['cacert'], $request_data, $this->alipay_config['input_charset']);
return $sResult;
}
/**
* 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果,带文件上传功能
* @param $para_temp 请求参数数组
* @param $file_para_name 文件类型的参数名
* @param $file_name 文件完整绝对路径
* @return 支付宝返回处理结果
*/
function buildRequestHttpInFile($para_temp, $file_para_name, $file_name)
{
//待请求参数数组
$para = $this->buildRequestPara($para_temp);
$para[$file_para_name] = "@" . $file_name;
//远程获取数据
$sResult = getHttpResponsePOST($this->alipay_gateway_new, $this->alipay_config['cacert'], $para, $this->alipay_config['input_charset']);
return $sResult;
}
/**
* 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
* 注意:该功能PHP5环境及以上支持,因此必须服务器、本地电脑中装有支持DOMDocument、SSL的PHP配置环境。建议本地调试时使用PHP开发软件
* return 时间戳字符串
*/
function query_timestamp()
{
$url = $this->alipay_gateway_new . "service=query_timestamp&partner=" . $this->alipay_config['partner'] . "&_input_charset=" . $this->alipay_config['input_charset'];
$encrypt_key = "";
$doc = new DOMDocument();
$doc->load($url);
$itemEncrypt_key = $doc->getElementsByTagName("encrypt_key");
$encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
return $encrypt_key;
}
/**
* 通过token获取用户信息
*
* @param array $parameter 参数项
* @return array
* @since 1.0.3
*/
function getUserInfoByToken($parameter)
{
$parameter = $this->buildRequestPara($parameter);
// 系统参数放入GET请求串
$requestUrl = $this->alipay_gateway_new . http_build_query($parameter, null, '&');
// 发起HTTP请求
$result = array();
try {
$response = getHttpResponseGET($requestUrl, $this->alipay_config['cacert']);
if (is_string($response)) {
$result = json_decode(json_encode(simplexml_load_string($response)), true);
}
} catch (Exception $e) {
// do nothing
}
return $result;
}
}
<?php
/**
* 支付宝各接口请求提交类
*
* @name AlipaySubmit
* @package lib/partner/alipay
* @copyright yoho.inc
* @version 5.0 (2014-03-06 16:23:47)
* @author fei.hong <fei.hong@yoho.cn>
*/
class AlipaySubmit {
/**
* 支付宝配置
*/
var $alipay_config = array();
/**
* 支付宝网关地址(新)
*/
var $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?';
function __construct($alipay_config){
$this->alipay_config = $alipay_config;
}
function AlipaySubmit($alipay_config) {
$this->__construct($alipay_config);
}
/**
* 生成签名结果
* @param $para_sort 已排序要签名的数组
* return 签名结果字符串
*/
function buildRequestMysign($para_sort) {
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = createLinkstring($para_sort);
$mysign = '';
switch ($this->alipay_config['sign_type']) {
case 'MD5' :
$mysign = md5Sign($prestr, $this->alipay_config['key']);
break;
default :
$mysign = '';
}
return $mysign;
}
/**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组
*/
function buildRequestPara($para_temp) {
//除去待签名参数数组中的空值和签名参数
$para_filter = paraFilter($para_temp);
//对待签名参数数组排序
$para_sort = argSort($para_filter);
//生成签名结果
$mysign = $this->buildRequestMysign($para_sort);
//签名结果与签名方式加入请求提交参数组中
$para_sort['sign'] = $mysign;
$para_sort['sign_type'] = $this->alipay_config['sign_type'];
return $para_sort;
}
/**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组字符串
*/
function buildRequestParaToString($para_temp) {
//待请求参数数组
$para = $this->buildRequestPara($para_temp);
//把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
$request_data = createLinkstringUrlencode($para);
return $request_data;
}
/**
* 建立请求,以表单HTML形式构造(默认)
* @param $para_temp 请求参数数组
* @param $method 提交方式。两个值可选:post、get
* @param $button_name 确认按钮显示文字
* @return 提交表单HTML文本
*/
function buildRequestForm($para_temp, $method) {
//待请求参数数组
$para = $this->buildRequestPara($para_temp);
$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->alipay_gateway_new."_input_charset=".$this->alipay_config['input_charset']."' method='".$method."'>";
while (list ($key, $val) = each ($para)) {
$sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
}
$sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";
return $sHtml;
}
/**
* 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
* @param $para_temp 请求参数数组
* @return 支付宝处理结果
*/
function buildRequestHttp($para_temp) {
$sResult = '';
//待请求参数数组字符串
$request_data = $this->buildRequestPara($para_temp);
//远程获取数据
$sResult = getHttpResponsePOST($this->alipay_gateway_new, $this->alipay_config['cacert'],$request_data,$this->alipay_config['input_charset']);
return $sResult;
}
/**
* 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果,带文件上传功能
* @param $para_temp 请求参数数组
* @param $file_para_name 文件类型的参数名
* @param $file_name 文件完整绝对路径
* @return 支付宝返回处理结果
*/
function buildRequestHttpInFile($para_temp, $file_para_name, $file_name) {
//待请求参数数组
$para = $this->buildRequestPara($para_temp);
$para[$file_para_name] = "@".$file_name;
//远程获取数据
$sResult = getHttpResponsePOST($this->alipay_gateway_new, $this->alipay_config['cacert'],$para,$this->alipay_config['input_charset']);
return $sResult;
}
/**
* 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
* 注意:该功能PHP5环境及以上支持,因此必须服务器、本地电脑中装有支持DOMDocument、SSL的PHP配置环境。建议本地调试时使用PHP开发软件
* return 时间戳字符串
*/
function query_timestamp() {
$url = $this->alipay_gateway_new."service=query_timestamp&partner=".$this->alipay_config['partner']."&_input_charset=".$this->alipay_config['input_charset'];
$encrypt_key = "";
$doc = new DOMDocument();
$doc->load($url);
$itemEncrypt_key = $doc->getElementsByTagName( "encrypt_key" );
$encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
return $encrypt_key;
}
/**
* 通过token获取用户信息
*
* @param array $parameter 参数项
* @return array
* @since 1.0.3
*/
function getUserInfoByToken($parameter) {
$parameter = $this->buildRequestPara($parameter);
// 系统参数放入GET请求串
$requestUrl = $this->alipay_gateway_new . http_build_query($parameter, null, '&');
// 发起HTTP请求
$result = array();
try {
$response = getHttpResponseGET($requestUrl, $this->alipay_config['cacert']);
if (is_string($response)) {
$result = json_decode(json_encode(simplexml_load_string($response)), true);
}
} catch (Exception $e) {
// do nothing
}
return $result;
}
}
?>
\ No newline at end of file
... ...
<?php
/* *
* 支付宝接口公用函数
* 详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件
* 版本:3.3
* 日期:2012-07-19
* 说明:
* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
* 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
/**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
function createLinkstring($para)
{
$arg = "";
while (list ($key, $val) = each($para)) {
$arg.=$key . "=" . $val . "&";
}
//去掉最后一个&字符
$arg = substr($arg, 0, count($arg) - 2);
//如果存在转义字符,那么去掉转义
if (get_magic_quotes_gpc()) {
$arg = stripslashes($arg);
}
return $arg;
}
/**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
function createLinkstringUrlencode($para)
{
$arg = "";
while (list ($key, $val) = each($para)) {
$arg.=$key . "=" . urlencode($val) . "&";
}
//去掉最后一个&字符
$arg = substr($arg, 0, count($arg) - 2);
//如果存在转义字符,那么去掉转义
if (get_magic_quotes_gpc()) {
$arg = stripslashes($arg);
}
return $arg;
}
/**
* 除去数组中的空值和签名参数
* @param $para 签名参数组
* return 去掉空值与签名参数后的新签名参数组
*/
function paraFilter($para)
{
$para_filter = array();
while (list ($key, $val) = each($para)) {
if ($key == "sign" || $key == "sign_type" || $val == "")
continue;
else
$para_filter[$key] = $para[$key];
}
return $para_filter;
}
/**
* 对数组排序
* @param $para 排序前的数组
* return 排序后的数组
*/
function argSort($para)
{
ksort($para);
reset($para);
return $para;
}
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* 注意:服务器需要开通fopen配置
* @param $word 要写入日志里的文本内容 默认值:空值
*/
function logResult($word = '')
{
$fp = fopen("log.txt", "a");
flock($fp, LOCK_EX);
fwrite($fp, "执行日期:" . strftime("%Y%m%d%H%M%S", time()) . "\n" . $word . "\n");
flock($fp, LOCK_UN);
fclose($fp);
}
/**
* 远程获取数据,POST模式
* 注意:
* 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
* 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
* @param $url 指定URL完整路径地址
* @param $cacert_url 指定当前工作目录绝对路径
* @param $para 请求的数据
* @param $input_charset 编码格式。默认值:空值
* return 远程输出的数据
*/
function getHttpResponsePOST($url, $cacert_url, $para, $input_charset = '')
{
if (trim($input_charset) != '') {
$url = $url . "_input_charset=" . $input_charset;
}
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); //SSL证书认证
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); //严格认证
curl_setopt($curl, CURLOPT_CAINFO, $cacert_url); //证书地址
curl_setopt($curl, CURLOPT_HEADER, 0); // 过滤HTTP头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 显示输出结果
curl_setopt($curl, CURLOPT_POST, true); // post传输数据
curl_setopt($curl, CURLOPT_POSTFIELDS, $para); // post传输数据
$responseText = curl_exec($curl);
//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
curl_close($curl);
return $responseText;
}
/**
* 远程获取数据,GET模式
* 注意:
* 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
* 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
* @param $url 指定URL完整路径地址
* @param $cacert_url 指定当前工作目录绝对路径
* return 远程输出的数据
*/
function getHttpResponseGET($url, $cacert_url)
{
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, 0); // 过滤HTTP头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 显示输出结果
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); //SSL证书认证
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); //严格认证
curl_setopt($curl, CURLOPT_CAINFO, $cacert_url); //证书地址
$responseText = curl_exec($curl);
//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
curl_close($curl);
return $responseText;
}
/**
* 实现多种字符编码方式
* @param $input 需要编码的字符串
* @param $_output_charset 输出的编码格式
* @param $_input_charset 输入的编码格式
* return 编码后的字符串
*/
function charsetEncode($input, $_output_charset, $_input_charset)
{
$output = "";
if (!isset($_output_charset))
$_output_charset = $_input_charset;
if ($_input_charset == $_output_charset || $input == null) {
$output = $input;
} elseif (function_exists("mb_convert_encoding")) {
$output = mb_convert_encoding($input, $_output_charset, $_input_charset);
} elseif (function_exists("iconv")) {
$output = iconv($_input_charset, $_output_charset, $input);
} else
die("sorry, you have no libs support for charset change.");
return $output;
}
/**
* 实现多种字符解码方式
* @param $input 需要解码的字符串
* @param $_output_charset 输出的解码格式
* @param $_input_charset 输入的解码格式
* return 解码后的字符串
*/
function charsetDecode($input, $_input_charset, $_output_charset)
{
$output = "";
if (!isset($_input_charset))
$_input_charset = $_input_charset;
if ($_input_charset == $_output_charset || $input == null) {
$output = $input;
} elseif (function_exists("mb_convert_encoding")) {
$output = mb_convert_encoding($input, $_output_charset, $_input_charset);
} elseif (function_exists("iconv")) {
$output = iconv($_input_charset, $_output_charset, $input);
} else
die("sorry, you have no libs support for charset changes.");
return $output;
}
/** MD5加密 * */
/**
* 签名字符串
* @param $prestr 需要签名的字符串
* @param $key 私钥
* return 签名结果
*/
function md5Sign($prestr, $key)
{
$prestr = $prestr . $key;
return md5($prestr);
}
/**
* 验证签名
* @param $prestr 需要签名的字符串
* @param $sign 签名结果
* @param $key 私钥
* return 签名结果
*/
function md5Verify($prestr, $sign, $key)
{
$prestr = $prestr . $key;
$mysgin = md5($prestr);
if ($mysgin == $sign) {
return true;
} else {
return false;
}
}
<?php
/* *
* 支付宝接口公用函数
* 详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件
* 版本:3.3
* 日期:2012-07-19
* 说明:
* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
* 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
/**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
function createLinkstring($para) {
$arg = "";
while (list ($key, $val) = each ($para)) {
$arg.=$key."=".$val."&";
}
//去掉最后一个&字符
$arg = substr($arg,0,count($arg)-2);
//如果存在转义字符,那么去掉转义
if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
return $arg;
}
/**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
function createLinkstringUrlencode($para) {
$arg = "";
while (list ($key, $val) = each ($para)) {
$arg.=$key."=".urlencode($val)."&";
}
//去掉最后一个&字符
$arg = substr($arg,0,count($arg)-2);
//如果存在转义字符,那么去掉转义
if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
return $arg;
}
/**
* 除去数组中的空值和签名参数
* @param $para 签名参数组
* return 去掉空值与签名参数后的新签名参数组
*/
function paraFilter($para) {
$para_filter = array();
while (list ($key, $val) = each ($para)) {
if($key == "sign" || $key == "sign_type" || $val == "")continue;
else $para_filter[$key] = $para[$key];
}
return $para_filter;
}
/**
* 对数组排序
* @param $para 排序前的数组
* return 排序后的数组
*/
function argSort($para) {
ksort($para);
reset($para);
return $para;
}
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* 注意:服务器需要开通fopen配置
* @param $word 要写入日志里的文本内容 默认值:空值
*/
function logResult($word='') {
$fp = fopen("log.txt","a");
flock($fp, LOCK_EX) ;
fwrite($fp,"执行日期:".strftime("%Y%m%d%H%M%S",time())."\n".$word."\n");
flock($fp, LOCK_UN);
fclose($fp);
}
/**
* 远程获取数据,POST模式
* 注意:
* 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
* 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
* @param $url 指定URL完整路径地址
* @param $cacert_url 指定当前工作目录绝对路径
* @param $para 请求的数据
* @param $input_charset 编码格式。默认值:空值
* return 远程输出的数据
*/
function getHttpResponsePOST($url, $cacert_url, $para, $input_charset = '') {
if (trim($input_charset) != '') {
$url = $url."_input_charset=".$input_charset;
}
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
curl_setopt($curl,CURLOPT_POST,true); // post传输数据
curl_setopt($curl,CURLOPT_POSTFIELDS,$para);// post传输数据
$responseText = curl_exec($curl);
//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
curl_close($curl);
return $responseText;
}
/**
* 远程获取数据,GET模式
* 注意:
* 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
* 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
* @param $url 指定URL完整路径地址
* @param $cacert_url 指定当前工作目录绝对路径
* return 远程输出的数据
*/
function getHttpResponseGET($url,$cacert_url) {
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
$responseText = curl_exec($curl);
//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
curl_close($curl);
return $responseText;
}
/**
* 实现多种字符编码方式
* @param $input 需要编码的字符串
* @param $_output_charset 输出的编码格式
* @param $_input_charset 输入的编码格式
* return 编码后的字符串
*/
function charsetEncode($input,$_output_charset ,$_input_charset) {
$output = "";
if(!isset($_output_charset) )$_output_charset = $_input_charset;
if($_input_charset == $_output_charset || $input ==null ) {
$output = $input;
} elseif (function_exists("mb_convert_encoding")) {
$output = mb_convert_encoding($input,$_output_charset,$_input_charset);
} elseif(function_exists("iconv")) {
$output = iconv($_input_charset,$_output_charset,$input);
} else die("sorry, you have no libs support for charset change.");
return $output;
}
/**
* 实现多种字符解码方式
* @param $input 需要解码的字符串
* @param $_output_charset 输出的解码格式
* @param $_input_charset 输入的解码格式
* return 解码后的字符串
*/
function charsetDecode($input,$_input_charset ,$_output_charset) {
$output = "";
if(!isset($_input_charset) )$_input_charset = $_input_charset ;
if($_input_charset == $_output_charset || $input ==null ) {
$output = $input;
} elseif (function_exists("mb_convert_encoding")) {
$output = mb_convert_encoding($input,$_output_charset,$_input_charset);
} elseif(function_exists("iconv")) {
$output = iconv($_input_charset,$_output_charset,$input);
} else die("sorry, you have no libs support for charset changes.");
return $output;
}
/** MD5加密 **/
/**
* 签名字符串
* @param $prestr 需要签名的字符串
* @param $key 私钥
* return 签名结果
*/
function md5Sign($prestr, $key) {
$prestr = $prestr . $key;
return md5($prestr);
}
/**
* 验证签名
* @param $prestr 需要签名的字符串
* @param $sign 签名结果
* @param $key 私钥
* return 签名结果
*/
function md5Verify($prestr, $sign, $key) {
$prestr = $prestr . $key;
$mysgin = md5($prestr);
if($mysgin == $sign) {
return true;
}
else {
return false;
}
}
?>
\ No newline at end of file
... ...
<?php
namespace Plugin\Partner\qqconnect;
use Plugin\Partner\Factory;
define('QC_CLASS_PATH', dirname(__FILE__) . '/class/');
require QC_CLASS_PATH . 'QC.class.php';
/**
* 腾讯QQ互联的调用接口
*
* @name Call
* @package lib/partner/qqconnect
* @copyright yoho.inc
* @version 4.0 (2013-12-19 11:42:11)
* @author fei.hong <fei.hong@yoho.cn>
*/
class Call extends Factory
{
/* QQ互联对象 */
protected $qc;
/**
* 初始化
*/
protected function init()
{
$this->qc = new \QC();
}
/**
* 获取授权URL
*
* @return string
*/
public function getAuthorizeUrl()
{
return $this->qc->qq_login();
}
/**
* 获取授权的TOKEN
*
* @return array
*/
public function getAccessToken()
{
$token = array();
// try
// {
$token = $this->qc->qq_callback();
$token['openid'] = $this->qc->get_openid();
// }
// catch (Exception $e)
// {
// // do nothing
// }
return $token;
}
/**
* 获取当前用户的基本资料
*
* @param array $token 授权成功的TOKEN, 默认为NULL
* @return array
*/
public function getUserInfo($token)
{
$userInfo = array();
if (is_array($token) && isset($token['openid'])) {
$this->qc = new \QC($token['access_token'], $token['openid']);
$userInfo = $this->qc->get_user_info();
if (isset($userInfo['ret']) && $userInfo['ret'] != 0) {
$userInfo = array();
}
}
return $userInfo;
}
/**
* 获取当前用户的偶像(关注)列表
*
* @see http://wiki.connect.qq.com/get_idollist
* @param string $access_token 访问令牌
* @param string $openid 腾讯唯一的对应QQ号
* @param array $params 参数列表
* format 是 返回数据的格式(json或xml)
* reqnum 是 请求个数(1-30)
* startindex 是 起始位置(第一页:填0,继续向下翻页:填上次请求返回的nextstartpos)
* mode 是 获取模式,默认为0
* mode=0,新粉丝在前,只能拉取1000个
* mode=1,最多可拉取一万粉丝,暂不支持排序
* install 否 过滤安装应用好友(可选)
* 0-不考虑该参数,1-获取已安装应用好友,2-获取未安装应用好友
* sex 否 按性别过滤标识,1-男,2-女,0-不进行性别过滤,默认为0,支持排序
* @return array
*/
public function getFriends($token, $params)
{
$friends = array();
if (is_array($token) && isset($token['openid'])) {
$this->qc = new \QC($token['access_token'], $token['openid']);
$friends = $this->qc->get_idollist($params);
if (isset($friends['ret']) && $friends['ret'] != 0) {
$friends = array();
}
}
return $friends;
}
/**
* 同步分享
*
* @param array $token 授权成功的TOKEN
* @param string $content 要更新的微博信息。信息内容不超过140个汉字, 为空返回400错误。
* @param string $image 要发布的图片路径, 支持url。[只支持png/jpg/gif三种格式, 增加格式请修改get_image_mime方法]
* @param string $link URL地址, 通过该地址链接回来
* @return boolean false:失败, true:成功
*/
public function syncShare($token, $content, $image, $link)
{
$result = false;
if (is_array($token) && isset($token['openid'])) {
$this->qc = new \QC($token['access_token'], $token['openid']);
$param = array('title' => '来自YOHO.CN的分享', 'url' => $link, 'summary' => $content,
'images' => $image, 'site' => 'yoho.cn', 'fromurl' => SITE_MAIN,);
$response = $this->qc->add_share($param);
if (isset($response['ret']) && $response['ret'] == 0) {
$result = true;
}
}
return $result;
}
}
<?php
namespace Plugin\Partner\qqconnect;
use Plugin\Partner\Factory;
define('QC_CLASS_PATH', dirname (__FILE__) . '/class/');
require QC_CLASS_PATH . 'QC.class.php';
/**
* 腾讯QQ互联的调用接口
*
* @name Call
* @package lib/partner/qqconnect
* @copyright yoho.inc
* @version 4.0 (2013-12-19 11:42:11)
* @author fei.hong <fei.hong@yoho.cn>
*/
class Call extends Factory
{
/*QQ互联对象*/
protected $qc;
/**
* 初始化
*/
protected function init()
{
$this->qc = new \QC();
}
/**
* 获取授权URL
*
* @return string
*/
public function getAuthorizeUrl()
{
return $this->qc->qq_login();
}
/**
* 获取授权的TOKEN
*
* @return array
*/
public function getAccessToken()
{
$token = array();
// try
// {
$token = $this->qc->qq_callback();
$token['openid'] = $this->qc->get_openid();
// }
// catch (Exception $e)
// {
// // do nothing
// }
return $token;
}
/**
* 获取当前用户的基本资料
*
* @param array $token 授权成功的TOKEN, 默认为NULL
* @return array
*/
public function getUserInfo($token)
{
$userInfo = array();
if (is_array($token) && isset($token['openid']))
{
$this->qc = new \QC($token['access_token'], $token['openid']);
$userInfo = $this->qc->get_user_info();
if (isset($userInfo['ret']) && $userInfo['ret'] != 0)
{
$userInfo = array();
}
}
return $userInfo;
}
/**
* 获取当前用户的偶像(关注)列表
*
* @see http://wiki.connect.qq.com/get_idollist
* @param string $access_token 访问令牌
* @param string $openid 腾讯唯一的对应QQ号
* @param array $params 参数列表
* format 是 返回数据的格式(json或xml)
* reqnum 是 请求个数(1-30)
* startindex 是 起始位置(第一页:填0,继续向下翻页:填上次请求返回的nextstartpos)
* mode 是 获取模式,默认为0
* mode=0,新粉丝在前,只能拉取1000个
* mode=1,最多可拉取一万粉丝,暂不支持排序
* install 否 过滤安装应用好友(可选)
* 0-不考虑该参数,1-获取已安装应用好友,2-获取未安装应用好友
* sex 否 按性别过滤标识,1-男,2-女,0-不进行性别过滤,默认为0,支持排序
* @return array
*/
public function getFriends($token, $params)
{
$friends = array();
if (is_array($token) && isset($token['openid']))
{
$this->qc = new \QC($token['access_token'], $token['openid']);
$friends = $this->qc->get_idollist($params);
if (isset($friends['ret']) && $friends['ret'] != 0)
{
$friends = array();
}
}
return $friends;
}
/**
* 同步分享
*
* @param array $token 授权成功的TOKEN
* @param string $content 要更新的微博信息。信息内容不超过140个汉字, 为空返回400错误。
* @param string $image 要发布的图片路径, 支持url。[只支持png/jpg/gif三种格式, 增加格式请修改get_image_mime方法]
* @param string $link URL地址, 通过该地址链接回来
* @return boolean false:失败, true:成功
*/
public function syncShare($token, $content, $image, $link)
{
$result = false;
if (is_array($token) && isset($token['openid']))
{
$this->qc = new \QC($token['access_token'], $token['openid']);
$param = array('title' => '来自YOHO.CN的分享', 'url' => $link, 'summary' => $content,
'images' => $image, 'site' => 'yoho.cn', 'fromurl' => SITE_MAIN,);
$response = $this->qc->add_share($param);
if (isset($response['ret']) && $response['ret'] == 0)
{
$result = true;
}
}
return $result;
}
}
\ No newline at end of file
... ...
<?php
defined('SITE_MAIN') || define('SITE_MAIN', $_SERVER['HTTP_HOST']);
return array(
'appid' => '100229394',
'appkey' => 'c0af9c29e0900813028c2ccb42021792',
'callback' => SITE_MAIN . '/passport/login/qqcallback',
'scope' => 'get_user_info,add_share,upload_pic,get_idollist,get_fanslist',
'errorReport' => true,
);
<?php
defined('SITE_MAIN') || define('SITE_MAIN', $_SERVER['HTTP_HOST']);
return array(
'appid' => '100229394',
'appkey' => 'c0af9c29e0900813028c2ccb42021792',
'callback' => SITE_MAIN . '/passport/login/qqcallback',
'scope' => 'get_user_info,add_share,upload_pic,get_idollist,get_fanslist',
'errorReport' => true,
);
\ No newline at end of file
... ...
<?php
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
require_once(QC_CLASS_PATH . 'Recorder.class.php');
/*
* @brief ErrorCase类,封闭异常
* */
class ErrorCase
{
private $errorMsg;
public function __construct()
{
$this->errorMsg = array(
"20001" => "<h2>配置文件损坏或无法读取,请重新执行intall</h2>",
"30001" => "<h2>The state does not match. You may be a victim of CSRF.</h2>",
"50001" => "<h2>可能是服务器无法请求https协议</h2>可能未开启curl支持,请尝试开启curl支持,重启web服务器,如果问题仍未解决,请联系我们"
);
}
/**
* showError
* 显示错误信息
* @param int $code 错误代码
* @param string $description 描述信息(可选)
*/
public function showError($code, $description = '$')
{
$recorder = new Recorder();
if (!$recorder->readInc("errorReport")) {
die(); //die quietly
}
echo "<meta charset=\"UTF-8\">";
if ($description == "$") {
die($this->errorMsg[$code]);
} else {
echo "<h3>error:</h3>$code";
echo "<h3>msg :</h3>$description";
exit();
}
}
public function showTips($code, $description = '$')
{
}
}
<?php
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
require_once(QC_CLASS_PATH.'Recorder.class.php');
/*
* @brief ErrorCase类,封闭异常
* */
class ErrorCase{
private $errorMsg;
public function __construct(){
$this->errorMsg = array(
"20001" => "<h2>配置文件损坏或无法读取,请重新执行intall</h2>",
"30001" => "<h2>The state does not match. You may be a victim of CSRF.</h2>",
"50001" => "<h2>可能是服务器无法请求https协议</h2>可能未开启curl支持,请尝试开启curl支持,重启web服务器,如果问题仍未解决,请联系我们"
);
}
/**
* showError
* 显示错误信息
* @param int $code 错误代码
* @param string $description 描述信息(可选)
*/
public function showError($code, $description = '$'){
$recorder = new Recorder();
if(! $recorder->readInc("errorReport")){
die();//die quietly
}
echo "<meta charset=\"UTF-8\">";
if($description == "$"){
die($this->errorMsg[$code]);
}else{
echo "<h3>error:</h3>$code";
echo "<h3>msg :</h3>$description";
exit();
}
}
public function showTips($code, $description = '$'){
}
}
... ...
<?php
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
require_once(QC_CLASS_PATH . 'Recorder.class.php');
require_once(QC_CLASS_PATH . 'URL.class.php');
require_once(QC_CLASS_PATH . 'ErrorCase.class.php');
use Hood\Session;
class Oauth
{
const VERSION = "2.0";
const GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize";
const GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
const GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me";
protected $recorder;
public $urlUtils;
protected $error;
function __construct()
{
$this->recorder = new Recorder();
$this->urlUtils = new URL();
$this->error = new ErrorCase();
}
public function qq_login()
{
$appid = $this->recorder->readInc("appid");
$callback = $this->recorder->readInc("callback");
$scope = $this->recorder->readInc("scope");
//-------生成唯一随机串防CSRF攻击
$state = md5(uniqid(rand(), TRUE));
// $this->recorder->write('state',$state);
//$_SESSION['qqstate'] = $state;
setcookie('_QQ_STATE', $state, 0, '/', '.yohobuy.com');
//-------构造请求参数列表
$keysArr = array(
"response_type" => "code",
"client_id" => $appid,
"redirect_uri" => $callback,
"state" => $state,
"scope" => $scope
);
$login_url = $this->urlUtils->combineURL(self::GET_AUTH_CODE_URL, $keysArr);
header("Location:$login_url");
}
public function qq_callback()
{
//$state = $this->recorder->read("state");
//--------验证state防止CSRF攻击
// if($_GET['state'] != $state){
$state = isset($_COOKIE['_QQ_STATE']) ? $_COOKIE['_QQ_STATE'] : null;
if ($_GET['state'] != $state) {
$this->error->showError("30001");
}
//-------请求参数列表
$keysArr = array(
"grant_type" => "authorization_code",
"client_id" => $this->recorder->readInc("appid"),
"redirect_uri" => urlencode($this->recorder->readInc("callback")),
"client_secret" => $this->recorder->readInc("appkey"),
"code" => $_GET['code']
);
//------构造请求access_token的url
$token_url = $this->urlUtils->combineURL(self::GET_ACCESS_TOKEN_URL, $keysArr);
$response = $this->urlUtils->get_contents($token_url);
if (strpos($response, "callback") !== false) {
$lpos = strpos($response, "(");
$rpos = strrpos($response, ")");
$response = substr($response, $lpos + 1, $rpos - $lpos - 1);
$msg = json_decode($response);
if (isset($msg->error)) {
$this->error->showError($msg->error, $msg->error_description);
}
}
$params = array();
parse_str($response, $params);
$this->recorder->write("access_token", $params["access_token"]);
// return $params["access_token"];
// 根据业务需要改造了一下
return $params;
}
public function get_openid()
{
//-------请求参数列表
$keysArr = array(
"access_token" => $this->recorder->read("access_token")
);
$graph_url = $this->urlUtils->combineURL(self::GET_OPENID_URL, $keysArr);
$response = $this->urlUtils->get_contents($graph_url);
//--------检测错误是否发生
if (strpos($response, "callback") !== false) {
$lpos = strpos($response, "(");
$rpos = strrpos($response, ")");
$response = substr($response, $lpos + 1, $rpos - $lpos - 1);
}
$user = json_decode($response);
if (isset($user->error)) {
$this->error->showError($user->error, $user->error_description);
}
//------记录openid
$this->recorder->write("openid", $user->openid);
return $user->openid;
}
}
<?php
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
require_once(QC_CLASS_PATH.'Recorder.class.php');
require_once(QC_CLASS_PATH.'URL.class.php');
require_once(QC_CLASS_PATH.'ErrorCase.class.php');
use Hood\Session;
class Oauth{
const VERSION = "2.0";
const GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize";
const GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
const GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me";
protected $recorder;
public $urlUtils;
protected $error;
function __construct(){
$this->recorder = new Recorder();
$this->urlUtils = new URL();
$this->error = new ErrorCase();
}
public function qq_login(){
$appid = $this->recorder->readInc("appid");
$callback = $this->recorder->readInc("callback");
$scope = $this->recorder->readInc("scope");
//-------生成唯一随机串防CSRF攻击
$state = md5(uniqid(rand(), TRUE));
// $this->recorder->write('state',$state);
//$_SESSION['qqstate'] = $state;
setcookie('_QQ_STATE', $state, 0, '/', '.yohobuy.com');
//-------构造请求参数列表
$keysArr = array(
"response_type" => "code",
"client_id" => $appid,
"redirect_uri" => $callback,
"state" => $state,
"scope" => $scope
);
$login_url = $this->urlUtils->combineURL(self::GET_AUTH_CODE_URL, $keysArr);
header("Location:$login_url");
}
public function qq_callback(){
//$state = $this->recorder->read("state");
//--------验证state防止CSRF攻击
// if($_GET['state'] != $state){
$state = isset($_COOKIE['_QQ_STATE']) ? $_COOKIE['_QQ_STATE'] : null;
if ($_GET['state'] != $state) {
$this->error->showError("30001");
}
//-------请求参数列表
$keysArr = array(
"grant_type" => "authorization_code",
"client_id" => $this->recorder->readInc("appid"),
"redirect_uri" => urlencode($this->recorder->readInc("callback")),
"client_secret" => $this->recorder->readInc("appkey"),
"code" => $_GET['code']
);
//------构造请求access_token的url
$token_url = $this->urlUtils->combineURL(self::GET_ACCESS_TOKEN_URL, $keysArr);
$response = $this->urlUtils->get_contents($token_url);
if(strpos($response, "callback") !== false){
$lpos = strpos($response, "(");
$rpos = strrpos($response, ")");
$response = substr($response, $lpos + 1, $rpos - $lpos -1);
$msg = json_decode($response);
if(isset($msg->error)){
$this->error->showError($msg->error, $msg->error_description);
}
}
$params = array();
parse_str($response, $params);
$this->recorder->write("access_token", $params["access_token"]);
// return $params["access_token"];
// 根据业务需要改造了一下
return $params;
}
public function get_openid(){
//-------请求参数列表
$keysArr = array(
"access_token" => $this->recorder->read("access_token")
);
$graph_url = $this->urlUtils->combineURL(self::GET_OPENID_URL, $keysArr);
$response = $this->urlUtils->get_contents($graph_url);
//--------检测错误是否发生
if(strpos($response, "callback") !== false){
$lpos = strpos($response, "(");
$rpos = strrpos($response, ")");
$response = substr($response, $lpos + 1, $rpos - $lpos -1);
}
$user = json_decode($response);
if(isset($user->error)){
$this->error->showError($user->error, $user->error_description);
}
//------记录openid
$this->recorder->write("openid", $user->openid);
return $user->openid;
}
}
... ...
<?php
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
require_once(QC_CLASS_PATH . 'Oauth.class.php');
/*
* @brief QC类,api外部对象,调用接口全部依赖于此对象
* */
class QC extends Oauth
{
private $kesArr, $APIMap;
/**
* _construct
*
* 构造方法
* @access public
* @since 5
* @param string $access_token access_token value
* @param string $openid openid value
* @return Object QC
*/
public function __construct($access_token = "", $openid = "")
{
parent::__construct();
//如果access_token和openid为空,则从session里去取,适用于demo展示情形
if ($access_token === "" || $openid === "") {
$this->keysArr = array(
"oauth_consumer_key" => (int) $this->recorder->readInc("appid"),
"access_token" => $this->recorder->read("access_token"),
"openid" => $this->recorder->read("openid")
);
} else {
$this->keysArr = array(
"oauth_consumer_key" => (int) $this->recorder->readInc("appid"),
"access_token" => $access_token,
"openid" => $openid
);
}
//初始化APIMap
/*
* 加#表示非必须,无则不传入url(url中不会出现该参数), "key" => "val" 表示key如果没有定义则使用默认值val
* 规则 array( baseUrl, argListArr, method)
*/
$this->APIMap = array(
/* qzone */
"add_blog" => array(
"https://graph.qq.com/blog/add_one_blog",
array("title", "format" => "json", "content" => null),
"POST"
),
"add_topic" => array(
"https://graph.qq.com/shuoshuo/add_topic",
array("richtype", "richval", "con", "#lbs_nm", "#lbs_x", "#lbs_y", "format" => "json", "#third_source"),
"POST"
),
"get_user_info" => array(
"https://graph.qq.com/user/get_user_info",
array("format" => "json"),
"GET"
),
"add_one_blog" => array(
"https://graph.qq.com/blog/add_one_blog",
array("title", "content", "format" => "json"),
"GET"
),
"add_album" => array(
"https://graph.qq.com/photo/add_album",
array("albumname", "#albumdesc", "#priv", "format" => "json"),
"POST"
),
"upload_pic" => array(
"https://graph.qq.com/photo/upload_pic",
array("picture", "#photodesc", "#title", "#albumid", "#mobile", "#x", "#y", "#needfeed", "#successnum", "#picnum", "format" => "json"),
"POST"
),
"list_album" => array(
"https://graph.qq.com/photo/list_album",
array("format" => "json")
),
"add_share" => array(
"https://graph.qq.com/share/add_share",
array("title", "url", "#comment", "#summary", "#images", "format" => "json", "#type", "#playurl", "#nswb", "site", "fromurl"),
"POST"
),
"check_page_fans" => array(
"https://graph.qq.com/user/check_page_fans",
array("page_id" => "314416946", "format" => "json")
),
/* wblog */
"add_t" => array(
"https://graph.qq.com/t/add_t",
array("format" => "json", "content", "#clientip", "#longitude", "#compatibleflag"),
"POST"
),
"add_pic_t" => array(
"https://graph.qq.com/t/add_pic_t",
array("content", "pic", "format" => "json", "#clientip", "#longitude", "#latitude", "#syncflag", "#compatiblefalg"),
"POST"
),
"del_t" => array(
"https://graph.qq.com/t/del_t",
array("id", "format" => "json"),
"POST"
),
"get_repost_list" => array(
"https://graph.qq.com/t/get_repost_list",
array("flag", "rootid", "pageflag", "pagetime", "reqnum", "twitterid", "format" => "json")
),
"get_info" => array(
"https://graph.qq.com/user/get_info",
array("format" => "json")
),
"get_other_info" => array(
"https://graph.qq.com/user/get_other_info",
array("format" => "json", "#name", "fopenid")
),
"get_fanslist" => array(
"https://graph.qq.com/relation/get_fanslist",
array("format" => "json", "reqnum", "startindex", "#mode", "#install", "#sex")
),
"get_idollist" => array(
"https://graph.qq.com/relation/get_idollist",
array("format" => "json", "reqnum", "startindex", "#mode", "#install")
),
"add_idol" => array(
"https://graph.qq.com/relation/add_idol",
array("format" => "json", "#name-1", "#fopenids-1"),
"POST"
),
"del_idol" => array(
"https://graph.qq.com/relation/del_idol",
array("format" => "json", "#name-1", "#fopenid-1"),
"POST"
),
/* pay */
"get_tenpay_addr" => array(
"https://graph.qq.com/cft_info/get_tenpay_addr",
array("ver" => 1, "limit" => 5, "offset" => 0, "format" => "json")
)
);
}
//调用相应api
private function _applyAPI($arr, $argsList, $baseUrl, $method)
{
$pre = "#";
$keysArr = $this->keysArr;
$optionArgList = array(); //一些多项选填参数必选一的情形
foreach ($argsList as $key => $val) {
$tmpKey = $key;
$tmpVal = $val;
if (!is_string($key)) {
$tmpKey = $val;
if (strpos($val, $pre) === 0) {
$tmpVal = $pre;
$tmpKey = substr($tmpKey, 1);
if (preg_match("/-(\d$)/", $tmpKey, $res)) {
$tmpKey = str_replace($res[0], "", $tmpKey);
$optionArgList[$res[1]][] = $tmpKey;
}
} else {
$tmpVal = null;
}
}
//-----如果没有设置相应的参数
if (!isset($arr[$tmpKey]) || $arr[$tmpKey] === "") {
if ($tmpVal == $pre) {//则使用默认的值
continue;
} else if ($tmpVal) {
$arr[$tmpKey] = $tmpVal;
} else {
if ($v = $_FILES[$tmpKey]) {
$filename = dirname($v['tmp_name']) . "/" . $v['name'];
move_uploaded_file($v['tmp_name'], $filename);
$arr[$tmpKey] = "@$filename";
} else {
$this->error->showError("api调用参数错误", "未传入参数$tmpKey");
}
}
}
$keysArr[$tmpKey] = $arr[$tmpKey];
}
//检查选填参数必填一的情形
foreach ($optionArgList as $val) {
$n = 0;
foreach ($val as $v) {
if (in_array($v, array_keys($keysArr))) {
$n ++;
}
}
if (!$n) {
$str = implode(",", $val);
$this->error->showError("api调用参数错误", $str . "必填一个");
}
}
if ($method == "POST") {
if ($baseUrl == "https://graph.qq.com/blog/add_one_blog")
$response = $this->urlUtils->post($baseUrl, $keysArr, 1);
else
$response = $this->urlUtils->post($baseUrl, $keysArr, 0);
}else if ($method == "GET") {
$response = $this->urlUtils->get($baseUrl, $keysArr);
}
return $response;
}
/**
* _call
* 魔术方法,做api调用转发
* @param string $name 调用的方法名称
* @param array $arg 参数列表数组
* @since 5.0
* @return array 返加调用结果数组
*/
public function __call($name, $arg)
{
//如果APIMap不存在相应的api
if (empty($this->APIMap[$name])) {
$this->error->showError("api调用名称错误", "不存在的API: <span style='color:red;'>$name</span>");
}
//从APIMap获取api相应参数
$baseUrl = $this->APIMap[$name][0];
$argsList = $this->APIMap[$name][1];
$method = isset($this->APIMap[$name][2]) ? $this->APIMap[$name][2] : "GET";
if (empty($arg)) {
$arg[0] = null;
}
//对于get_tenpay_addr,特殊处理,php json_decode对\xA312此类字符支持不好
if ($name != "get_tenpay_addr") {
$response = json_decode($this->_applyAPI($arg[0], $argsList, $baseUrl, $method));
$responseArr = $this->objToArr($response);
} else {
$responseArr = $this->simple_json_parser($this->_applyAPI($arg[0], $argsList, $baseUrl, $method));
}
// 根据业务需求,返回结果
//检查返回ret判断api是否成功调用
// if($responseArr['ret'] == 0){
// return $responseArr;
// }else{
// $this->error->showError($response->ret, $response->msg);
// }
return $responseArr;
}
//php 对象到数组转换
private function objToArr($obj)
{
if (!is_object($obj) && !is_array($obj)) {
return $obj;
}
$arr = array();
foreach ($obj as $k => $v) {
$arr[$k] = $this->objToArr($v);
}
return $arr;
}
/**
* get_access_token
* 获得access_token
* @param void
* @since 5.0
* @return string 返加access_token
*/
public function get_access_token()
{
return $this->recorder->read("access_token");
}
//简单实现json到php数组转换功能
private function simple_json_parser($json)
{
$json = str_replace("{", "", str_replace("}", "", $json));
$jsonValue = explode(",", $json);
$arr = array();
foreach ($jsonValue as $v) {
$jValue = explode(":", $v);
$arr[str_replace('"', "", $jValue[0])] = (str_replace('"', "", $jValue[1]));
}
return $arr;
}
}
<?php
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
require_once(QC_CLASS_PATH.'Oauth.class.php');
/*
* @brief QC类,api外部对象,调用接口全部依赖于此对象
* */
class QC extends Oauth{
private $kesArr, $APIMap;
/**
* _construct
*
* 构造方法
* @access public
* @since 5
* @param string $access_token access_token value
* @param string $openid openid value
* @return Object QC
*/
public function __construct($access_token = "", $openid = ""){
parent::__construct();
//如果access_token和openid为空,则从session里去取,适用于demo展示情形
if($access_token === "" || $openid === ""){
$this->keysArr = array(
"oauth_consumer_key" => (int)$this->recorder->readInc("appid"),
"access_token" => $this->recorder->read("access_token"),
"openid" => $this->recorder->read("openid")
);
}else{
$this->keysArr = array(
"oauth_consumer_key" => (int)$this->recorder->readInc("appid"),
"access_token" => $access_token,
"openid" => $openid
);
}
//初始化APIMap
/*
* 加#表示非必须,无则不传入url(url中不会出现该参数), "key" => "val" 表示key如果没有定义则使用默认值val
* 规则 array( baseUrl, argListArr, method)
*/
$this->APIMap = array(
/* qzone */
"add_blog" => array(
"https://graph.qq.com/blog/add_one_blog",
array("title", "format" => "json", "content" => null),
"POST"
),
"add_topic" => array(
"https://graph.qq.com/shuoshuo/add_topic",
array("richtype","richval","con","#lbs_nm","#lbs_x","#lbs_y","format" => "json", "#third_source"),
"POST"
),
"get_user_info" => array(
"https://graph.qq.com/user/get_user_info",
array("format" => "json"),
"GET"
),
"add_one_blog" => array(
"https://graph.qq.com/blog/add_one_blog",
array("title", "content", "format" => "json"),
"GET"
),
"add_album" => array(
"https://graph.qq.com/photo/add_album",
array("albumname", "#albumdesc", "#priv", "format" => "json"),
"POST"
),
"upload_pic" => array(
"https://graph.qq.com/photo/upload_pic",
array("picture", "#photodesc", "#title", "#albumid", "#mobile", "#x", "#y", "#needfeed", "#successnum", "#picnum", "format" => "json"),
"POST"
),
"list_album" => array(
"https://graph.qq.com/photo/list_album",
array("format" => "json")
),
"add_share" => array(
"https://graph.qq.com/share/add_share",
array("title", "url", "#comment","#summary","#images","format" => "json","#type","#playurl","#nswb","site","fromurl"),
"POST"
),
"check_page_fans" => array(
"https://graph.qq.com/user/check_page_fans",
array("page_id" => "314416946","format" => "json")
),
/* wblog */
"add_t" => array(
"https://graph.qq.com/t/add_t",
array("format" => "json", "content","#clientip","#longitude","#compatibleflag"),
"POST"
),
"add_pic_t" => array(
"https://graph.qq.com/t/add_pic_t",
array("content", "pic", "format" => "json", "#clientip", "#longitude", "#latitude", "#syncflag", "#compatiblefalg"),
"POST"
),
"del_t" => array(
"https://graph.qq.com/t/del_t",
array("id", "format" => "json"),
"POST"
),
"get_repost_list" => array(
"https://graph.qq.com/t/get_repost_list",
array("flag", "rootid", "pageflag", "pagetime", "reqnum", "twitterid", "format" => "json")
),
"get_info" => array(
"https://graph.qq.com/user/get_info",
array("format" => "json")
),
"get_other_info" => array(
"https://graph.qq.com/user/get_other_info",
array("format" => "json", "#name", "fopenid")
),
"get_fanslist" => array(
"https://graph.qq.com/relation/get_fanslist",
array("format" => "json", "reqnum", "startindex", "#mode", "#install", "#sex")
),
"get_idollist" => array(
"https://graph.qq.com/relation/get_idollist",
array("format" => "json", "reqnum", "startindex", "#mode", "#install")
),
"add_idol" => array(
"https://graph.qq.com/relation/add_idol",
array("format" => "json", "#name-1", "#fopenids-1"),
"POST"
),
"del_idol" => array(
"https://graph.qq.com/relation/del_idol",
array("format" => "json", "#name-1", "#fopenid-1"),
"POST"
),
/* pay */
"get_tenpay_addr" => array(
"https://graph.qq.com/cft_info/get_tenpay_addr",
array("ver" => 1,"limit" => 5,"offset" => 0,"format" => "json")
)
);
}
//调用相应api
private function _applyAPI($arr, $argsList, $baseUrl, $method){
$pre = "#";
$keysArr = $this->keysArr;
$optionArgList = array();//一些多项选填参数必选一的情形
foreach($argsList as $key => $val){
$tmpKey = $key;
$tmpVal = $val;
if(!is_string($key)){
$tmpKey = $val;
if(strpos($val,$pre) === 0){
$tmpVal = $pre;
$tmpKey = substr($tmpKey,1);
if(preg_match("/-(\d$)/", $tmpKey, $res)){
$tmpKey = str_replace($res[0], "", $tmpKey);
$optionArgList[$res[1]][] = $tmpKey;
}
}else{
$tmpVal = null;
}
}
//-----如果没有设置相应的参数
if(!isset($arr[$tmpKey]) || $arr[$tmpKey] === ""){
if($tmpVal == $pre){//则使用默认的值
continue;
}else if($tmpVal){
$arr[$tmpKey] = $tmpVal;
}else{
if($v = $_FILES[$tmpKey]){
$filename = dirname($v['tmp_name'])."/".$v['name'];
move_uploaded_file($v['tmp_name'], $filename);
$arr[$tmpKey] = "@$filename";
}else{
$this->error->showError("api调用参数错误","未传入参数$tmpKey");
}
}
}
$keysArr[$tmpKey] = $arr[$tmpKey];
}
//检查选填参数必填一的情形
foreach($optionArgList as $val){
$n = 0;
foreach($val as $v){
if(in_array($v, array_keys($keysArr))){
$n ++;
}
}
if(! $n){
$str = implode(",",$val);
$this->error->showError("api调用参数错误",$str."必填一个");
}
}
if($method == "POST"){
if($baseUrl == "https://graph.qq.com/blog/add_one_blog") $response = $this->urlUtils->post($baseUrl, $keysArr, 1);
else $response = $this->urlUtils->post($baseUrl, $keysArr, 0);
}else if($method == "GET"){
$response = $this->urlUtils->get($baseUrl, $keysArr);
}
return $response;
}
/**
* _call
* 魔术方法,做api调用转发
* @param string $name 调用的方法名称
* @param array $arg 参数列表数组
* @since 5.0
* @return array 返加调用结果数组
*/
public function __call($name,$arg){
//如果APIMap不存在相应的api
if(empty($this->APIMap[$name])){
$this->error->showError("api调用名称错误","不存在的API: <span style='color:red;'>$name</span>");
}
//从APIMap获取api相应参数
$baseUrl = $this->APIMap[$name][0];
$argsList = $this->APIMap[$name][1];
$method = isset($this->APIMap[$name][2]) ? $this->APIMap[$name][2] : "GET";
if(empty($arg)){
$arg[0] = null;
}
//对于get_tenpay_addr,特殊处理,php json_decode对\xA312此类字符支持不好
if($name != "get_tenpay_addr"){
$response = json_decode($this->_applyAPI($arg[0], $argsList, $baseUrl, $method));
$responseArr = $this->objToArr($response);
}else{
$responseArr = $this->simple_json_parser($this->_applyAPI($arg[0], $argsList, $baseUrl, $method));
}
// 根据业务需求,返回结果
//检查返回ret判断api是否成功调用
// if($responseArr['ret'] == 0){
// return $responseArr;
// }else{
// $this->error->showError($response->ret, $response->msg);
// }
return $responseArr;
}
//php 对象到数组转换
private function objToArr($obj){
if(!is_object($obj) && !is_array($obj)) {
return $obj;
}
$arr = array();
foreach($obj as $k => $v){
$arr[$k] = $this->objToArr($v);
}
return $arr;
}
/**
* get_access_token
* 获得access_token
* @param void
* @since 5.0
* @return string 返加access_token
*/
public function get_access_token(){
return $this->recorder->read("access_token");
}
//简单实现json到php数组转换功能
private function simple_json_parser($json){
$json = str_replace("{","",str_replace("}","", $json));
$jsonValue = explode(",", $json);
$arr = array();
foreach($jsonValue as $v){
$jValue = explode(":", $v);
$arr[str_replace('"',"", $jValue[0])] = (str_replace('"', "", $jValue[1]));
}
return $arr;
}
}
... ...
<?php
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
require_once(QC_CLASS_PATH . 'ErrorCase.class.php');
class Recorder
{
private static $data;
private $inc;
private $error;
public function __construct()
{
$this->error = new ErrorCase();
//-------读取配置文件
$this->inc = require(QC_CLASS_PATH . '../Config.inc.php');
if (empty($this->inc)) {
$this->error->showError("20001");
}
self::$data = array();
// if(empty($_SESSION['QC_userData'])){
// self::$data = array();
// }else{
// self::$data = $_SESSION['QC_userData'];
// }
}
public function write($name, $value)
{
self::$data[$name] = $value;
}
public function read($name)
{
if (empty(self::$data[$name])) {
return null;
} else {
return self::$data[$name];
}
}
public function readInc($name)
{
if (empty($this->inc[$name])) {
return null;
} else {
return $this->inc[$name];
}
}
public function delete($name)
{
unset(self::$data[$name]);
}
function __destruct()
{
self::$data = null;
//$_SESSION['QC_userData'] = self::$data;
}
}
<?php
/* PHP SDK
* @version 2.0.0
* @author connect@qq.com
* @copyright © 2013, Tencent Corporation. All rights reserved.
*/
require_once(QC_CLASS_PATH . 'ErrorCase.class.php');
class Recorder
{
private static $data;
private $inc;
private $error;
public function __construct()
{
$this->error = new ErrorCase();
//-------读取配置文件
$this->inc = require(QC_CLASS_PATH . '../Config.inc.php');
if (empty($this->inc)) {
$this->error->showError("20001");
}
self::$data = array();
// if(empty($_SESSION['QC_userData'])){
// self::$data = array();
// }else{
// self::$data = $_SESSION['QC_userData'];
// }
}
public function write($name, $value)
{
self::$data[$name] = $value;
}
public function read($name)
{
if (empty(self::$data[$name])) {
return null;
} else {
return self::$data[$name];
}
}
public function readInc($name)
{
if (empty($this->inc[$name])) {
return null;
} else {
return $this->inc[$name];
}
}
public function delete($name)
{
unset(self::$data[$name]);
}
function __destruct()
{
self::$data = null;
//$_SESSION['QC_userData'] = self::$data;
}
}
... ...