Merge branch 'dev' of https://github.com/redmatrix/hubzilla into dev_merge

This commit is contained in:
zotlabs 2017-12-21 13:36:33 -08:00
commit e7143a265a
388 changed files with 18999 additions and 13488 deletions

114
CHANGELOG
View File

@ -1,3 +1,117 @@
Hubzilla 3.0 (????-??-??)
- Don't zidify all permalinks, only zot permalinks
- Make remote homelink link to the home host and not to the home channel
- Auto promote beginner (techlevel 0) accounts to level 1 after they show signs of active participation.
- Go back to including the photo thumbnail data in the export file.
- Improvements to file import/export
- Default value for xlink_rating_text
- Implement IMoveTarget and recursive file/directory move/rename - github issue #680
- Synchronise an attach_move operation to clones
- Provide a themed page with an error notification on errors instead of an obtuse XML error structure in mod cloud
- Disallow backslashes in wiki and wiki-page names
- We only require one update module. The rest are superfluous.
- Render installable elements as buttons instead of links
- Implement chunked uploads for photos page
- Remove warning for large files on cloud upload
- Add a filter for notification to show new posts only
- Implement chunked uploads for cloud
- Use httpsig auth for getfile
- Load the profile images in the custom acl selector only if we actually need them
- Rework liveUpdate() and notificationsUpdate() (aka ping) to first do the liveUpdate and when this is done only do the ping once.
- Don't include invisible "update activities" in category widget
- Default profile assign
- Provide system config option for minimum registration age.
- Remove deprecated $a argument from advanced_profile()
- Change to bbcode calling parameters
- Extra checking of server headers in upload functions
- Provide a handler for chunked uploads in mod file_upload
- Optional divider between item header and body
- Allow toggle to SMBC scaling mode.
- Add thumbnail hook
- Implement SVG thumbnails and expose security setting
- Implement video thumbnail generator
- Implement pdf thumbnails
- Implement thumbnail generator for epubs
- Make browser history buttons work with ajax calls in mod display and hq
- Implement tile view for mod cloud (read only)
- Add mp3 audio thumbnail generator
- Set display_path for photo_upload from the DAV File interface
- Provide a generalised interface for thumbnail generators to support various content types
- Add ID3Parser library.
- Text thumbnails in cloud tile mode
- Revisit media breakpoints - do not switch to mobile view to early.
- Add French to help pages language dropdown selector
- Inroduce the HQ module - an alternative landing page for hubzilla
- Strip author name from notify messages in notifications - github issue #911
- Remove column item.diaspora_meta
- Provide ability to pin apps to navbar from mod apps
- Add private forums to forum widget
- Move notifications style to widgets.css
- Sort out a few more large image upload issues
- Move notifications full-screen handling to notifications widget
- Move mailhost settings from plugin to core
- Sort combined private mail conversations by latest updated conversation instead of created parent
- Filter atokens on acl search
- Allow a site to block (public) the directory separately from other resources.
- Improve removed_channel final cleanup - github issue #386
- Cleanup of upload_to_comments(
- Dedicate the first click to slideup the cover again but make sure the nav buttons remain functional
- Set os_syspath in DAV file put operation so that photos will scale correctly.
- Unit tests for Zotlabs\Access classes
- Bring back tabindex to submit comments
- attach.php minor cleanup and doc
- Allow cloud filenames to include ampersands without messing up auth tokens (zid, owt, and zat, and the constant placeholder 'f=')
- Provide short localised summary for likes that will end up in displayed notifications
- Improving Doxygen documentation.
- Update item_normal() to not include ACTIVITY_OBJ_FILE obj_type
- Sort out issues with pubstream item interactions
- Don't perform zot_refresh on dead sites unless $force is set
- Do not send message_list responses to dead sites (this delivery method bypassed the notifier)
- Support for netselect query
- Add another delivery control parameter (queue threshold)
- Add some documentation about shareable widgets
- Allow plugin class widgets
- Some more work on unit tests
- Encrypt the owa token
- Bring back the markdown post feature
- We call Theme:url() statically, make it also static.
- Table structure for pseudo or proxy channels (pchan)
Bugfixes
- Fix issue with long filenames in mod cloud
- Fix misc. issues with new 'insert photo from photo album' github issue #475
- Fix regression in channel sources delivery
- Fix loading of theme-specific widgets
- Fix unable to add wiki pages with spaces
- Fix mod display and others that require a non-zero profile_uid for updates
- Fix various PHP 7.2 issues
- Fix typo in HTTPSig
- Fix pagetitle lost importing a pdl element from conversation
- Fix js warning - getelementbyid (id doesn't exist)
- Fix some pubstream on/off weirdness
- Fix default addressbook has no name - github issue #921
- Fix double html ids in caldav widget if more than one sharee
- Fix regression in cdav calendar widget
- Fix sync packet not generated when deleting a file using the web browser interface
- Fix album cover thumb generator
- Fix like-button for images - github issue #826
- Fix typo - github issue #910
- Fix issue with group_rmv()
- Fix php warnings on photo delete
- Fix some conflicts between private tags and forum tags
- Fix some schema issues
- Fix wiki pages not updating after creating new page
- Fix a PHP warning in Permissions::FilledPerms()
- Fix unicode characters in urls tripping up url regexes - github issue #901
- Fix second half of github issue #893
- Fix common connections on suggestion page showing wildly different results than remote profile, and is consistently off by one
- Fix cloud redirects with owt tokens
- Fix issues with diaspora xchans
- Fix memory overflow trying to delete a connection with a very high noise to signal ratio
- Fix sql error in page module
- Fix unstar
Hubzilla 2.8.1 (2017-11-11)
- Rename channel app events to calendar and add nav_set_selected() to /cal
- Load notifications links to /display via ajax if we are already in /display

View File

@ -98,6 +98,8 @@ class Hq extends \Zotlabs\Web\Controller {
$sys = get_sys_channel();
$sql_extra = item_permissions_sql($sys['channel_id']);
$sys_item = false;
}
if(! $update) {
@ -215,6 +217,8 @@ class Hq extends \Zotlabs\Web\Controller {
}
if(!$r) {
$sys_item = true;
$r = q("SELECT item.id AS item_id FROM item
LEFT JOIN abook ON item.author_xchan = abook.abook_xchan
WHERE mid = '%s' AND item.uid = %d $item_normal
@ -243,6 +247,8 @@ class Hq extends \Zotlabs\Web\Controller {
}
if(!$r) {
$sys_item = true;
$r = q("SELECT item.parent AS item_id FROM item
LEFT JOIN abook ON item.author_xchan = abook.abook_xchan
WHERE mid = '%s' AND item.uid = %d $item_normal_update $simple_update
@ -268,7 +274,7 @@ class Hq extends \Zotlabs\Web\Controller {
dbesc($parents_str)
);
xchan_query($items,true,local_channel());
xchan_query($items,true,(($sys_item) ? local_channel() : 0));
$items = fetch_post_tags($items,true);
$items = conv_sort($items,'created');
}

View File

@ -156,7 +156,7 @@ class Item extends \Zotlabs\Web\Controller {
if(! x($_REQUEST,'type'))
$_REQUEST['type'] = 'net-comment';
if($obj_type == ACTIVITY_OBJ_POST)
if($obj_type == ACTIVITY_OBJ_NOTE)
$obj_type = ACTIVITY_OBJ_COMMENT;
if($parent) {

View File

@ -279,8 +279,8 @@ class Ping extends \Zotlabs\Web\Controller {
'photo' => $tt['photo'],
'when' => relative_date($tt['created']),
'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
'b64mid' => $b64mid,
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''),
'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'),
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'),
'message' => $message
);
}

View File

@ -2,8 +2,6 @@
namespace Zotlabs\Render;
require_once('library/Smarty/libs/Smarty.class.php');
class SmartyInterface extends \Smarty {
public $filename;

View File

@ -36,15 +36,17 @@
"league/html-to-markdown": "^4.4",
"pear/text_languagedetect": "^1.0",
"commerceguys/intl": "~0.7",
"lukasreschke/id3parser": "^0.0.1"
"lukasreschke/id3parser": "^0.0.1",
"smarty/smarty": "~3.1"
},
"require-dev" : {
"php" : ">=7.0",
"phpunit/phpunit" : "^6.1",
"phpunit/phpunit" : "~6.4.4",
"behat/behat" : "@stable",
"behat/mink-extension": "@stable",
"behat/mink-goutte-driver": "@stable",
"php-mock/php-mock-phpunit": "^2.0"
"php-mock/php-mock-phpunit": "^2.0",
"phpunit/dbunit": "^3.0"
},
"autoload" : {
"psr-4" : {

618
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,9 @@
[h3]Zot API[/h3]
Many existing social applications and tools can interface directly using the Twitter/StatusNet API, which is available using the 'twitter_api' addon.
This document describes the native API; which allows direct programmatic access to several internal data structures and libraries extending beyond the basic social interface.
The API endpoints detailed below are relative to [code]api/z/1.0[/code], meaning that if an API is listed as [code]channel/stream[/code] the full API URL is [code][baseurl]/api/z/1.0/channel/stream[/code].
[h3]channel/export/basic[/h3]

View File

@ -941,27 +941,34 @@ function bbcode($Text, $options = []) {
// Check for h1
if (strpos($Text,'[h1]') !== false) {
$Text = preg_replace("(\[h1\](.*?)\[\/h1\])ism",'<h1>$1</h1>',$Text);
$Text = str_replace('</h1><br />', '</h1>', $Text);
}
// Check for h2
if (strpos($Text,'[h2]') !== false) {
$Text = preg_replace("(\[h2\](.*?)\[\/h2\])ism",'<h2>$1</h2>',$Text);
$Text = str_replace('</h2><br />', '</h2>', $Text);
}
// Check for h3
if (strpos($Text,'[h3]') !== false) {
$Text = preg_replace("(\[h3\](.*?)\[\/h3\])ism",'<h3>$1</h3>',$Text);
$Text = str_replace('</h3><br />', '</h3>', $Text);
}
// Check for h4
if (strpos($Text,'[h4]') !== false) {
$Text = preg_replace("(\[h4\](.*?)\[\/h4\])ism",'<h4>$1</h4>',$Text);
$Text = str_replace('</h4><br />', '</h4>', $Text);
}
// Check for h5
if (strpos($Text,'[h5]') !== false) {
$Text = preg_replace("(\[h5\](.*?)\[\/h5\])ism",'<h5>$1</h5>',$Text);
$Text = str_replace('</h5><br />', '</h5>', $Text);
}
// Check for h6
if (strpos($Text,'[h6]') !== false) {
$Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text);
$Text = str_replace('</h6><br />', '</h6>', $Text);
}
// Check for table of content without params
while(strpos($Text,'[toc]') !== false) {
$toc_id = 'toc-' . random_string(10);

View File

@ -1305,7 +1305,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// allow likes of comments
if($item_parent_mid && activity_match($datarray['verb'],ACTVITY_LIKE)) {
if($item_parent_mid && activity_match($datarray['verb'],ACTIVITY_LIKE)) {
$datarray['thr_parent'] = $item_parent_mid[0]['parent_mid'];
}

View File

@ -196,12 +196,12 @@ function html2bbcode($message)
//node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
//node2bbcode($doc, 'td', array(), "[td]", "[/td]");
node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n");
node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n");
node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n");
node2bbcode($doc, 'h1', array(), "\n\n[h1]", "[/h1]\n");
node2bbcode($doc, 'h2', array(), "\n\n[h2]", "[/h2]\n");
node2bbcode($doc, 'h3', array(), "\n\n[h3]", "[/h3]\n");
node2bbcode($doc, 'h4', array(), "\n\n[h4]", "[/h4]\n");
node2bbcode($doc, 'h5', array(), "\n\n[h5]", "[/h5]\n");
node2bbcode($doc, 'h6', array(), "\n\n[h6]", "[/h6]\n");
node2bbcode($doc, 'a', array('href'=>'/(.+)/'), '[url=$1]', '[/url]');

View File

@ -215,7 +215,7 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep
return $ret;
}
if(count($images)) {
if($images) {
foreach($images as $image) {
if(! stristr($image,z_root() . '/photo/'))
continue;

View File

@ -1754,9 +1754,14 @@ function get_plink($item,$conversation_mode = true) {
else
$key = 'llink';
$zidify = true;
if(array_key_exists('author',$item) && $item['author']['xchan_network'] !== 'zot')
$zidify = false;
if(x($item,$key)) {
return array(
'href' => zid($item[$key]),
'href' => (($zidify) ? zid($item[$key]) : $item[$key]),
'title' => t('Link to Source'),
);
}

View File

@ -1,78 +0,0 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {counter} function plugin
* Type: function<br>
* Name: counter<br>
* Purpose: print out a counter value
*
* @author Monte Ohrt <monte at ohrt dot com>
* @link http://www.smarty.net/manual/en/language.function.counter.php {counter}
* (Smarty online manual)
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string|null
*/
function smarty_function_counter($params, $template)
{
static $counters = array();
$name = (isset($params['name'])) ? $params['name'] : 'default';
if (!isset($counters[$name])) {
$counters[$name] = array(
'start' => 1,
'skip' => 1,
'direction' => 'up',
'count' => 1
);
}
$counter =& $counters[$name];
if (isset($params['start'])) {
$counter['start'] = $counter['count'] = (int) $params['start'];
}
if (!empty($params['assign'])) {
$counter['assign'] = $params['assign'];
}
if (isset($counter['assign'])) {
$template->assign($counter['assign'], $counter['count']);
}
if (isset($params['print'])) {
$print = (bool) $params['print'];
} else {
$print = empty($counter['assign']);
}
if ($print) {
$retval = $counter['count'];
} else {
$retval = null;
}
if (isset($params['skip'])) {
$counter['skip'] = $params['skip'];
}
if (isset($params['direction'])) {
$counter['direction'] = $params['direction'];
}
if ($counter['direction'] == "down") {
$counter['count'] -= $counter['skip'];
} else {
$counter['count'] += $counter['skip'];
}
return $retval;
}

View File

@ -1,91 +0,0 @@
<?php
/**
* Smarty plugin
* This plugin is only for Smarty2 BC
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {math} function plugin
* Type: function<br>
* Name: math<br>
* Purpose: handle math computations in template
*
* @link http://www.smarty.net/manual/en/language.function.math.php {math}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string|null
*/
function smarty_function_math($params, $template)
{
static $_allowed_funcs = array(
'int' => true, 'abs' => true, 'ceil' => true, 'cos' => true, 'exp' => true, 'floor' => true,
'log' => true, 'log10' => true, 'max' => true, 'min' => true, 'pi' => true, 'pow' => true,
'rand' => true, 'round' => true, 'sin' => true, 'sqrt' => true, 'srand' => true, 'tan' => true
);
// be sure equation parameter is present
if (empty($params['equation'])) {
trigger_error("math: missing equation parameter", E_USER_WARNING);
return;
}
$equation = $params['equation'];
// make sure parenthesis are balanced
if (substr_count($equation, "(") != substr_count($equation, ")")) {
trigger_error("math: unbalanced parenthesis", E_USER_WARNING);
return;
}
// match all vars in equation, make sure all are passed
preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]*)!", $equation, $match);
foreach ($match[1] as $curr_var) {
if ($curr_var && !isset($params[$curr_var]) && !isset($_allowed_funcs[$curr_var])) {
trigger_error("math: function call $curr_var not allowed", E_USER_WARNING);
return;
}
}
foreach ($params as $key => $val) {
if ($key != "equation" && $key != "format" && $key != "assign") {
// make sure value is not empty
if (strlen($val) == 0) {
trigger_error("math: parameter $key is empty", E_USER_WARNING);
return;
}
if (!is_numeric($val)) {
trigger_error("math: parameter $key: is not numeric", E_USER_WARNING);
return;
}
$equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation);
}
}
$smarty_math_result = null;
eval("\$smarty_math_result = " . $equation . ";");
if (empty($params['format'])) {
if (empty($params['assign'])) {
return $smarty_math_result;
} else {
$template->assign($params['assign'], $smarty_math_result);
}
} else {
if (empty($params['assign'])) {
printf($params['format'], $smarty_math_result);
} else {
$template->assign($params['assign'], sprintf($params['format'], $smarty_math_result));
}
}
}

View File

@ -1,50 +0,0 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty unescape modifier plugin
* Type: modifier<br>
* Name: unescape<br>
* Purpose: unescape html entities
*
* @author Rodney Rehm
*
* @param array $params parameters
*
* @return string with compiled code
*/
function smarty_modifiercompiler_unescape($params)
{
if (!isset($params[1])) {
$params[1] = 'html';
}
if (!isset($params[2])) {
$params[2] = '\'' . addslashes(Smarty::$_CHARSET) . '\'';
} else {
$params[2] = "'" . $params[2] . "'";
}
switch (trim($params[1], '"\'')) {
case 'entity':
case 'htmlall':
if (Smarty::$_MBSTRING) {
return 'mb_convert_encoding(' . $params[0] . ', ' . $params[2] . ', \'HTML-ENTITIES\')';
}
return 'html_entity_decode(' . $params[0] . ', ENT_NOQUOTES, ' . $params[2] . ')';
case 'html':
return 'htmlspecialchars_decode(' . $params[0] . ', ENT_QUOTES)';
case 'url':
return 'rawurldecode(' . $params[0] . ')';
default:
return $params[0];
}
}

View File

@ -1,53 +0,0 @@
<?php
/**
* Smarty shared plugin
*
* @package Smarty
* @subpackage PluginsShared
*/
if (version_compare(PHP_VERSION, '5.2.3', '>=')) {
/**
* escape_special_chars common function
* Function: smarty_function_escape_special_chars<br>
* Purpose: used by other smarty functions to escape
* special chars except for already escaped ones
*
* @author Monte Ohrt <monte at ohrt dot com>
*
* @param string $string text that should by escaped
*
* @return string
*/
function smarty_function_escape_special_chars($string)
{
if (!is_array($string)) {
$string = htmlspecialchars($string, ENT_COMPAT, Smarty::$_CHARSET, false);
}
return $string;
}
} else {
/**
* escape_special_chars common function
* Function: smarty_function_escape_special_chars<br>
* Purpose: used by other smarty functions to escape
* special chars except for already escaped ones
*
* @author Monte Ohrt <monte at ohrt dot com>
*
* @param string $string text that should by escaped
*
* @return string
*/
function smarty_function_escape_special_chars($string)
{
if (!is_array($string)) {
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlspecialchars($string);
$string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
}
return $string;
}
}

View File

@ -1,98 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Assign
* Compiles the {assign} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Assign Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase
{
/**
* Valid scope names
*
* @var array
*/
public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'global' => true,
'smarty' => true, 'tpl_root' => true);
/**
* Compiles code for the {assign} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// the following must be assigned at runtime because it will be overwritten in Smarty_Internal_Compile_Append
$this->required_attributes = array('var', 'value');
$this->shorttag_order = array('var', 'value');
$this->optional_attributes = array('scope', 'bubble_up');
$_nocache = 'null';
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
// nocache ?
if ($compiler->tag_nocache || $compiler->nocache) {
$_nocache = 'true';
// create nocache var to make it know for further compiling
if (isset($compiler->template->tpl_vars[trim($_attr['var'], "'")])) {
$compiler->template->tpl_vars[trim($_attr['var'], "'")]->nocache = true;
} else {
$compiler->template->tpl_vars[trim($_attr['var'], "'")] = new Smarty_Variable(null, true);
}
}
// scope setup
$_scope = Smarty::SCOPE_LOCAL;
if (isset($_attr['scope'])) {
$_attr['scope'] = trim($_attr['scope'], "'\"");
if (!isset($this->valid_scopes[$_attr['scope']])) {
$compiler->trigger_template_error("illegal value '{$_attr['scope']}' for \"scope\" attribute", null, true);
}
if ($_attr['scope'] != 'local') {
if ($_attr['scope'] == 'parent') {
$_scope = Smarty::SCOPE_PARENT;
} elseif ($_attr['scope'] == 'root') {
$_scope = Smarty::SCOPE_ROOT;
} elseif ($_attr['scope'] == 'global') {
$_scope = Smarty::SCOPE_GLOBAL;
} elseif ($_attr['scope'] == 'smarty') {
$_scope = Smarty::SCOPE_SMARTY;
} elseif ($_attr['scope'] == 'tpl_root') {
$_scope = Smarty::SCOPE_TPL_ROOT;
}
$_scope += (isset($_attr['bubble_up']) && $_attr['bubble_up'] == 'false') ? 0 : Smarty::SCOPE_BUBBLE_UP;
}
}
// compiled output
if (isset($parameter['smarty_internal_index'])) {
$output =
"<?php \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, $_attr[var], $_nocache);\n\$_smarty_tpl->tpl_vars[$_attr[var]]->value$parameter[smarty_internal_index] = $_attr[value];";
} else {
// implement Smarty2's behaviour of variables assigned by reference
if ($compiler->template->smarty instanceof SmartyBC) {
$output =
"<?php if (isset(\$_smarty_tpl->tpl_vars[$_attr[var]])) {\$_smarty_tpl->tpl_vars[$_attr[var]] = clone \$_smarty_tpl->tpl_vars[$_attr[var]];";
$output .= "\n\$_smarty_tpl->tpl_vars[$_attr[var]]->value = $_attr[value]; \$_smarty_tpl->tpl_vars[$_attr[var]]->nocache = $_nocache;";
$output .= "\n} else \$_smarty_tpl->tpl_vars[$_attr[var]] = new Smarty_Variable($_attr[value], $_nocache);";
} else {
$output = "<?php \$_smarty_tpl->tpl_vars[$_attr[var]] = new Smarty_Variable($_attr[value], $_nocache);";
}
}
$output .= "\n\$_smarty_tpl->ext->_updateScope->updateScope(\$_smarty_tpl, $_attr[var], $_scope);";
$output .= '?>';
return $output;
}
}

View File

@ -1,292 +0,0 @@
<?php
/*
* This file is part of Smarty.
*
* (c) 2015 Uwe Tews
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Smarty Internal Plugin Compile Block Class
*
* @author Uwe Tews <uwe.tews@googlemail.com>
*/
class Smarty_Internal_Compile_Block extends Smarty_Internal_Compile_Shared_Inheritance
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $required_attributes = array('name');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('name');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $option_flags = array('hide', 'nocache');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('assign');
/**
* nesting level of block tags
*
* @var int
*/
public static $blockTagNestingLevel = 0;
/**
* Saved compiler object
*
* @var Smarty_Internal_TemplateCompilerBase
*/
public $compiler = null;
/**
* Compiles code for the {block} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return bool true
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->_cache['blockNesting'] = 0;
}
if ($compiler->_cache['blockNesting'] == 0) {
// make sure that inheritance gets initialized in template code
$this->registerInit($compiler);
$this->option_flags = array('hide', 'nocache', 'append', 'prepend');
} else {
$this->option_flags = array('hide', 'nocache');
}
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$compiler->_cache['blockNesting'] ++;
$compiler->_cache['blockName'][$compiler->_cache['blockNesting']] = $_attr['name'];
$compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][0] = 'block_' . preg_replace('![^\w]+!', '_', uniqid(rand(), true));
$compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][1] = false;
$this->openTag($compiler, 'block', array($_attr, $compiler->nocache, $compiler->parser->current_buffer,
$compiler->template->compiled->has_nocache_code,
$compiler->template->caching));
// must whole block be nocache ?
if ($compiler->tag_nocache) {
$i = 0;
}
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// $compiler->suppressNocacheProcessing = true;
if ($_attr['nocache'] === true) {
//$compiler->trigger_template_error('nocache option not allowed', $compiler->parser->lex->taglineno);
}
$compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
$compiler->template->compiled->has_nocache_code = false;
$compiler->suppressNocacheProcessing = true;
}
/**
* Compile saved child block source
*
* @param \Smarty_Internal_TemplateCompilerBase compiler object
* @param string $_name optional name of child block
*
* @return string compiled code of child block
*/
static function compileChildBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null)
{
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->trigger_template_error(' tag {$smarty.block.child} used outside {block} tags ',
$compiler->parser->lex->taglineno);
}
$compiler->has_code = true;
$compiler->suppressNocacheProcessing = true;
$compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][1] = true;
$output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 2, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n";
return $output;
}
/**
* Compile $smarty.block.parent
*
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param string $_name optional name of child block
*
* @return string compiled code of child block
*/
static function compileParentBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null)
{
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->trigger_template_error(' tag {$smarty.block.parent} used outside {block} tags ',
$compiler->parser->lex->taglineno);
}
$compiler->suppressNocacheProcessing = true;
$compiler->has_code = true;
$output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 4, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n";
return $output;
}
}
/**
* Smarty Internal Plugin Compile BlockClose Class
*
*/
class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_Inheritance
{
/**
* Compiles code for the {/block} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return bool true
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
list($_attr, $_nocache, $_buffer, $_has_nocache_code, $_caching) = $this->closeTag($compiler, array('block'));
// init block parameter
$_block = $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']];
unset($compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]);
$_block[2] = $_block[3] = 0;
$_name = trim($_attr['name'], "'\"");
$_assign = isset($_attr['assign']) ? $_attr['assign'] : null;
unset($_attr['assign'], $_attr['name']);
foreach ($_attr as $name => $stat) {
if ((is_bool($stat) && $stat !== false) || (!is_bool($stat) && $stat != 'false')) {
$_block[$name] = is_string($stat) ? trim($stat, "'\"") : $stat;
}
}
$_funcName = $_block[0];
// get compiled block code
$_functionCode = $compiler->parser->current_buffer;
// setup buffer for template function code
$compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
if ($compiler->template->compiled->has_nocache_code) {
// $compiler->parent_compiler->template->tpl_function[$_name]['call_name_caching'] = $_funcNameCaching;
$_block[6] = $_funcNameCaching = $_funcName . '_nocache';
$output = "<?php\n";
$output .= "/* {block '{$_name}'} {$compiler->template->source->type}:{$compiler->template->source->name} */\n";
$output .= "function {$_funcNameCaching} (\$_smarty_tpl, \$_blockParentStack) {\n";
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n";
$output .= "\$_smarty_tpl->cached->hashes['{$compiler->template->compiled->nocache_hash}'] = true;\n";
if (isset($_assign)) {
$output .= "ob_start();\n";
}
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output));
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
$output = "<?php\n";
if (isset($_assign)) {
$output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n";
}
$output .= "/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n";
$output .= "}\n";
$output .= "/* {/block '{$_name}'} */\n\n";
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output));
$compiler->blockOrFunctionCode .= $f = $compiler->parser->current_buffer->to_smarty_php($compiler->parser);
$compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
$this->compiler = $compiler;
$_functionCode = new Smarty_Internal_ParseTree_Tag($compiler->parser,
preg_replace_callback("/((<\?php )?echo '\/\*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/([\S\s]*?)\/\*\/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/",
array($this, 'removeNocache'),
$_functionCode->to_smarty_php($compiler->parser)));
$this->compiler = null;
}
$output = "<?php\n";
$output .= "/* {block '{$_name}'} {$compiler->template->source->type}:{$compiler->template->source->name} */\n";
$output .= "function {$_funcName}(\$_smarty_tpl, \$_blockParentStack) {\n";
if (isset($_assign)) {
$output .= "ob_start();\n";
}
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output));
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
$output = "<?php\n";
if (isset($_assign)) {
$output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n";
}
$output .= "}\n";
$output .= "/* {/block '{$_name}'} */\n\n";
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output));
$compiler->blockOrFunctionCode .= $compiler->parser->current_buffer->to_smarty_php($compiler->parser);
// nocache plugins must be copied
if (!empty($compiler->template->compiled->required_plugins['nocache'])) {
foreach ($compiler->template->compiled->required_plugins['nocache'] as $plugin => $tmp) {
foreach ($tmp as $type => $data) {
$compiler->parent_compiler->template->compiled->required_plugins['compiled'][$plugin][$type] =
$data;
}
}
}
// restore old status
$compiler->template->compiled->has_nocache_code = $_has_nocache_code;
$compiler->tag_nocache = $compiler->nocache;
$compiler->nocache = $_nocache;
$compiler->parser->current_buffer = $_buffer;
$output = "<?php \n";
if ($compiler->_cache['blockNesting'] == 1) {
$output .= "\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 0, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, " .
var_export($_block, true) . ");\n";
} else {
$output .= "\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 0, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, " .
var_export($_block, true) . ", \$_blockParentStack);\n";
}
$output .= "?>\n";
$compiler->_cache['blockNesting'] --;
if ($compiler->_cache['blockNesting'] == 0) {
unset($compiler->_cache['blockNesting']);
}
$compiler->has_code = true;
$compiler->suppressNocacheProcessing = true;
return $output;
}
/**
* @param $match
*
* @return mixed
*/
function removeNocache($match)
{
$code =
preg_replace("/((<\?php )?echo '\/\*%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/)|(\/\*\/%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/",
'', $match[0]);
$code = str_replace(array('\\\'', '\\\\\''), array('\'', '\\\''), $code);
return $code;
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Break
* Compiles the {break} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Break Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Break extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('levels');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('levels');
/**
* Compiles code for the {break} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true);
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->trigger_template_error('nocache option not allowed', null, true);
}
if (isset($_attr['levels'])) {
if (!is_numeric($_attr['levels'])) {
$compiler->trigger_template_error('level attribute must be a numeric constant', null, true);
}
$_levels = $_attr['levels'];
} else {
$_levels = 1;
}
$level_count = $_levels;
$stack_count = count($compiler->_tag_stack) - 1;
while ($level_count > 0 && $stack_count >= 0) {
if (isset($_is_loopy[$compiler->_tag_stack[$stack_count][0]])) {
$level_count --;
}
$stack_count --;
}
if ($level_count != 0) {
$compiler->trigger_template_error("cannot break {$_levels} level(s)", null, true);
}
return "<?php break {$_levels};?>";
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Continue
* Compiles the {continue} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Continue Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Continue extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('levels');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('levels');
/**
* Compiles code for the {continue} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true);
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->trigger_template_error('nocache option not allowed', null, true);
}
if (isset($_attr['levels'])) {
if (!is_numeric($_attr['levels'])) {
$compiler->trigger_template_error('level attribute must be a numeric constant', null, true);
}
$_levels = $_attr['levels'];
} else {
$_levels = 1;
}
$level_count = $_levels;
$stack_count = count($compiler->_tag_stack) - 1;
while ($level_count > 0 && $stack_count >= 0) {
if (isset($_is_loopy[$compiler->_tag_stack[$stack_count][0]])) {
$level_count --;
}
$stack_count --;
}
if ($level_count != 0) {
$compiler->trigger_template_error("cannot continue {$_levels} level(s)", null, true);
}
return "<?php continue {$_levels};?>";
}
}

View File

@ -1,252 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile If
* Compiles the {if} {else} {elseif} {/if} tags
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile If Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_If extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {if} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$this->openTag($compiler, 'if', array(1, $compiler->nocache));
// must whole block be nocache ?
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
if (!array_key_exists("if condition", $parameter)) {
$compiler->trigger_template_error("missing if condition", null, true);
}
if (is_array($parameter['if condition'])) {
if ($compiler->nocache) {
$_nocache = ',true';
// create nocache var to make it know for further compiling
if (is_array($parameter['if condition']['var'])) {
$var = trim($parameter['if condition']['var']['var'], "'");
} else {
$var = trim($parameter['if condition']['var'], "'");
}
if (isset($compiler->template->tpl_vars[$var])) {
$compiler->template->tpl_vars[$var]->nocache = true;
} else {
$compiler->template->tpl_vars[$var] = new Smarty_Variable(null, true);
}
} else {
$_nocache = '';
}
if (is_array($parameter['if condition']['var'])) {
$_output = "<?php if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] .
"]) || !is_array(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] .
"]->value)) \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, " . $parameter['if condition']['var']['var'] .
"$_nocache);\n";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] . "]->value" .
$parameter['if condition']['var']['smarty_internal_index'] . " = " .
$parameter['if condition']['value'] . ") {?>";
} else {
$_output = "<?php if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] .
"])) \$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] .
"] = new Smarty_Variable(null{$_nocache});";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] . "]->value = " .
$parameter['if condition']['value'] . ") {?>";
}
return $_output;
} else {
return "<?php if ({$parameter['if condition']}) {?>";
}
}
}
/**
* Smarty Internal Plugin Compile Else Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Else extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {else} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
list($nesting, $compiler->tag_nocache) = $this->closeTag($compiler, array('if', 'elseif'));
$this->openTag($compiler, 'else', array($nesting, $compiler->tag_nocache));
return "<?php } else { ?>";
}
}
/**
* Smarty Internal Plugin Compile ElseIf Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Elseif extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {elseif} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
list($nesting, $compiler->tag_nocache) = $this->closeTag($compiler, array('if', 'elseif'));
if (!array_key_exists("if condition", $parameter)) {
$compiler->trigger_template_error("missing elseif condition", null, true);
}
if (is_array($parameter['if condition'])) {
$condition_by_assign = true;
if ($compiler->nocache) {
$_nocache = ',true';
// create nocache var to make it know for further compiling
if (is_array($parameter['if condition']['var'])) {
$var = trim($parameter['if condition']['var']['var'], "'");
} else {
$var = trim($parameter['if condition']['var'], "'");
}
if (isset($compiler->template->tpl_vars[$var])) {
$compiler->template->tpl_vars[$var]->nocache = true;
} else {
$compiler->template->tpl_vars[$var] = new Smarty_Variable(null, true);
}
} else {
$_nocache = '';
}
} else {
$condition_by_assign = false;
}
if (empty($compiler->prefix_code)) {
if ($condition_by_assign) {
$this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache));
if (is_array($parameter['if condition']['var'])) {
$_output = "<?php } else { if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var']['var'] . "]) || !is_array(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var']['var'] .
"]->value)) \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, " .
$parameter['if condition']['var']['var'] . "$_nocache);\n";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] . "]->value" .
$parameter['if condition']['var']['smarty_internal_index'] . " = " .
$parameter['if condition']['value'] . ") {?>";
} else {
$_output = "<?php } else { if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var'] . "])) \$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var'] . "] = new Smarty_Variable(null{$_nocache});";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] . "]->value = " .
$parameter['if condition']['value'] . ") {?>";
}
return $_output;
} else {
$this->openTag($compiler, 'elseif', array($nesting, $compiler->tag_nocache));
return "<?php } elseif ({$parameter['if condition']}) {?>";
}
} else {
$tmp = '';
foreach ($compiler->prefix_code as $code) {
$tmp = $compiler->appendCode($tmp, $code);
}
$compiler->prefix_code = array();
$tmp = $compiler->appendCode("<?php } else {?>", $tmp);
$this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache));
if ($condition_by_assign) {
if (is_array($parameter['if condition']['var'])) {
$_output = $compiler->appendCode($tmp, "<?php if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var']['var'] .
"]) || !is_array(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var']['var'] .
"]->value)) \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, " .
$parameter['if condition']['var']['var'] . "$_nocache);\n");
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] . "]->value" .
$parameter['if condition']['var']['smarty_internal_index'] . " = " .
$parameter['if condition']['value'] . ") {?>";
} else {
$_output = $compiler->appendCode($tmp, "<?php if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var'] .
"])) \$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var'] .
"] = new Smarty_Variable(null{$_nocache});");
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] . "]->value = " .
$parameter['if condition']['value'] . ") {?>";
}
return $_output;
} else {
return $compiler->appendCode($tmp, "<?php if ({$parameter['if condition']}) {?>");
}
}
}
}
/**
* Smarty Internal Plugin Compile Ifclose Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Ifclose extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {/if} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
list($nesting, $compiler->nocache) = $this->closeTag($compiler, array('if', 'else', 'elseif'));
$tmp = '';
for ($i = 0; $i < $nesting; $i ++) {
$tmp .= '}';
}
return "<?php {$tmp}?>";
}
}

View File

@ -1,89 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Block Plugin
* Compiles code for the execution of block plugin
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Block Plugin Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Private_Block_Plugin extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('_any');
/**
* Compiles code for the execution of block plugin
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
* @param string $tag name of block plugin
* @param string $function PHP function name
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $function)
{
if (!isset($tag[5]) || substr($tag, - 5) != 'close') {
// opening tag of block plugin
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->tag_nocache = true;
}
unset($_attr['nocache']);
// convert attributes into parameter array string
$_paramsArray = array();
foreach ($_attr as $_key => $_value) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
$_params = 'array(' . implode(",", $_paramsArray) . ')';
$this->openTag($compiler, $tag, array($_params, $compiler->nocache));
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// compile code
$output = "<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo {$function}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
} else {
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
// closing tag of block plugin, restore nocache
list($_params, $compiler->nocache) = $this->closeTag($compiler, substr($tag, 0, - 5));
// This tag does create output
$compiler->has_output = true;
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = '';
} else {
$mod_pre = ' ob_start(); ';
$mod_post = 'echo ' .
$compiler->compileTag('private_modifier', array(), array('modifierlist' => $parameter['modifier_list'],
'value' => 'ob_get_clean()')) . ';';
}
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo {$function}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " . $mod_post .
" } array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
}
return $output . "\n";
}
}

View File

@ -1,91 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Object Block Function
* Compiles code for registered objects as block function
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Object Block Function Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Private_Object_Block_Function extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('_any');
/**
* Compiles code for the execution of block plugin
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
* @param string $tag name of block object
* @param string $method name of method to call
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $method)
{
if (!isset($tag[5]) || substr($tag, - 5) != 'close') {
// opening tag of block plugin
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->tag_nocache = true;
}
unset($_attr['nocache']);
// convert attributes into parameter array string
$_paramsArray = array();
foreach ($_attr as $_key => $_value) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
$_params = 'array(' . implode(",", $_paramsArray) . ')';
$this->openTag($compiler, $tag . '->' . $method, array($_params, $compiler->nocache));
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// compile code
$output =
"<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}->{$method}', {$_params}); \$_block_repeat=true; echo \$_smarty_tpl->smarty->registered_objects['{$tag}'][0]->{$method}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
} else {
$base_tag = substr($tag, 0, - 5);
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
// closing tag of block plugin, restore nocache
list($_params, $compiler->nocache) = $this->closeTag($compiler, $base_tag . '->' . $method);
// This tag does create output
$compiler->has_output = true;
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = '';
} else {
$mod_pre = ' ob_start(); ';
$mod_post = 'echo ' . $compiler->compileTag('private_modifier', array(),
array('modifierlist' => $parameter['modifier_list'],
'value' => 'ob_get_clean()')) . ';';
}
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo \$_smarty_tpl->smarty->registered_objects['{$base_tag}'][0]->{$method}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " .
$mod_post . " } array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
}
return $output . "\n";
}
}

View File

@ -1,119 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Registered Block
* Compiles code for the execution of a registered block function
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Registered Block Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Private_Registered_Block extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('_any');
/**
* Compiles code for the execution of a block function
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
* @param string $tag name of block function
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag)
{
if (!isset($tag[5]) || substr($tag, - 5) != 'close') {
// opening tag of block plugin
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache']) {
$compiler->tag_nocache = true;
}
unset($_attr['nocache']);
if (isset($compiler->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$tag])) {
$tag_info = $compiler->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$tag];
} else {
$tag_info = $compiler->default_handler_plugins[Smarty::PLUGIN_BLOCK][$tag];
}
// convert attributes into parameter array string
$_paramsArray = array();
foreach ($_attr as $_key => $_value) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} elseif ($compiler->template->caching && in_array($_key, $tag_info[2])) {
$_value = str_replace("'", "^#^", $_value);
$_paramsArray[] = "'$_key'=>^#^.var_export($_value,true).^#^";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
$_params = 'array(' . implode(",", $_paramsArray) . ')';
$this->openTag($compiler, $tag, array($_params, $compiler->nocache));
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = !$tag_info[1] | $compiler->nocache | $compiler->tag_nocache;
$function = $tag_info[0];
// compile code
if (!is_array($function)) {
$output = "<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo {$function}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
} elseif (is_object($function[0])) {
$output = "<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo \$_smarty_tpl->smarty->registered_plugins['block']['{$tag}'][0][0]->{$function[1]}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
} else {
$output = "<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo {$function[0]}::{$function[1]}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
}
} else {
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
$base_tag = substr($tag, 0, - 5);
// closing tag of block plugin, restore nocache
list($_params, $compiler->nocache) = $this->closeTag($compiler, $base_tag);
// This tag does create output
$compiler->has_output = true;
if (isset($compiler->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) {
$function = $compiler->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag][0];
} else {
$function = $compiler->default_handler_plugins[Smarty::PLUGIN_BLOCK][$base_tag][0];
}
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = '';
} else {
$mod_pre = ' ob_start(); ';
$mod_post = 'echo ' .
$compiler->compileTag('private_modifier', array(), array('modifierlist' => $parameter['modifier_list'],
'value' => 'ob_get_clean()')) . ';';
}
if (!is_array($function)) {
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo {$function}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat);" . $mod_post .
" } array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
} elseif (is_object($function[0])) {
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo \$_smarty_tpl->smarty->registered_plugins['block']['{$base_tag}'][0][0]->{$function[1]}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " .
$mod_post . "} array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
} else {
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo {$function[0]}::{$function[1]}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " .
$mod_post . "} array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
}
}
return $output . "\n";
}
}

View File

@ -1,108 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile While
* Compiles the {while} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile While Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_While extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {while} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
$compiler->loopNesting++;
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$this->openTag($compiler, 'while', $compiler->nocache);
if (!array_key_exists("if condition", $parameter)) {
$compiler->trigger_template_error("missing while condition", null, true);
}
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$_output = "<?php\n";
if (is_array($parameter['if condition'])) {
if ($compiler->nocache) {
$_nocache = ',true';
// create nocache var to make it know for further compiling
if (is_array($parameter['if condition']['var'])) {
$var = trim($parameter['if condition']['var']['var'], "'");
} else {
$var = trim($parameter['if condition']['var'], "'");
}
if (isset($compiler->template->tpl_vars[$var])) {
$compiler->template->tpl_vars[$var]->nocache = true;
} else {
$compiler->template->tpl_vars[$var] = new Smarty_Variable(null, true);
}
} else {
$_nocache = '';
}
if (is_array($parameter['if condition']['var'])) {
$_output .= "if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] .
"]) || !is_array(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] .
"]->value)) \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, " . $parameter['if condition']['var']['var'] .
"$_nocache);\n";
$_output .= "while (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] . "]->value" .
$parameter['if condition']['var']['smarty_internal_index'] . " = " .
$parameter['if condition']['value'] . ") {?>";
} else {
$_output .= "if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] .
"])) \$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] .
"] = new Smarty_Variable(null{$_nocache});";
$_output .= "while (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] . "]->value = " .
$parameter['if condition']['value'] . ") {?>";
}
} else {
$_output .= "while ({$parameter['if condition']}) {?>";
}
return $_output;
}
}
/**
* Smarty Internal Plugin Compile Whileclose Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Whileclose extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {/while} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
{
$compiler->loopNesting--;
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
$compiler->nocache = $this->closeTag($compiler, array('while'));
return "<?php }?>\n";
}
}

View File

@ -1,157 +0,0 @@
<?php
/**
* Smarty Extension handler
*
* Load extensions dynamically
*
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
* @property Smarty_Internal_Runtime_Inheritance $_inheritance
* @property Smarty_Internal_Runtime_SubTemplate $_subTemplate
* @property Smarty_Internal_Runtime_TplFunction $_tplFunction
* @property Smarty_Internal_Runtime_Var $_var
* @property Smarty_Internal_Runtime_Config $_config
* @property Smarty_Internal_Runtime_Foreach $_foreach
* @property Smarty_Internal_Runtime_Hhvm $_hhvm
* @property Smarty_Internal_Runtime_WriteFile $_writeFile
* @property Smarty_Internal_Runtime_ValidateCompiled $_validateCompiled
* @property Smarty_Internal_Runtime_CodeFrame $_codeFrame
* @property Smarty_Internal_Runtime_FilterHandler $_filterHandler
* @property Smarty_Internal_Runtime_GetIncludePath $_getIncludePath
* @property Smarty_Internal_Runtime_UpdateScope $_updateScope
* @property Smarty_Internal_Runtime_IsCached $_isCached
* @property Smarty_Internal_Runtime_CacheModify $_cacheModify
* @property Smarty_Internal_Runtime_UpdateCache $_updateCache
* @property Smarty_Internal_Method_GetTemplateVars $getTemplateVars
* @property Smarty_Internal_Method_Append $append
* @property Smarty_Internal_Method_AppendByRef $appendByRef
* @property Smarty_Internal_Method_AssignGlobal $assignGlobal
* @property Smarty_Internal_Method_AssignByRef $assignByRef
* @property Smarty_Internal_Method_LoadFilter $loadFilter
* @property Smarty_Internal_Method_LoadPlugin $loadPlugin
* @property Smarty_Internal_Method_RegisterFilter $registerFilter
* @property Smarty_Internal_Method_RegisterObject $registerObject
* @property Smarty_Internal_Method_RegisterPlugin $registerPlugin
*/
class Smarty_Internal_Extension_Handler
{
public $objType = null;
/**
* Cache for property information from generic getter/setter
* Preloaded with names which should not use with generic getter/setter
*
* @var array
*/
private $_property_info = array('AutoloadFilters' => 0, 'DefaultModifiers' => 0, 'ConfigVars' => 0,
'DebugTemplate' => 0, 'RegisteredObject' => 0, 'StreamVariable' => 0,
'TemplateVars' => 0,);#
private $resolvedProperties = array();
/**
* Call external Method
*
* @param \Smarty_Internal_Data $data
* @param string $name external method names
* @param array $args argument array
*
* @return mixed
* @throws SmartyException
*/
public function _callExternalMethod(Smarty_Internal_Data $data, $name, $args)
{
/* @var Smarty $data ->smarty */
$smarty = isset($data->smarty) ? $data->smarty : $data;
if (!isset($smarty->ext->$name)) {
$class = 'Smarty_Internal_Method_' . ucfirst($name);
if (preg_match('/^(set|get)([A-Z].*)$/', $name, $match)) {
if (!isset($this->_property_info[$prop = $match[2]])) {
// convert camel case to underscored name
$this->resolvedProperties[$prop] = $pn = strtolower(join('_',
preg_split('/([A-Z][^A-Z]*)/', $prop, - 1,
PREG_SPLIT_NO_EMPTY |
PREG_SPLIT_DELIM_CAPTURE)));
$this->_property_info[$prop] = property_exists($data, $pn) ? 1 :
($data->_objType == 2 && property_exists($smarty, $pn) ? 2 : 0);
}
if ($this->_property_info[$prop]) {
$pn = $this->resolvedProperties[$prop];
if ($match[1] == 'get') {
return $this->_property_info[$prop] == 1 ? $data->$pn : $data->smarty->$pn;
} else {
return $this->_property_info[$prop] == 1 ? $data->$pn = $args[0] :
$data->smarty->$pn = $args[0];
}
} elseif (!class_exists($class)) {
throw new SmartyException("property '$pn' does not exist.");
}
}
if (class_exists($class)) {
$callback = array($smarty->ext->$name = new $class(), $name);
}
} else {
$callback = array($smarty->ext->$name, $name);
}
array_unshift($args, $data);
if (isset($callback) && $callback[0]->objMap | $data->_objType) {
return call_user_func_array($callback, $args);
}
return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), $args);
}
/**
* set extension property
*
* @param string $property_name property name
* @param mixed $value value
*
* @throws SmartyException
*/
public function __set($property_name, $value)
{
$this->$property_name = $value;
}
/**
* get extension object
*
* @param string $property_name property name
*
* @return mixed|Smarty_Template_Cached
* @throws SmartyException
*/
public function __get($property_name)
{
// object properties of runtime template extensions will start with '_'
if ($property_name[0] == '_') {
$class = 'Smarty_Internal_Runtime_' . ucfirst(substr($property_name, 1));
} else {
$class = 'Smarty_Internal_Method_' . ucfirst($property_name);
}
if (class_exists($class)) {
return $this->$property_name = new $class();
}
return $this;
}
/**
* Call error handler for undefined method
*
* @param string $name unknown method-name
* @param array $args argument array
*
* @return mixed
* @throws SmartyException
*/
public function __call($name, $args)
{
return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), $args);
}
}

View File

@ -1,47 +0,0 @@
<?php
/**
* Foreach Runtime Methods count
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_Foreach
{
/**
* [util function] counts an array, arrayAccess/traversable or PDOStatement object
*
* @param mixed $value
*
* @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
* for empty elements
*/
public function count($value)
{
if (is_array($value) === true || $value instanceof Countable) {
return count($value);
} elseif ($value instanceof IteratorAggregate) {
// Note: getIterator() returns a Traversable, not an Iterator
// thus rewind() and valid() methods may not be present
return iterator_count($value->getIterator());
} elseif ($value instanceof Iterator) {
if ($value instanceof Generator) {
return 1;
}
return iterator_count($value);
} elseif ($value instanceof PDOStatement) {
return $value->rowCount();
} elseif ($value instanceof Traversable) {
return iterator_count($value);
} elseif ($value instanceof ArrayAccess) {
if ($value->offsetExists(0)) {
return 1;
}
} elseif (is_object($value)) {
return count($value);
}
return 0;
}
}

View File

@ -1,30 +0,0 @@
<?php
/**
* Runtime Extension Hhvm
*
* include patch for modified compiled or cached templates
* HHVM does not check if file was modified when including same file multiple times
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class Smarty_Internal_Runtime_Hhvm
{
/**
* @param \Smarty_Internal_Template $_template
* @param string $file file name
*
* @return mixed
*/
static function includeHhvm(Smarty_Internal_Template $_template, $file)
{
$_smarty_tpl = $_template;
$tmp_file = $file . preg_replace('![^\w]+!', '_', uniqid(rand(), true)) . '.php';
file_put_contents($tmp_file, file_get_contents($file));
$result = @include $tmp_file;
@unlink($tmp_file);
return $result;
}
}

View File

@ -1,233 +0,0 @@
<?php
/**
* Inheritance Runtime Methods processBlock, endChild, init
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_Inheritance
{
/**
* State machine
* - 0 idle next extends will create a new inheritance tree
* - 1 processing child template
* - 2 wait for next inheritance template
* - 3 assume parent template, if child will loaded goto state 1
* a call to a sub template resets the state to 0
*
* @var int
*/
public $state = 0;
/**
* Array of block parameter of known {block} tags
*
* @var array
*/
public $blockParameter = array();
/**
* inheritance template nesting level
*
* @var int
*/
public $inheritanceLevel = 0;
/**
* inheritance template index
*
* @var int
*/
public $tplIndex = - 1;
/**
* Array of compiled template file path
* - key template index
* only used when caching is enabled
*
* @var []string
*/
public $compiledFilePath = array();
/**
* Current {block} nesting level
*
* @var int
*/
public $blockNesting = 0;
/**
* Initialize inheritance
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param bool $initChild if true init for child template
* @param array $blockNames outer level block name
*
*/
public function init(Smarty_Internal_Template $tpl, $initChild, $blockNames = array())
{
// if template was from an inner block or template is a parent template create new inheritance root
if ($initChild && ($this->blockNesting || $this->state == 3)) {
$tpl->ext->_inheritance = new Smarty_Internal_Runtime_Inheritance();
$tpl->ext->_inheritance->init($tpl, $initChild, $blockNames);
return;
}
// start of child sub template(s)
if ($initChild) {
$this->state = 1;
if (!$this->inheritanceLevel) {
//grab any output of child templates
ob_start();
}
$this->inheritanceLevel ++;
}
// in parent state {include} will not increment template index
if ($this->state != 3) {
$this->tplIndex ++;
}
// if state was waiting for parent change state to parent
if ($this->state == 2) {
$this->state = 3;
}
}
/**
* End of child template(s)
* - if outer level is reached flush output buffer and switch to wait for parent template state
*
* @param \Smarty_Internal_Template $tpl template object of caller
*/
public function endChild(Smarty_Internal_Template $tpl)
{
$this->inheritanceLevel --;
if (!$this->inheritanceLevel) {
ob_end_clean();
$this->state = 2;
}
}
/**
* Process inheritance {block} tag
*
* $type 0 = {block}:
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise call current block
* - ignored for outer level blocks in child templates
*
* $type 1 = {block}:
* - nested {block}
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise call current block
*
* $type 2 = {$smarty.block.child}:
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise ignore
*
* $type 3 = {block append} {block prepend}:
* - call parent block
*
* $type 4 = {$smarty.block.parent}:
* - call parent block
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param int $type call type see above
* @param string $name block name
* @param array $block block parameter
* @param array $callStack call stack with block parameters
*
* @throws \SmartyException
*/
public function processBlock(Smarty_Internal_Template $tpl, $type = 0, $name, $block, $callStack = array())
{
if (!isset($this->blockParameter[ $name ])) {
$this->blockParameter[ $name ] = array();
}
if ($this->state == 1) {
$block[ 2 ] = count($this->blockParameter[ $name ]);
$block[ 3 ] = $this->tplIndex;
$this->blockParameter[ $name ][] = $block;
return;
}
if ($type == 3) {
if (!empty($callStack)) {
$block = array_shift($callStack);
} else {
return;
}
} elseif ($type == 4) {
if (!empty($callStack)) {
array_shift($callStack);
if (empty($callStack)) {
throw new SmartyException("inheritance: tag {\$smarty.block.parent} used in parent template block '{$name}'");
}
$block = array_shift($callStack);
} else {
return;
}
} else {
$index = 0;
$blockParameter = &$this->blockParameter[ $name ];
if ($type == 0) {
$index = $block[ 2 ] = count($blockParameter);
$block[ 3 ] = $this->tplIndex;
$callStack = array(&$block);
} elseif ($type == 1) {
$block[ 3 ] = $callStack[ 0 ][ 3 ];
for ($i = 0; $i < count($blockParameter); $i ++) {
if ($blockParameter[ $i ][ 3 ] <= $block[ 3 ]) {
$index = $blockParameter[ $i ][ 2 ];
}
}
$block[ 2 ] = $index;
$callStack = array(&$block);
} elseif ($type == 2) {
$index = $callStack[ 0 ][ 2 ];
if ($index == 0) {
return;
}
$callStack = $block = array(1 => false);
}
$index --;
// find lowest level child block
while ($index >= 0 && ($type || !$block[ 1 ])) {
$block = &$blockParameter[ $index ];
array_unshift($callStack, $block);
if ($block[ 1 ]) {
break;
}
$index --;
}
if (isset($block[ 'hide' ]) && $index <= 0) {
return;
}
}
$this->blockNesting ++;
// {block append} ?
if (isset($block[ 'append' ])) {
$appendStack = $callStack;
if ($type == 0) {
array_shift($appendStack);
}
$this->processBlock($tpl, 3, $name, null, $appendStack);
}
// call block of current stack level
if (isset($block[6])) {
$block[6]($tpl, $callStack);
} else {
$block[0]($tpl, $callStack);
}
// {block prepend} ?
if (isset($block[ 'prepend' ])) {
$prependStack = $callStack;
if ($type == 0) {
array_shift($prependStack);
}
$this->processBlock($tpl, 3, $name, null, $prependStack);
}
$this->blockNesting --;
}
}

View File

@ -1,203 +0,0 @@
<?php
/**
* Sub Template Runtime Methods render, setupSubTemplate
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_SubTemplate
{
/**
* Subtemplate template object cache
*
* @var Smarty_Internal_Template[]
*/
public $tplObjects = array();
/**
* Subtemplate call count
*
* @var int[]
*/
public $subTplInfo = array();
/**
* Runtime function to render subtemplate
*
* @param \Smarty_Internal_Template $parent
* @param string $template template name
* @param mixed $cache_id cache id
* @param mixed $compile_id compile id
* @param integer $caching cache mode
* @param integer $cache_lifetime life time of cache data
* @param array $data passed parameter template variables
* @param int $scope scope in which {include} should execute
* @param bool $forceTplCache cache template object
* @param string $uid file dependency uid
* @param string $content_func function name
*
*/
public function render(Smarty_Internal_Template $parent, $template, $cache_id, $compile_id, $caching,
$cache_lifetime, $data, $scope, $forceTplCache, $uid = null, $content_func = null)
{
// if there are cached template objects calculate $templateID
$_templateId =
!empty($this->tplObjects) ? $parent->smarty->_getTemplateId($template, $cache_id, $compile_id, $caching) :
null;
// already in template cache?
/* @var Smarty_Internal_Template $tpl */
if (isset($_templateId) && isset($this->tplObjects[$_templateId])) {
// clone cached template object because of possible recursive call
$tpl = clone $this->tplObjects[$_templateId];
$tpl->parent = $parent;
// if $caching mode changed the compiled resource is invalid
if ((bool) $tpl->caching !== (bool) $caching) {
unset($tpl->compiled);
}
// get variables from calling scope
$tpl->tpl_vars = $parent->tpl_vars;
$tpl->config_vars = $parent->config_vars;
// get template functions
$tpl->tpl_function = $parent->tpl_function;
// copy inheritance object?
if (isset($parent->ext->_inheritance)) {
$tpl->ext->_inheritance = $parent->ext->_inheritance;
} else {
unset($tpl->ext->_inheritance);
}
} else {
$tpl = clone $parent;
$tpl->parent = $parent;
if (!isset($tpl->templateId) || $tpl->templateId !== $_templateId) {
$tpl->templateId = $_templateId;
$tpl->template_resource = $template;
$tpl->cache_id = $cache_id;
$tpl->compile_id = $compile_id;
if (isset($uid)) {
// for inline templates we can get all resource information from file dependency
if (isset($tpl->compiled->file_dependency[$uid])) {
list($filepath, $timestamp, $resource) = $tpl->compiled->file_dependency[$uid];
$tpl->source =
new Smarty_Template_Source(isset($tpl->smarty->_cache['resource_handlers'][$resource]) ?
$tpl->smarty->_cache['resource_handlers'][$resource] :
Smarty_Resource::load($tpl->smarty, $resource), $tpl->smarty,
$filepath, $resource, $filepath);
$tpl->source->filepath = $filepath;
$tpl->source->timestamp = $timestamp;
$tpl->source->exists = true;
$tpl->source->uid = $uid;
} else {
$tpl->source = null;
}
} else {
$tpl->source = null;
}
if (!isset($tpl->source)) {
$tpl->source = Smarty_Template_Source::load($tpl);
unset($tpl->compiled);
}
unset($tpl->cached);
}
}
$tpl->caching = $caching;
$tpl->cache_lifetime = $cache_lifetime;
if ($caching == 9999) {
$tpl->cached = $parent->cached;
}
// set template scope
$tpl->scope = $scope;
$scopePtr = false;
if ($scope & ~Smarty::SCOPE_BUBBLE_UP) {
if ($scope == Smarty::SCOPE_GLOBAL) {
$tpl->tpl_vars = Smarty::$global_tpl_vars;
$tpl->config_vars = $tpl->smarty->config_vars;
$scopePtr = true;
} else {
if ($scope == Smarty::SCOPE_PARENT) {
$scopePtr = $parent;
} elseif ($scope == Smarty::SCOPE_SMARTY) {
$scopePtr = $tpl->smarty;
} else {
$scopePtr = $tpl;
while (isset($scopePtr->parent)) {
if ($scopePtr->parent->_objType != 2 && $scope & Smarty::SCOPE_TPL_ROOT) {
break;
}
$scopePtr = $scopePtr->parent;
}
}
$tpl->tpl_vars = $scopePtr->tpl_vars;
$tpl->config_vars = $scopePtr->config_vars;
}
}
if (!isset($this->tplObjects[$tpl->_getTemplateId()]) && !$tpl->source->handler->recompiled) {
// if template is called multiple times set flag to to cache template objects
$forceTplCache = $forceTplCache ||
(isset($this->subTplInfo[$tpl->template_resource]) && $this->subTplInfo[$tpl->template_resource] > 1);
// check if template object should be cached
if ($tpl->parent->_objType == 2 && isset($this->tplObjects[$tpl->parent->templateId]) ||
($forceTplCache && $tpl->smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_AUTOMATIC) ||
($tpl->smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_ON)
) {
$this->tplObjects[$tpl->_getTemplateId()] = $tpl;
}
}
if (!empty($data)) {
// set up variable values
foreach ($data as $_key => $_val) {
$tpl->tpl_vars[$_key] = new Smarty_Variable($_val);
}
}
if (isset($uid)) {
if ($parent->smarty->debugging) {
$parent->smarty->_debug->start_template($tpl);
$parent->smarty->_debug->start_render($tpl);
}
$tpl->compiled->getRenderedTemplateCode($tpl, $content_func);
if ($parent->smarty->debugging) {
$parent->smarty->_debug->end_template($tpl);
$parent->smarty->_debug->end_render($tpl);
}
if ($tpl->caching == 9999 && $tpl->compiled->has_nocache_code) {
$parent->cached->hashes[$tpl->compiled->nocache_hash] = true;
}
} else {
if (isset($tpl->compiled)) {
$tpl->compiled->render($tpl);
} else {
$tpl->render();
}
}
if ($scopePtr) {
if ($scope == Smarty::SCOPE_GLOBAL) {
Smarty::$global_tpl_vars = $tpl->tpl_vars;
$tpl->smarty->config_vars = $tpl->config_vars;
} else {
$scopePtr->tpl_vars = $tpl->tpl_vars;
$scopePtr->config_vars = $tpl->config_vars;
}
}
}
/**
* Get called subtemplates from compiled template and save call count
*
* @param \Smarty_Internal_Template $tpl
*/
public function registerSubTemplates(Smarty_Internal_Template $tpl)
{
foreach ($tpl->compiled->includes as $name => $count) {
if (isset($this->subTplInfo[$name])) {
$this->subTplInfo[$name] += $count;
} else {
$this->subTplInfo[$name] = $count;
}
}
}
}

View File

@ -1,97 +0,0 @@
<?php
/**
* Tplfunc Runtime Methods callTemplateFunction
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_TplFunction
{
/**
* Call template function
*
* @param \Smarty_Internal_Template $tpl template object
* @param string $name template function name
* @param array $params parameter array
* @param bool $nocache true if called nocache
*
* @throws \SmartyException
*/
public function callTemplateFunction(Smarty_Internal_Template $tpl, $name, $params, $nocache)
{
if (isset($tpl->tpl_function[$name])) {
if (!$tpl->caching || ($tpl->caching && $nocache)) {
$function = $tpl->tpl_function[$name]['call_name'];
} else {
if (isset($tpl->tpl_function[$name]['call_name_caching'])) {
$function = $tpl->tpl_function[$name]['call_name_caching'];
} else {
$function = $tpl->tpl_function[$name]['call_name'];
}
}
if (function_exists($function)) {
$function ($tpl, $params);
return;
}
// try to load template function dynamically
if ($this->addTplFuncToCache($tpl, $name, $function)) {
$function ($tpl, $params);
return;
}
}
throw new SmartyException("Unable to find template function '{$name}'");
}
/**
*
* Add template function to cache file for nocache calls
*
* @param Smarty_Internal_Template $tpl
* @param string $_name template function name
* @param string $_function PHP function name
*
* @return bool
*/
public function addTplFuncToCache(Smarty_Internal_Template $tpl, $_name, $_function)
{
$funcParam = $tpl->tpl_function[$_name];
if (is_file($funcParam['compiled_filepath'])) {
// read compiled file
$code = file_get_contents($funcParam['compiled_filepath']);
// grab template function
if (preg_match("/\/\* {$_function} \*\/([\S\s]*?)\/\*\/ {$_function} \*\//", $code, $match)) {
// grab source info from file dependency
preg_match("/\s*'{$funcParam['uid']}'([\S\s]*?)\),/", $code, $match1);
unset($code);
// make PHP function known
eval($match[0]);
if (function_exists($_function)) {
// search cache file template
$tplPtr = $tpl;
while (!isset($tplPtr->cached) && isset($tplPtr->parent)) {
$tplPtr = $tplPtr->parent;
}
// add template function code to cache file
if (isset($tplPtr->cached)) {
$cache = $tplPtr->cached;
$content = $cache->read($tplPtr);
if ($content) {
// check if we must update file dependency
if (!preg_match("/'{$funcParam['uid']}'(.*?)'nocache_hash'/", $content, $match2)) {
$content = preg_replace("/('file_dependency'(.*?)\()/", "\\1{$match1[0]}", $content);
}
$tplPtr->smarty->ext->_updateCache->write($cache, $tplPtr, preg_replace('/\s*\?>\s*$/', "\n", $content) . "\n" .
preg_replace(array('/^\s*<\?php\s+/', '/\s*\?>\s*$/'), "\n",
$match[0]));
}
}
return true;
}
}
}
return false;
}
}

View File

@ -1,55 +0,0 @@
<?php
/**
* Runtime Methods updateScope
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_UpdateScope
{
/**
* Update new assigned template variable in other effected scopes
*
* @param \Smarty_Internal_Template $tpl template object
* @param string $varName variable name
* @param int $scope scope to which bubble up variable value
*/
public function updateScope(Smarty_Internal_Template $tpl, $varName, $scope = Smarty::SCOPE_LOCAL)
{
if (!$scope && !$tpl->scope) {
return;
}
foreach (array($scope, $tpl->scope) as $s) {
$s = ($bubble_up = $s >= Smarty::SCOPE_BUBBLE_UP) ? $s - Smarty::SCOPE_BUBBLE_UP : $s;
if ($bubble_up && $s) {
$ptr = $tpl->parent;
if (isset($ptr)) {
$ptr->tpl_vars[$varName] = $tpl->tpl_vars[$varName];
$ptr = $ptr->parent;
}
if ($s == Smarty::SCOPE_PARENT) {
continue;
}
while (isset($ptr) && $ptr->_objType == 2) {
$ptr->tpl_vars[$varName] = $tpl->tpl_vars[$varName];
$ptr = $ptr->parent;
}
if ($s == Smarty::SCOPE_TPL_ROOT) {
continue;
} elseif ($s == Smarty::SCOPE_SMARTY) {
$tpl->smarty->tpl_vars[$varName] = $tpl->tpl_vars[$varName];
} elseif ($s == Smarty::SCOPE_GLOBAL) {
Smarty::$global_tpl_vars[$varName] = $tpl->tpl_vars[$varName];
} elseif ($s == Smarty::SCOPE_ROOT) {
while (isset($ptr->parent)) {
$ptr = $ptr->parent;
}
$ptr->tpl_vars[$varName] = $tpl->tpl_vars[$varName];
}
}
}
}
}

View File

@ -1,86 +0,0 @@
<?php
/**
* Runtime Methods decodeProperties
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_ValidateCompiled
{
/**
* This function is executed automatically when a compiled or cached template file is included
* - Decode saved properties from compiled template and cache files
* - Check if compiled or cache file is valid
*
* @param array $properties special template properties
* @param bool $cache flag if called from cache file
*
* @return bool flag if compiled or cache file is valid
*/
public function decodeProperties(Smarty_Internal_Template $tpl, $properties, $cache = false)
{
$is_valid = true;
if (Smarty::SMARTY_VERSION != $properties['version']) {
// new version must rebuild
$is_valid = false;
} elseif ($is_valid && !empty($properties['file_dependency']) &&
((!$cache && $tpl->smarty->compile_check) || $tpl->smarty->compile_check == 1)
) {
// check file dependencies at compiled code
foreach ($properties['file_dependency'] as $_file_to_check) {
if ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
if ($tpl->source->filepath == $_file_to_check[0]) {
// do not recheck current template
continue;
//$mtime = $tpl->source->getTimeStamp();
} else {
// file and php types can be checked without loading the respective resource handlers
$mtime = is_file($_file_to_check[0]) ? filemtime($_file_to_check[0]) : false;
}
} elseif ($_file_to_check[2] == 'string') {
continue;
} else {
$handler = Smarty_Resource::load($tpl->smarty, $_file_to_check[2]);
if ($handler->checkTimestamps()) {
$source = Smarty_Template_Source::load($tpl, $tpl->smarty, $_file_to_check[ 0 ]);
$mtime = $source->getTimeStamp();
} else {
continue;
}
}
if (!$mtime || $mtime > $_file_to_check[1]) {
$is_valid = false;
break;
}
}
}
if ($cache) {
// CACHING_LIFETIME_SAVED cache expiry has to be validated here since otherwise we'd define the unifunc
if ($tpl->caching === Smarty::CACHING_LIFETIME_SAVED && $properties['cache_lifetime'] >= 0 &&
(time() > ($tpl->cached->timestamp + $properties['cache_lifetime']))
) {
$is_valid = false;
}
$tpl->cached->cache_lifetime = $properties['cache_lifetime'];
$tpl->cached->valid = $is_valid;
$resource = $tpl->cached;
} else {
$tpl->mustCompile = !$is_valid;
$resource = $tpl->compiled;
$resource->includes = isset($properties['includes']) ? $properties['includes'] : array();
}
if ($is_valid) {
$resource->unifunc = $properties['unifunc'];
$resource->has_nocache_code = $properties['has_nocache_code'];
// $tpl->compiled->nocache_hash = $properties['nocache_hash'];
$resource->file_dependency = $properties['file_dependency'];
if (isset($properties['tpl_function'])) {
$tpl->tpl_function = $properties['tpl_function'];
}
}
return $is_valid && !function_exists($properties['unifunc']);
}
}

View File

@ -1,33 +0,0 @@
<?php
/**
* Runtime Methods createLocalArrayVariable
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_Var
{
/**
* Template code runtime function to create a local Smarty variable for array assignments
*
* @param \Smarty_Internal_Template $tpl template object
* @param string $varName template variable name
* @param bool $nocache cache mode of variable
*/
public function createLocalArrayVariable(Smarty_Internal_Template $tpl, $varName, $nocache = false)
{
if (!isset($tpl->tpl_vars[$varName])) {
$tpl->tpl_vars[$varName] = new Smarty_Variable(array(), $nocache);
} else {
$tpl->tpl_vars[$varName] = clone $tpl->tpl_vars[$varName];
if (!(is_array($tpl->tpl_vars[$varName]->value) ||
$tpl->tpl_vars[$varName]->value instanceof ArrayAccess)
) {
settype($tpl->tpl_vars[$varName]->value, 'array');
}
}
}
}

View File

@ -1,376 +0,0 @@
<?php
/**
* Smarty Internal Plugin Template
* This file contains the Smarty template engine
*
* @package Smarty
* @subpackage Template
* @author Uwe Tews
*/
/**
* Main class with template data structures and methods
*
* @package Smarty
* @subpackage Template
*
* @property Smarty_Template_Source|Smarty_Template_Config $source
* @property Smarty_Template_Compiled $compiled
* @property Smarty_Template_Cached $cached
* @method bool mustCompile()
*/
class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
{
/**
* This object type (Smarty = 1, template = 2, data = 4)
*
* @var int
*/
public $_objType = 2;
/**
* Global smarty instance
*
* @var Smarty
*/
public $smarty = null;
/**
* Source instance
*
* @var Smarty_Template_Source|Smarty_Template_Config
*/
public $source = null;
/**
* Template resource
*
* @var string
*/
public $template_resource = null;
/**
* flag if compiled template is invalid and must be (re)compiled
*
* @var bool
*/
public $mustCompile = null;
/**
* Template Id
*
* @var null|string
*/
public $templateId = null;
/**
* Known template functions
*
* @var array
*/
public $tpl_function = array();
/**
* Scope in which template is rendered
*
* @var int
*/
public $scope = 0;
/**
* Create template data object
* Some of the global Smarty settings copied to template scope
* It load the required template resources and caching plugins
*
* @param string $template_resource template resource string
* @param Smarty $smarty Smarty instance
* @param \Smarty_Internal_Template|\Smarty|\Smarty_Internal_Data $_parent back pointer to parent object
* with variables or null
* @param mixed $_cache_id cache id or null
* @param mixed $_compile_id compile id or null
* @param bool $_caching use caching?
* @param int $_cache_lifetime cache life-time in seconds
*
* @throws \SmartyException
*/
public function __construct($template_resource, Smarty $smarty, Smarty_Internal_Data $_parent = null,
$_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null)
{
$this->smarty = &$smarty;
// Smarty parameter
$this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id;
$this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id;
$this->caching = $_caching === null ? $this->smarty->caching : $_caching;
if ($this->caching === true) {
$this->caching = Smarty::CACHING_LIFETIME_CURRENT;
}
$this->cache_lifetime = $_cache_lifetime === null ? $this->smarty->cache_lifetime : $_cache_lifetime;
$this->parent = $_parent;
// Template resource
$this->template_resource = $template_resource;
$this->source = Smarty_Template_Source::load($this);
parent::__construct();
}
/**
* render template
*
* @param bool $merge_tpl_vars if true parent template variables merged in to local scope
* @param bool $no_output_filter if true do not run output filter
* @param bool $display true: display, false: fetch null: subtemplate
*
* @throws Exception
* @throws SmartyException
* @return string rendered template output
*/
public function render($no_output_filter = true, $display = null)
{
$parentIsTpl = isset($this->parent) && $this->parent->_objType == 2;
if ($this->smarty->debugging) {
$this->smarty->_debug->start_template($this, $display);
}
// checks if template exists
if (!$this->source->exists) {
if ($parentIsTpl) {
$parent_resource = " in '{$this->parent->template_resource}'";
} else {
$parent_resource = '';
}
throw new SmartyException("Unable to load template {$this->source->type} '{$this->source->name}'{$parent_resource}");
}
// disable caching for evaluated code
if ($this->source->handler->recompiled) {
$this->caching = false;
}
// read from cache or render
$isCacheTpl =
$this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED;
if ($isCacheTpl) {
if (!isset($this->cached)) {
$this->loadCached();
}
$this->cached->render($this, $no_output_filter);
} elseif ($this->source->handler->uncompiled) {
$this->source->render($this);
} else {
if (!isset($this->compiled)) {
$this->loadCompiled();
}
$this->compiled->render($this);
}
// display or fetch
if ($display) {
if ($this->caching && $this->smarty->cache_modified_check) {
$this->smarty->ext->_cachemodify->cacheModifiedCheck($this->cached, $this,
isset($content) ? $content : ob_get_clean());
} else {
if ((!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled) &&
!$no_output_filter && (isset($this->smarty->autoload_filters['output']) ||
isset($this->smarty->registered_filters['output']))
) {
echo $this->smarty->ext->_filterHandler->runFilter('output', ob_get_clean(), $this);
} else {
ob_end_flush();
flush();
}
}
if ($this->smarty->debugging) {
$this->smarty->_debug->end_template($this);
// debug output
$this->smarty->_debug->display_debug($this, true);
}
return '';
} else {
if ($this->smarty->debugging) {
$this->smarty->_debug->end_template($this);
if ($this->smarty->debugging === 2 && $display === false) {
$this->smarty->_debug->display_debug($this, true);
}
}
if ($parentIsTpl) {
if (!empty($this->tpl_function)) {
$this->parent->tpl_function = array_merge($this->parent->tpl_function, $this->tpl_function);
}
foreach ($this->compiled->required_plugins as $code => $tmp1) {
foreach ($tmp1 as $name => $tmp) {
foreach ($tmp as $type => $data) {
$this->parent->compiled->required_plugins[$code][$name][$type] = $data;
}
}
}
}
if (!$no_output_filter &&
(!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled) &&
(isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))
) {
return $this->smarty->ext->_filterHandler->runFilter('output', ob_get_clean(), $this);
}
// return cache content
return null;
}
}
/**
* Compiles the template
* If the template is not evaluated the compiled template is saved on disk
*/
public function compileTemplateSource()
{
return $this->compiled->compileTemplateSource($this);
}
/**
* Writes the content to cache resource
*
* @param string $content
*
* @return bool
*/
public function writeCachedContent($content)
{
return $this->smarty->ext->_updateCache->writeCachedContent($this->cached, $this, $content);
}
/**
* Get unique template id
*
* @return string
*/
public function _getTemplateId()
{
return isset($this->templateId) ? $this->templateId : $this->templateId =
$this->smarty->_getTemplateId($this->template_resource, $this->cache_id, $this->compile_id);
}
/**
* runtime error not matching capture tags
*/
public function capture_error()
{
throw new SmartyException("Not matching {capture} open/close in \"{$this->template_resource}\"");
}
/**
* Load compiled object
*
*/
public function loadCompiled()
{
if (!isset($this->compiled)) {
$this->compiled = Smarty_Template_Compiled::load($this);
}
}
/**
* Load cached object
*
*/
public function loadCached()
{
if (!isset($this->cached)) {
$this->cached = Smarty_Template_Cached::load($this);
}
}
/**
* Load compiler object
*
* @throws \SmartyException
*/
public function loadCompiler()
{
if (!class_exists($this->source->handler->compiler_class)) {
$this->smarty->loadPlugin($this->source->handler->compiler_class);
}
$this->compiler = new $this->source->handler->compiler_class($this->source->handler->template_lexer_class,
$this->source->handler->template_parser_class,
$this->smarty);
}
/**
* Handle unknown class methods
*
* @param string $name unknown method-name
* @param array $args argument array
*
* @return mixed
* @throws SmartyException
*/
public function __call($name, $args)
{
// method of Smarty object?
if (method_exists($this->smarty, $name)) {
return call_user_func_array(array($this->smarty, $name), $args);
}
// parent
return parent::__call($name, $args);
}
/**
* set Smarty property in template context
*
* @param string $property_name property name
* @param mixed $value value
*
* @throws SmartyException
*/
public function __set($property_name, $value)
{
switch ($property_name) {
case 'compiled':
case 'cached':
case 'compiler':
$this->$property_name = $value;
return;
default:
// Smarty property ?
if (property_exists($this->smarty, $property_name)) {
$this->smarty->$property_name = $value;
return;
}
}
throw new SmartyException("invalid template property '$property_name'.");
}
/**
* get Smarty property in template context
*
* @param string $property_name property name
*
* @return mixed|Smarty_Template_Cached
* @throws SmartyException
*/
public function __get($property_name)
{
switch ($property_name) {
case 'compiled':
$this->loadCompiled();
return $this->compiled;
case 'cached':
$this->loadCached();
return $this->cached;
case 'compiler':
$this->loadCompiler();
return $this->compiler;
default:
// Smarty property ?
if (property_exists($this->smarty, $property_name)) {
return $this->smarty->$property_name;
}
}
throw new SmartyException("template property '$property_name' does not exist.");
}
/**
* Template data object destructor
*/
public function __destruct()
{
if ($this->smarty->cache_locking && isset($this->cached) && $this->cached->is_locked) {
$this->cached->handler->releaseLock($this->smarty, $this->cached);
}
}
}

View File

@ -1,48 +0,0 @@
<?php
/**
* Smarty Method AppendByRef
*
* Smarty::appendByRef() method
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class Smarty_Internal_Undefined
{
/**
* This function is executed automatically when a compiled or cached template file is included
* - Decode saved properties from compiled template and cache files
* - Check if compiled or cache file is valid
*
* @param array $properties special template properties
* @param bool $cache flag if called from cache file
*
* @return bool flag if compiled or cache file is valid
*/
public function decodeProperties($tpl, $properties, $cache = false)
{
if ($cache) {
$tpl->cached->valid = false;
} else {
$tpl->mustCompile = true;
}
return false;
}
/**
* Call error handler for undefined method
*
* @param string $name unknown method-name
* @param array $args argument array
*
* @return mixed
* @throws SmartyException
*/
public function __call($name, $args)
{
throw new SmartyException(get_class($args[0]) . "->{$name}() undefined method");
}
}

View File

@ -1,47 +0,0 @@
<?php
/**
* Smarty Resource Plugin
*
* @package Smarty
* @subpackage TemplateResources
* @author Rodney Rehm
*/
/**
* Smarty Resource Plugin
* Base implementation for resource plugins that don't compile cache
*
* @package Smarty
* @subpackage TemplateResources
*/
abstract class Smarty_Resource_Recompiled extends Smarty_Resource
{
/**
* Flag that it's an recompiled resource
*
* @var bool
*/
public $recompiled = true;
/**
* Resource does implement populateCompiledFilepath() method
*
* @var bool
*/
public $hasCompiledHandler = true;
/**
* populate Compiled Object with compiled filepath
*
* @param Smarty_Template_Compiled $compiled compiled object
* @param Smarty_Internal_Template $_template template object
*
* @return void
*/
public function populateCompiledFilepath(Smarty_Template_Compiled $compiled, Smarty_Internal_Template $_template)
{
$compiled->filepath = false;
$compiled->timestamp = false;
$compiled->exists = false;
}
}

View File

@ -1,79 +0,0 @@
<?php
/**
* Smarty Resource Plugin
*
* @package Smarty
* @subpackage TemplateResources
* @author Rodney Rehm
*/
/**
* Smarty Resource Plugin
* Base implementation for resource plugins that don't use the compiler
*
* @package Smarty
* @subpackage TemplateResources
*/
abstract class Smarty_Resource_Uncompiled extends Smarty_Resource
{
/**
* Flag that it's an uncompiled resource
*
* @var bool
*/
public $uncompiled = true;
/**
* Resource does implement populateCompiledFilepath() method
*
* @var bool
*/
public $hasCompiledHandler = true;
/**
* Render and output the template (without using the compiler)
*
* @param Smarty_Template_Source $source source object
* @param Smarty_Internal_Template $_template template object
*
* @throws SmartyException on failure
*/
abstract public function renderUncompiled(Smarty_Template_Source $source, Smarty_Internal_Template $_template);
/**
* populate compiled object with compiled filepath
*
* @param Smarty_Template_Compiled $compiled compiled object
* @param Smarty_Internal_Template $_template template object (is ignored)
*/
public function populateCompiledFilepath(Smarty_Template_Compiled $compiled, Smarty_Internal_Template $_template)
{
$compiled->filepath = false;
$compiled->timestamp = false;
$compiled->exists = false;
}
/**
* render compiled template code
*
* @param Smarty_Internal_Template $_template
*
* @return string
* @throws Exception
*/
public function render($_template)
{
$level = ob_get_level();
ob_start();
try {
$this->renderUncompiled($_template->source, $_template);
return ob_get_clean();
}
catch (Exception $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
}
}
}

View File

@ -1,297 +0,0 @@
<?php
/**
* Smarty Resource Data Object
* Meta Data Container for Template Files
*
* @package Smarty
* @subpackage TemplateResources
* @author Rodney Rehm
* @property string $content compiled content
*/
class Smarty_Template_Compiled extends Smarty_Template_Resource_Base
{
/**
* nocache hash
*
* @var string|null
*/
public $nocache_hash = null;
/**
* get a Compiled Object of this source
*
* @param Smarty_Internal_Template $_template template object
*
* @return Smarty_Template_Compiled compiled object
*/
static function load($_template)
{
// check runtime cache
if (!$_template->source->handler->recompiled &&
($_template->smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_ON)
) {
$_cache_key = $_template->source->unique_resource . '#';
if ($_template->caching) {
$_cache_key .= 'caching#';
}
$_cache_key .= $_template->compile_id;
if (isset($_template->source->compileds[$_cache_key])) {
return $_template->source->compileds[$_cache_key];
}
}
$compiled = new Smarty_Template_Compiled();
if ($_template->source->handler->hasCompiledHandler) {
$_template->source->handler->populateCompiledFilepath($compiled, $_template);
} else {
$compiled->populateCompiledFilepath($_template);
}
// runtime cache
if (!$_template->source->handler->recompiled &&
($_template->smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_ON)
) {
$_template->source->compileds[$_cache_key] = $compiled;
}
return $compiled;
}
/**
* populate Compiled Object with compiled filepath
*
* @param Smarty_Internal_Template $_template template object
**/
public function populateCompiledFilepath(Smarty_Internal_Template $_template)
{
$_compile_id = isset($_template->compile_id) ? preg_replace('![^\w]+!', '_', $_template->compile_id) : null;
if ($_template->source->isConfig) {
$_flag = '_' .
((int) $_template->smarty->config_read_hidden + (int) $_template->smarty->config_booleanize * 2 +
(int) $_template->smarty->config_overwrite * 4);
} else {
$_flag =
'_' . ((int) $_template->smarty->merge_compiled_includes + (int) $_template->smarty->escape_html * 2);
}
$_filepath = $_template->source->uid . $_flag;
// if use_sub_dirs, break file into directories
if ($_template->smarty->use_sub_dirs) {
$_filepath = substr($_filepath, 0, 2) . DS . substr($_filepath, 2, 2) . DS . substr($_filepath, 4, 2) . DS .
$_filepath;
}
$_compile_dir_sep = $_template->smarty->use_sub_dirs ? DS : '^';
if (isset($_compile_id)) {
$_filepath = $_compile_id . $_compile_dir_sep . $_filepath;
}
// caching token
if ($_template->caching) {
$_cache = '.cache';
} else {
$_cache = '';
}
$_compile_dir = $_template->smarty->getCompileDir();
// set basename if not specified
$_basename = $_template->source->handler->getBasename($_template->source);
if ($_basename === null) {
$_basename = basename(preg_replace('![^\w]+!', '_', $_template->source->name));
}
// separate (optional) basename by dot
if ($_basename) {
$_basename = '.' . $_basename;
}
$this->filepath = $_compile_dir . $_filepath . '.' . $_template->source->type . $_basename . $_cache . '.php';
$this->exists = is_file($this->filepath);
if (!$this->exists) {
$this->timestamp = false;
}
}
/**
* load compiled template or compile from source
*
* @param Smarty_Internal_Template $_template
*
* @throws Exception
*/
public function process(Smarty_Internal_Template $_template)
{
$_smarty_tpl = $_template;
if ($_template->source->handler->recompiled || !$_template->compiled->exists ||
$_template->smarty->force_compile || ($_template->smarty->compile_check &&
$_template->source->getTimeStamp() > $_template->compiled->getTimeStamp())
) {
$this->compileTemplateSource($_template);
$compileCheck = $_template->smarty->compile_check;
$_template->smarty->compile_check = false;
if ($_template->source->handler->recompiled) {
$level = ob_get_level();
ob_start();
try {
eval("?>" . $this->content);
}
catch (Exception $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
}
ob_get_clean();
$this->content = null;
} else {
$this->loadCompiledTemplate($_template);
}
$_template->smarty->compile_check = $compileCheck;
} else {
$_template->mustCompile = true;
@include($_template->compiled->filepath);
if ($_template->mustCompile) {
$this->compileTemplateSource($_template);
$compileCheck = $_template->smarty->compile_check;
$_template->smarty->compile_check = false;
$this->loadCompiledTemplate($_template);
$_template->smarty->compile_check = $compileCheck;
}
}
$_template->smarty->ext->_subTemplate->registerSubTemplates($_template);
$this->processed = true;
}
/**
* Load fresh compiled template by including the PHP file
* HHVM requires a work around because of a PHP incompatibility
*
* @param \Smarty_Internal_Template $_template
*/
private function loadCompiledTemplate(Smarty_Internal_Template $_template)
{
if (function_exists('opcache_invalidate')) {
opcache_invalidate($_template->compiled->filepath);
}
$_smarty_tpl = $_template;
if (defined('HHVM_VERSION')) {
$_template->smarty->ext->_hhvm->includeHhvm($_template, $_template->compiled->filepath);
} else {
include($_template->compiled->filepath);
}
}
/**
* render compiled template code
*
* @param Smarty_Internal_Template $_template
*
* @return string
* @throws Exception
*/
public function render(Smarty_Internal_Template $_template)
{
if ($_template->smarty->debugging) {
$_template->smarty->_debug->start_render($_template);
}
if (!$this->processed) {
$this->process($_template);
}
if (isset($_template->cached)) {
$_template->cached->file_dependency =
array_merge($_template->cached->file_dependency, $this->file_dependency);
}
$this->getRenderedTemplateCode($_template);
if ($_template->caching && $this->has_nocache_code) {
$_template->cached->hashes[$this->nocache_hash] = true;
}
if (isset($_template->parent) && $_template->parent->_objType == 2 && !empty($_template->tpl_function)) {
$_template->parent->tpl_function = array_merge($_template->parent->tpl_function, $_template->tpl_function);
}
if ($_template->smarty->debugging) {
$_template->smarty->_debug->end_render($_template);
}
}
/**
* compile template from source
*
* @param Smarty_Internal_Template $_template
*
* @return string
* @throws Exception
*/
public function compileTemplateSource(Smarty_Internal_Template $_template)
{
$_template->source->compileds = array();
$this->file_dependency = array();
$this->tpl_function = array();
$this->includes = array();
$this->nocache_hash = null;
$this->unifunc = null;
// compile locking
if (!$_template->source->handler->recompiled) {
if ($saved_timestamp = $_template->compiled->getTimeStamp()) {
touch($_template->compiled->filepath);
}
}
// call compiler
try {
$_template->loadCompiler();
$code = $_template->compiler->compileTemplate($_template);
}
catch (Exception $e) {
// restore old timestamp in case of error
if (!$_template->source->handler->recompiled && $saved_timestamp) {
touch($_template->compiled->filepath, $saved_timestamp);
}
throw $e;
}
// compiling succeeded
if ($_template->compiler->write_compiled_code) {
// write compiled template
$this->write($_template, $code);
$code = '';
}
// release compiler object to free memory
unset($_template->compiler);
return $code;
}
/**
* Write compiled code by handler
*
* @param Smarty_Internal_Template $_template template object
* @param string $code compiled code
*
* @return boolean success
*/
public function write(Smarty_Internal_Template $_template, $code)
{
if (!$_template->source->handler->recompiled) {
if ($_template->smarty->ext->_writeFile->writeFile($this->filepath, $code, $_template->smarty) === true) {
$this->timestamp = $this->exists = is_file($this->filepath);
if ($this->exists) {
$this->timestamp = filemtime($this->filepath);
return true;
}
}
return false;
} else {
$this->content = $code;
}
$this->timestamp = time();
$this->exists = true;
return true;
}
/**
* Read compiled content from handler
*
* @param Smarty_Internal_Template $_template template object
*
* @return string content
*/
public function read(Smarty_Internal_Template $_template)
{
if (!$_template->source->handler->recompiled) {
return file_get_contents($this->filepath);
}
return isset($this->content) ? $this->content : false;
}
}

View File

@ -1,97 +0,0 @@
<?php
/**
* Smarty Config Source Plugin
*
* @package Smarty
* @subpackage TemplateResources
* @author Uwe Tews
*/
/**
* Smarty Connfig Resource Data Object
* Meta Data Container for Template Files
*
* @package Smarty
* @subpackage TemplateResources
* @author Uwe Tews
*
*/
class Smarty_Template_Config extends Smarty_Template_Source
{
/**
* array of section names, single section or null
*
* @var null|string|array
*/
public $config_sections = null;
/**
* scope into which the config variables shall be loaded
*
* @var string
*/
public $scope = 'local';
/**
* Flag that source is a config file
*
* @var bool
*/
public $isConfig = true;
/**
* create Source Object container
*
* @param Smarty_Resource $handler Resource Handler this source object communicates with
* @param Smarty $smarty Smarty instance this source object belongs to
* @param string $resource full template_resource
* @param string $type type of resource
* @param string $name resource name
*/
public function __construct(Smarty_Resource $handler, Smarty $smarty, $resource, $type, $name)
{
// must clone handler as we change class names
$this->handler = clone $handler; // Note: prone to circular references
$this->handler->compiler_class = 'Smarty_Internal_Config_File_Compiler';
$this->handler->template_lexer_class = 'Smarty_Internal_Configfilelexer';
$this->handler->template_parser_class = 'Smarty_Internal_Configfileparser';
$this->resource = $resource;
$this->type = $type;
$this->name = $name;
$this->smarty = $smarty;
}
/**
* initialize Source Object for given resource
* Either [$_template] or [$smarty, $template_resource] must be specified
*
* @param Smarty_Internal_Template $_template template object
* @param Smarty $smarty smarty object
* @param string $template_resource resource identifier
*
* @return Smarty_Template_Config Source Object
* @throws SmartyException
*/
public static function load(Smarty_Internal_Template $_template = null, Smarty $smarty = null, $template_resource = null)
{
static $_incompatible_resources = array('extends' => true, 'php' => true);
$template_resource = $_template->template_resource;
if (empty($template_resource)) {
throw new SmartyException('Missing config name');
}
// parse resource_name, load resource handler
list($name, $type) = Smarty_Resource::parseResourceName($template_resource, $_template->smarty->default_config_type);
// make sure configs are not loaded via anything smarty can't handle
if (isset($_incompatible_resources[$type])) {
throw new SmartyException ("Unable to use resource '{$type}' for config");
}
$resource = Smarty_Resource::load($_template->smarty, $type);
$source = new Smarty_Template_Config($resource, $_template->smarty, $template_resource, $type, $name);
$resource->populate($source, $_template);
if (!$source->exists && isset($_template->smarty->default_config_handler_func)) {
Smarty_Internal_Method_RegisterDefaultTemplateHandler::_getDefaultTemplate($source);
}
$source->unique_resource = $resource->buildUniqueResourceName($_template->smarty, $name, true);
return $source;
}
}

View File

@ -8,6 +8,24 @@ To see the files changed for a given bug, go to https://github.com/bshaffer/oaut
To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1
To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash
* 1.10.0 (2017-12-14)
PR: https://github.com/bshaffer/oauth2-server-php/pull/889
* #795 - [feature] added protected createPayload method to allow easier customization of JWT payload
* #807 - [refactor] simplifies UserInfoController constructor
* #814 - [docs] Adds https to README link
* #827 - [testing] Explicitly pulls in phpunit 4
* #828 - [docs] PHPDoc improvements and type hinting of variables.
* #829 - [bug] Fix CORS issue for revoking and requesting an access token
* #869 - [testing] Remove php 5.3 from travis and use vendored phpunit
* #834 - [feature] use random_bytes if available
* #851 - [docs] Fix PHPDoc
* #872 - [bug] Fix count() error on PHP 7.2
* #873 - [testing] adds php 7.2 to travis
* #794 - [docs] Fix typo in composer.json
* #885 - [testing] Use PHPUnit\Framework\TestCase instead of PHPUnit_Framework_TestCase
* 1.9.0 (2016-01-06)
PR: https://github.com/bshaffer/oauth2-server-php/pull/788
@ -87,7 +105,7 @@ To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-
* bug #346 Fixes open_basedir warning
* bug #351 Adds OpenID Connect support
* bug #355 Adds php 5.6 and HHVM to travis.ci testing
* [BC] bug #358 Adds `getQuerystringIdentifier()` to the GrantType interface
* [BC] bug #358 Adds `getQueryStringIdentifier()` to the GrantType interface
* bug #363 Encryption\JWT - Allows for subclassing JWT Headers
* bug #349 Bearer Tokens - adds requestHasToken method for when access tokens are optional
* bug #301 Encryption\JWT - fixes urlSafeB64Encode(): ensures newlines are replaced as expected

View File

@ -5,4 +5,4 @@ oauth2-server-php
[![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads.png)](https://packagist.org/packages/bshaffer/oauth2-server-php)
View the [complete documentation](http://bshaffer.github.io/oauth2-server-php-docs/)
View the [complete documentation](https://bshaffer.github.io/oauth2-server-php-docs/)

View File

@ -19,6 +19,7 @@
"php":">=5.3.9"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"aws/aws-sdk-php": "~2.8",
"firebase/php-jwt": "~2.2",
"predis/predis": "dev-master",
@ -29,6 +30,7 @@
"predis/predis": "Required to use Redis storage",
"thobbs/phpcassa": "Required to use Cassandra storage",
"aws/aws-sdk-php": "~2.8 is required to use DynamoDB storage",
"firebase/php-jwt": "~1.1 is required to use MondoDB storage"
"firebase/php-jwt": "~2.2 is required to use JWT features",
"mongodb/mongodb": "^1.1 is required to use MongoDB storage"
}
}

View File

@ -10,8 +10,14 @@ namespace OAuth2;
*/
class Autoloader
{
/**
* @var string
*/
private $dir;
/**
* @param string $dir
*/
public function __construct($dir = null)
{
if (is_null($dir)) {
@ -19,6 +25,7 @@ class Autoloader
}
$this->dir = $dir;
}
/**
* Registers OAuth2\Autoloader as an SPL autoloader.
*/
@ -31,9 +38,8 @@ class Autoloader
/**
* Handles autoloading of classes.
*
* @param string $class A class name.
*
* @return boolean Returns true if the class has been loaded
* @param string $class - A class name.
* @return boolean - Returns true if the class has been loaded
*/
public function autoload($class)
{

View File

@ -10,6 +10,19 @@ use OAuth2\ResponseInterface;
*/
interface ClientAssertionTypeInterface
{
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return mixed
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response);
/**
* Get the client id
*
* @return mixed
*/
public function getClientId();
}

View File

@ -5,6 +5,7 @@ namespace OAuth2\ClientAssertionType;
use OAuth2\Storage\ClientCredentialsInterface;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
use LogicException;
/**
* Validate a client via Http Basic authentication
@ -19,14 +20,16 @@ class HttpBasic implements ClientAssertionTypeInterface
protected $config;
/**
* @param OAuth2\Storage\ClientCredentialsInterface $clientStorage REQUIRED Storage class for retrieving client credentials information
* @param array $config OPTIONAL Configuration options for the server
* <code>
* Config array $config should look as follows:
* @code
* $config = array(
* 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header
* 'allow_public_clients' => true // if true, "public clients" (clients without a secret) may be authenticated
* );
* </code>
* @endcode
*
* @param ClientCredentialsInterface $storage Storage
* @param array $config Configuration options for the server
*/
public function __construct(ClientCredentialsInterface $storage, array $config = array())
{
@ -37,6 +40,14 @@ class HttpBasic implements ClientAssertionTypeInterface
), $config);
}
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool|mixed
* @throws LogicException
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response)
{
if (!$clientData = $this->getClientCredentials($request, $response)) {
@ -44,7 +55,7 @@ class HttpBasic implements ClientAssertionTypeInterface
}
if (!isset($clientData['client_id'])) {
throw new \LogicException('the clientData array must have "client_id" set');
throw new LogicException('the clientData array must have "client_id" set');
}
if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') {
@ -70,6 +81,11 @@ class HttpBasic implements ClientAssertionTypeInterface
return true;
}
/**
* Get the client id
*
* @return mixed
*/
public function getClientId()
{
return $this->clientData['client_id'];
@ -82,8 +98,9 @@ class HttpBasic implements ClientAssertionTypeInterface
* According to the spec (draft 20), the client_id can be provided in
* the Basic Authorization header (recommended) or via GET/POST.
*
* @return
* A list containing the client identifier and password, for example
* @param RequestInterface $request
* @param ResponseInterface $response
* @return array|null A list containing the client identifier and password, for example:
* @code
* return array(
* "client_id" => CLIENT_ID, // REQUIRED the client id
@ -108,7 +125,6 @@ class HttpBasic implements ClientAssertionTypeInterface
* client_secret can be null if the client's password is an empty string
* @see http://tools.ietf.org/html/rfc6749#section-2.3.1
*/
return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret'));
}
}

View File

@ -7,37 +7,76 @@ use OAuth2\ScopeInterface;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
use OAuth2\Scope;
use InvalidArgumentException;
/**
* @see OAuth2\Controller\AuthorizeControllerInterface
* @see AuthorizeControllerInterface
*/
class AuthorizeController implements AuthorizeControllerInterface
{
/**
* @var string
*/
private $scope;
/**
* @var int
*/
private $state;
/**
* @var mixed
*/
private $client_id;
/**
* @var string
*/
private $redirect_uri;
/**
* The response type
*
* @var string
*/
private $response_type;
/**
* @var ClientInterface
*/
protected $clientStorage;
/**
* @var array
*/
protected $responseTypes;
/**
* @var array
*/
protected $config;
/**
* @var ScopeInterface
*/
protected $scopeUtil;
/**
* @param OAuth2\Storage\ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information
* Constructor
*
* @param ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information
* @param array $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array
* keys are "code" and "token"
* @param array $config OPTIONAL Configuration options for the server
* <code>
* @param array $config OPTIONAL Configuration options for the server:
* @param ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope
* @code
* $config = array(
* 'allow_implicit' => false, // if the controller should allow the "implicit" grant type
* 'enforce_state' => true // if the controller should require the "state" parameter
* 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter
* 'redirect_status_code' => 302, // HTTP status code to use for redirect responses
* );
* </code>
* @param OAuth2\ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope
* @endcode
*/
public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null)
{
@ -56,10 +95,20 @@ class AuthorizeController implements AuthorizeControllerInterface
$this->scopeUtil = $scopeUtil;
}
/**
* Handle the authorization request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param boolean $is_authorized
* @param mixed $user_id
* @return mixed|void
* @throws InvalidArgumentException
*/
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
{
if (!is_bool($is_authorized)) {
throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.');
throw new InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.');
}
// We repeat this, because we need to re-validate. The request could be POSTed
@ -101,6 +150,14 @@ class AuthorizeController implements AuthorizeControllerInterface
$response->setRedirect($this->config['redirect_status_code'], $uri);
}
/**
* Set not authorized response
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param string $redirect_uri
* @param mixed $user_id
*/
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
{
$error = 'access_denied';
@ -108,9 +165,16 @@ class AuthorizeController implements AuthorizeControllerInterface
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message);
}
/*
/**
* We have made this protected so this class can be extended to add/modify
* these parameters
*
* @TODO: add dependency injection for the parameters in this method
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param mixed $user_id
* @return array
*/
protected function buildAuthorizeParameters($request, $response, $user_id)
{
@ -127,6 +191,8 @@ class AuthorizeController implements AuthorizeControllerInterface
}
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool
@ -186,7 +252,7 @@ class AuthorizeController implements AuthorizeControllerInterface
$redirect_uri = $registered_redirect_uri;
}
// Select the redirect URI
// Select the response type
$response_type = $request->query('response_type', $request->request('response_type'));
// for multiple-valued response types - make them alphabetical
@ -281,10 +347,10 @@ class AuthorizeController implements AuthorizeControllerInterface
/**
* Build the absolute URI based on supplied URI and parameters.
*
* @param $uri An absolute URI.
* @param $params Parameters to be append as GET.
* @param string $uri An absolute URI.
* @param array $params Parameters to be append as GET.
*
* @return
* @return string
* An absolute URI with supplied parameters.
*
* @ingroup oauth2_section_4
@ -302,7 +368,7 @@ class AuthorizeController implements AuthorizeControllerInterface
}
}
// Put humpty dumpty back together
// Put the uri back together
return
((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "")
. ((isset($parse_url["user"])) ? $parse_url["user"]
@ -329,7 +395,7 @@ class AuthorizeController implements AuthorizeControllerInterface
* @param string $inputUri The submitted URI to be validated
* @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to
* allow for multiple URIs
*
* @return bool
* @see http://tools.ietf.org/html/rfc6749#section-3.1.2
*/
protected function validateRedirectUri($inputUri, $registeredUriString)
@ -363,29 +429,50 @@ class AuthorizeController implements AuthorizeControllerInterface
}
/**
* Convenience methods to access the parameters derived from the validated request
* Convenience method to access the scope
*
* @return string
*/
public function getScope()
{
return $this->scope;
}
/**
* Convenience method to access the state
*
* @return int
*/
public function getState()
{
return $this->state;
}
/**
* Convenience method to access the client id
*
* @return mixed
*/
public function getClientId()
{
return $this->client_id;
}
/**
* Convenience method to access the redirect url
*
* @return string
*/
public function getRedirectUri()
{
return $this->redirect_uri;
}
/**
* Convenience method to access the response type
*
* @return string
*/
public function getResponseType()
{
return $this->response_type;

View File

@ -11,17 +11,18 @@ use OAuth2\ResponseInterface;
* authorization directly, this controller ensures the request is valid, but
* requires the application to determine the value of $is_authorized
*
* ex:
* > $user_id = $this->somehowDetermineUserId();
* > $is_authorized = $this->somehowDetermineUserAuthorization();
* > $response = new OAuth2\Response();
* > $authorizeController->handleAuthorizeRequest(
* > OAuth2\Request::createFromGlobals(),
* > $response,
* > $is_authorized,
* > $user_id);
* > $response->send();
*
* @code
* $user_id = $this->somehowDetermineUserId();
* $is_authorized = $this->somehowDetermineUserAuthorization();
* $response = new OAuth2\Response();
* $authorizeController->handleAuthorizeRequest(
* OAuth2\Request::createFromGlobals(),
* $response,
* $is_authorized,
* $user_id
* );
* $response->send();
* @endcode
*/
interface AuthorizeControllerInterface
{
@ -37,7 +38,21 @@ interface AuthorizeControllerInterface
const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code';
const RESPONSE_TYPE_ACCESS_TOKEN = 'token';
/**
* Handle the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param $is_authorized
* @param null $user_id
* @return mixed
*/
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null);
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool
*/
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response);
}

View File

@ -10,17 +10,43 @@ use OAuth2\ResponseInterface;
use OAuth2\Scope;
/**
* @see OAuth2\Controller\ResourceControllerInterface
* @see ResourceControllerInterface
*/
class ResourceController implements ResourceControllerInterface
{
/**
* @var array
*/
private $token;
/**
* @var TokenTypeInterface
*/
protected $tokenType;
/**
* @var AccessTokenInterface
*/
protected $tokenStorage;
/**
* @var array
*/
protected $config;
/**
* @var ScopeInterface
*/
protected $scopeUtil;
/**
* Constructor
*
* @param TokenTypeInterface $tokenType
* @param AccessTokenInterface $tokenStorage
* @param array $config
* @param ScopeInterface $scopeUtil
*/
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null)
{
$this->tokenType = $tokenType;
@ -36,6 +62,14 @@ class ResourceController implements ResourceControllerInterface
$this->scopeUtil = $scopeUtil;
}
/**
* Verify the resource request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param null $scope
* @return bool
*/
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null)
{
$token = $this->getAccessTokenData($request, $response);
@ -71,6 +105,13 @@ class ResourceController implements ResourceControllerInterface
return (bool) $token;
}
/**
* Get access token data.
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return array|null
*/
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response)
{
// Get the token parameter
@ -103,7 +144,11 @@ class ResourceController implements ResourceControllerInterface
return null;
}
// convenience method to allow retrieval of the token
/**
* convenience method to allow retrieval of the token.
*
* @return array
*/
public function getToken()
{
return $this->token;

View File

@ -10,17 +10,32 @@ use OAuth2\ResponseInterface;
* call verifyResourceRequest in order to determine if the request
* contains a valid token.
*
* ex:
* > if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) {
* > $response->send(); // authorization failed
* > die();
* > }
* > return json_encode($resource); // valid token! Send the stuff!
*
* @code
* if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) {
* $response->send(); // authorization failed
* die();
* }
* return json_encode($resource); // valid token! Send the stuff!
* @endcode
*/
interface ResourceControllerInterface
{
/**
* Verify the resource request
*
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @param string $scope
* @return mixed
*/
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null);
/**
* Get access token data.
*
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @return mixed
*/
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response);
}

View File

@ -10,9 +10,12 @@ use OAuth2\Scope;
use OAuth2\Storage\ClientInterface;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
use InvalidArgumentException;
use LogicException;
use RuntimeException;
/**
* @see \OAuth2\Controller\TokenControllerInterface
* @see TokenControllerInterface
*/
class TokenController implements TokenControllerInterface
{
@ -22,7 +25,7 @@ class TokenController implements TokenControllerInterface
protected $accessToken;
/**
* @var array
* @var array<GrantTypeInterface>
*/
protected $grantTypes;
@ -32,7 +35,7 @@ class TokenController implements TokenControllerInterface
protected $clientAssertionType;
/**
* @var Scope|ScopeInterface
* @var ScopeInterface
*/
protected $scopeUtil;
@ -41,12 +44,22 @@ class TokenController implements TokenControllerInterface
*/
protected $clientStorage;
/**
* Constructor
*
* @param AccessTokenInterface $accessToken
* @param ClientInterface $clientStorage
* @param array $grantTypes
* @param ClientAssertionTypeInterface $clientAssertionType
* @param ScopeInterface $scopeUtil
* @throws InvalidArgumentException
*/
public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null)
{
if (is_null($clientAssertionType)) {
foreach ($grantTypes as $grantType) {
if (!$grantType instanceof ClientAssertionTypeInterface) {
throw new \InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface');
throw new InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface');
}
}
}
@ -63,6 +76,12 @@ class TokenController implements TokenControllerInterface
$this->scopeUtil = $scopeUtil;
}
/**
* Handle the token request.
*
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object
*/
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response)
{
if ($token = $this->grantAccessToken($request, $response)) {
@ -83,8 +102,10 @@ class TokenController implements TokenControllerInterface
* This would be called from the "/token" endpoint as defined in the spec.
* You can call your endpoint whatever you want.
*
* @param RequestInterface $request Request object to grant access token
* @param ResponseInterface $response
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object
*
* @return bool|null|array
*
* @throws \InvalidArgumentException
* @throws \LogicException
@ -97,9 +118,15 @@ class TokenController implements TokenControllerInterface
*/
public function grantAccessToken(RequestInterface $request, ResponseInterface $response)
{
if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
if (strtolower($request->server('REQUEST_METHOD')) === 'options') {
$response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null;
}
if (strtolower($request->server('REQUEST_METHOD')) !== 'post') {
$response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2');
$response->addHttpHeaders(array('Allow' => 'POST'));
$response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null;
}
@ -121,6 +148,7 @@ class TokenController implements TokenControllerInterface
return null;
}
/** @var GrantTypeInterface $grantType */
$grantType = $this->grantTypes[$grantTypeIdentifier];
/**
@ -128,8 +156,8 @@ class TokenController implements TokenControllerInterface
* ClientAssertionTypes allow for grant types which also assert the client data
* in which case ClientAssertion is handled in the validateRequest method
*
* @see OAuth2\GrantType\JWTBearer
* @see OAuth2\GrantType\ClientCredentials
* @see \OAuth2\GrantType\JWTBearer
* @see \OAuth2\GrantType\ClientCredentials
*/
if (!$grantType instanceof ClientAssertionTypeInterface) {
if (!$this->clientAssertionType->validateRequest($request, $response)) {
@ -178,7 +206,6 @@ class TokenController implements TokenControllerInterface
*
* @see http://tools.ietf.org/html/rfc6749#section-3.3
*/
$requestedScope = $this->scopeUtil->getScopeFromRequest($request);
$availableScope = $grantType->getScope();
@ -225,20 +252,24 @@ class TokenController implements TokenControllerInterface
}
/**
* addGrantType
* Add grant type
*
* @param GrantTypeInterface $grantType the grant type to add for the specified identifier
* @param string $identifier a string passed in as "grant_type" in the response that will call this grantType
* @param GrantTypeInterface $grantType - the grant type to add for the specified identifier
* @param string|null $identifier - a string passed in as "grant_type" in the response that will call this grantType
*/
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
{
if (is_null($identifier) || is_numeric($identifier)) {
$identifier = $grantType->getQuerystringIdentifier();
$identifier = $grantType->getQueryStringIdentifier();
}
$this->grantTypes[$identifier] = $grantType;
}
/**
* @param RequestInterface $request
* @param ResponseInterface $response
*/
public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response)
{
if ($this->revokeToken($request, $response)) {
@ -257,13 +288,20 @@ class TokenController implements TokenControllerInterface
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @throws RuntimeException
* @return bool|null
*/
public function revokeToken(RequestInterface $request, ResponseInterface $response)
{
if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
if (strtolower($request->server('REQUEST_METHOD')) === 'options') {
$response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null;
}
if (strtolower($request->server('REQUEST_METHOD')) !== 'post') {
$response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2');
$response->addHttpHeaders(array('Allow' => 'POST'));
$response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null;
}
@ -285,7 +323,7 @@ class TokenController implements TokenControllerInterface
// @todo remove this check for v2.0
if (!method_exists($this->accessToken, 'revokeToken')) {
$class = get_class($this->accessToken);
throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method");
throw new RuntimeException("AccessToken {$class} does not implement required revokeToken method");
}
$this->accessToken->revokeToken($token, $token_type_hint);

View File

@ -10,23 +10,30 @@ use OAuth2\ResponseInterface;
* it is called to handle all grant types the application supports.
* It also validates the client's credentials
*
* ex:
* > $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response());
* > $response->send();
*
* @code
* $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response());
* $response->send();
* @endcode
*/
interface TokenControllerInterface
{
/**
* handleTokenRequest
*
* @param $request
* OAuth2\RequestInterface - The current http request
* @param $response
* OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data
* Handle the token request
*
* @param RequestInterface $request - The current http request
* @param ResponseInterface $response - An instance of OAuth2\ResponseInterface to contain the response data
*/
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response);
/**
* Grant or deny a requested access token.
* This would be called from the "/token" endpoint as defined in the spec.
* You can call your endpoint whatever you want.
*
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object
*
* @return mixed
*/
public function grantAccessToken(RequestInterface $request, ResponseInterface $response);
}

View File

@ -4,8 +4,31 @@ namespace OAuth2\Encryption;
interface EncryptionInterface
{
/**
* @param $payload
* @param $key
* @param null $algorithm
* @return mixed
*/
public function encode($payload, $key, $algorithm = null);
/**
* @param $payload
* @param $key
* @param null $algorithm
* @return mixed
*/
public function decode($payload, $key, $algorithm = null);
/**
* @param $data
* @return mixed
*/
public function urlSafeB64Encode($data);
/**
* @param $b64
* @return mixed
*/
public function urlSafeB64Decode($b64);
}

View File

@ -2,12 +2,21 @@
namespace OAuth2\Encryption;
use Exception;
use InvalidArgumentException;
/**
* @link https://github.com/F21/jwt
* @author F21
*/
class Jwt implements EncryptionInterface
{
/**
* @param $payload
* @param $key
* @param string $algo
* @return string
*/
public function encode($payload, $key, $algo = 'HS256')
{
$header = $this->generateJwtHeader($payload, $algo);
@ -25,6 +34,12 @@ class Jwt implements EncryptionInterface
return implode('.', $segments);
}
/**
* @param string $jwt
* @param null $key
* @param array|bool $allowedAlgorithms
* @return bool|mixed
*/
public function decode($jwt, $key = null, $allowedAlgorithms = true)
{
if (!strpos($jwt, '.')) {
@ -67,6 +82,14 @@ class Jwt implements EncryptionInterface
return $payload;
}
/**
* @param $signature
* @param $input
* @param $key
* @param string $algo
* @return bool
* @throws InvalidArgumentException
*/
private function verifySignature($signature, $input, $key, $algo = 'HS256')
{
// use constants when possible, for HipHop support
@ -89,10 +112,17 @@ class Jwt implements EncryptionInterface
return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1;
default:
throw new \InvalidArgumentException("Unsupported or invalid signing algorithm.");
throw new InvalidArgumentException("Unsupported or invalid signing algorithm.");
}
}
/**
* @param $input
* @param $key
* @param string $algo
* @return string
* @throws Exception
*/
private function sign($input, $key, $algo = 'HS256')
{
switch ($algo) {
@ -115,19 +145,30 @@ class Jwt implements EncryptionInterface
return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512');
default:
throw new \Exception("Unsupported or invalid signing algorithm.");
throw new Exception("Unsupported or invalid signing algorithm.");
}
}
/**
* @param $input
* @param $key
* @param string $algo
* @return mixed
* @throws Exception
*/
private function generateRSASignature($input, $key, $algo)
{
if (!openssl_sign($input, $signature, $key, $algo)) {
throw new \Exception("Unable to sign data.");
throw new Exception("Unable to sign data.");
}
return $signature;
}
/**
* @param string $data
* @return string
*/
public function urlSafeB64Encode($data)
{
$b64 = base64_encode($data);
@ -138,6 +179,10 @@ class Jwt implements EncryptionInterface
return $b64;
}
/**
* @param string $b64
* @return mixed|string
*/
public function urlSafeB64Decode($b64)
{
$b64 = str_replace(array('-', '_'),
@ -158,6 +203,11 @@ class Jwt implements EncryptionInterface
);
}
/**
* @param string $a
* @param string $b
* @return bool
*/
protected function hash_equals($a, $b)
{
if (function_exists('hash_equals')) {

View File

@ -6,29 +6,47 @@ use OAuth2\Storage\AuthorizationCodeInterface;
use OAuth2\ResponseType\AccessTokenInterface;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
use Exception;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class AuthorizationCode implements GrantTypeInterface
{
/**
* @var AuthorizationCodeInterface
*/
protected $storage;
/**
* @var array
*/
protected $authCode;
/**
* @param \OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information
* @param AuthorizationCodeInterface $storage - REQUIRED Storage class for retrieving authorization code information
*/
public function __construct(AuthorizationCodeInterface $storage)
{
$this->storage = $storage;
}
public function getQuerystringIdentifier()
/**
* @return string
*/
public function getQueryStringIdentifier()
{
return 'authorization_code';
}
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool
* @throws Exception
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response)
{
if (!$request->request('code')) {
@ -75,21 +93,45 @@ class AuthorizationCode implements GrantTypeInterface
return true;
}
/**
* Get the client id
*
* @return mixed
*/
public function getClientId()
{
return $this->authCode['client_id'];
}
/**
* Get the scope
*
* @return string
*/
public function getScope()
{
return isset($this->authCode['scope']) ? $this->authCode['scope'] : null;
}
/**
* Get the user id
*
* @return mixed
*/
public function getUserId()
{
return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null;
}
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{
$token = $accessToken->createAccessToken($client_id, $user_id, $scope);

View File

@ -9,12 +9,19 @@ use OAuth2\Storage\ClientCredentialsInterface;
/**
* @author Brent Shaffer <bshafs at gmail dot com>
*
* @see OAuth2\ClientAssertionType_HttpBasic
* @see HttpBasic
*/
class ClientCredentials extends HttpBasic implements GrantTypeInterface
{
/**
* @var array
*/
private $clientData;
/**
* @param ClientCredentialsInterface $storage
* @param array $config
*/
public function __construct(ClientCredentialsInterface $storage, array $config = array())
{
/**
@ -27,11 +34,21 @@ class ClientCredentials extends HttpBasic implements GrantTypeInterface
parent::__construct($storage, $config);
}
public function getQuerystringIdentifier()
/**
* Get query string identifier
*
* @return string
*/
public function getQueryStringIdentifier()
{
return 'client_credentials';
}
/**
* Get scope
*
* @return string|null
*/
public function getScope()
{
$this->loadClientData();
@ -39,6 +56,11 @@ class ClientCredentials extends HttpBasic implements GrantTypeInterface
return isset($this->clientData['scope']) ? $this->clientData['scope'] : null;
}
/**
* Get user id
*
* @return mixed
*/
public function getUserId()
{
$this->loadClientData();
@ -46,6 +68,15 @@ class ClientCredentials extends HttpBasic implements GrantTypeInterface
return isset($this->clientData['user_id']) ? $this->clientData['user_id'] : null;
}
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{
/**

View File

@ -11,10 +11,49 @@ use OAuth2\ResponseInterface;
*/
interface GrantTypeInterface
{
public function getQuerystringIdentifier();
/**
* Get query string identifier
*
* @return string
*/
public function getQueryStringIdentifier();
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return mixed
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response);
/**
* Get client id
*
* @return mixed
*/
public function getClientId();
/**
* Get user id
*
* @return mixed
*/
public function getUserId();
/**
* Get scope
*
* @return string|null
*/
public function getScope();
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope);
}

View File

@ -30,9 +30,11 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
/**
* Creates an instance of the JWT bearer grant type.
*
* @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type.
* @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
* @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs.
* @param JwtBearerInterface $storage - A valid storage interface that implements storage hooks for the JWT
* bearer grant type.
* @param string $audience - The audience to validate the token against. This is usually the full
* URI of the OAuth token requests endpoint.
* @param EncryptionInterface|JWT $jwtUtil - OPTONAL The class used to decode, encode and verify JWTs.
* @param array $config
*/
public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array())
@ -56,12 +58,11 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
/**
* Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant.
*
* @return
* The string identifier for grant_type.
* @return string - The string identifier for grant_type.
*
* @see OAuth2\GrantType\GrantTypeInterface::getQuerystringIdentifier()
* @see GrantTypeInterface::getQueryStringIdentifier()
*/
public function getQuerystringIdentifier()
public function getQueryStringIdentifier()
{
return 'urn:ietf:params:oauth:grant-type:jwt-bearer';
}
@ -69,10 +70,9 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
/**
* Validates the data from the decoded JWT.
*
* @return
* TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned.
*
* @see OAuth2\GrantType\GrantTypeInterface::getTokenData()
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool|mixed|null TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned.@see GrantTypeInterface::getTokenData()
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response)
{
@ -196,16 +196,31 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
return true;
}
/**
* Get client id
*
* @return mixed
*/
public function getClientId()
{
return $this->jwt['iss'];
}
/**
* Get user id
*
* @return mixed
*/
public function getUserId()
{
return $this->jwt['sub'];
}
/**
* Get scope
*
* @return null
*/
public function getScope()
{
return null;
@ -215,7 +230,13 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
* Creates an access token that is NOT associated with a refresh token.
* If a subject (sub) the name of the user/account we are accessing data on behalf of.
*
* @see OAuth2\GrantType\GrantTypeInterface::createAccessToken()
* @see GrantTypeInterface::createAccessToken()
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{

View File

@ -8,25 +8,34 @@ use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class RefreshToken implements GrantTypeInterface
{
/**
* @var array
*/
private $refreshToken;
/**
* @var RefreshTokenInterface
*/
protected $storage;
/**
* @var array
*/
protected $config;
/**
* @param OAuth2\Storage\RefreshTokenInterface $storage REQUIRED Storage class for retrieving refresh token information
* @param array $config OPTIONAL Configuration options for the server
* <code>
* @param RefreshTokenInterface $storage - REQUIRED Storage class for retrieving refresh token information
* @param array $config - OPTIONAL Configuration options for the server
* @code
* $config = array(
* 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request
* 'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using
* );
* </code>
* @endcode
*/
public function __construct(RefreshTokenInterface $storage, $config = array())
{
@ -45,11 +54,21 @@ class RefreshToken implements GrantTypeInterface
$this->storage = $storage;
}
public function getQuerystringIdentifier()
/**
* @return string
*/
public function getQueryStringIdentifier()
{
return 'refresh_token';
}
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool|mixed|null
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response)
{
if (!$request->request("refresh_token")) {
@ -76,21 +95,45 @@ class RefreshToken implements GrantTypeInterface
return true;
}
/**
* Get client id
*
* @return mixed
*/
public function getClientId()
{
return $this->refreshToken['client_id'];
}
/**
* Get user id
*
* @return mixed|null
*/
public function getUserId()
{
return isset($this->refreshToken['user_id']) ? $this->refreshToken['user_id'] : null;
}
/**
* Get scope
*
* @return null|string
*/
public function getScope()
{
return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null;
}
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{
/*

View File

@ -6,30 +6,46 @@ use OAuth2\Storage\UserCredentialsInterface;
use OAuth2\ResponseType\AccessTokenInterface;
use OAuth2\RequestInterface;
use OAuth2\ResponseInterface;
use LogicException;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class UserCredentials implements GrantTypeInterface
{
/**
* @var array
*/
private $userInfo;
/**
* @var UserCredentialsInterface
*/
protected $storage;
/**
* @param OAuth2\Storage\UserCredentialsInterface $storage REQUIRED Storage class for retrieving user credentials information
* @param UserCredentialsInterface $storage - REQUIRED Storage class for retrieving user credentials information
*/
public function __construct(UserCredentialsInterface $storage)
{
$this->storage = $storage;
}
public function getQuerystringIdentifier()
/**
* @return string
*/
public function getQueryStringIdentifier()
{
return 'password';
}
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool|mixed|null
*
* @throws LogicException
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response)
{
if (!$request->request("password") || !$request->request("username")) {
@ -61,21 +77,45 @@ class UserCredentials implements GrantTypeInterface
return true;
}
/**
* Get client id
*
* @return mixed|null
*/
public function getClientId()
{
return null;
}
/**
* Get user id
*
* @return mixed
*/
public function getUserId()
{
return $this->userInfo['user_id'];
}
/**
* Get scope
*
* @return null|string
*/
public function getScope()
{
return isset($this->userInfo['scope']) ? $this->userInfo['scope'] : null;
}
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{
return $accessToken->createAccessToken($client_id, $user_id, $scope);

View File

@ -11,8 +11,19 @@ use OAuth2\ResponseInterface;
*/
class AuthorizeController extends BaseAuthorizeController implements AuthorizeControllerInterface
{
/**
* @var mixed
*/
private $nonce;
/**
* Set not authorized response
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param string $redirect_uri
* @param null $user_id
*/
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
{
$prompt = $request->query('prompt', 'consent');
@ -32,6 +43,14 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message);
}
/**
* @TODO: add dependency injection for the parameters in this method
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param mixed $user_id
* @return array
*/
protected function buildAuthorizeParameters($request, $response, $user_id)
{
if (!$params = parent::buildAuthorizeParameters($request, $response, $user_id)) {
@ -49,6 +68,11 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
return $params;
}
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool
*/
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
{
if (!parent::validateAuthorizeRequest($request, $response)) {
@ -69,6 +93,11 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
return true;
}
/**
* Array of valid response types
*
* @return array
*/
protected function getValidResponseTypes()
{
return array(
@ -87,11 +116,8 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
* method checks whether OpenID Connect is enabled in the server settings
* and whether the openid scope was requested.
*
* @param $request_scope
* A space-separated string of scopes.
*
* @return
* TRUE if an id token is needed, FALSE otherwise.
* @param string $request_scope - A space-separated string of scopes.
* @return boolean - TRUE if an id token is needed, FALSE otherwise.
*/
public function needsIdToken($request_scope)
{
@ -99,6 +125,9 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
return $this->scopeUtil->checkScope('openid', $request_scope);
}
/**
* @return mixed
*/
public function getNonce()
{
return $this->nonce;

View File

@ -5,6 +5,8 @@ namespace OAuth2\OpenID\Controller;
interface AuthorizeControllerInterface
{
const RESPONSE_TYPE_ID_TOKEN = 'id_token';
const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token';
const RESPONSE_TYPE_CODE_ID_TOKEN = 'code id_token';
}

View File

@ -16,30 +16,34 @@ use OAuth2\ResponseInterface;
*/
class UserInfoController extends ResourceController implements UserInfoControllerInterface
{
private $token;
protected $tokenType;
protected $tokenStorage;
/**
* @var UserClaimsInterface
*/
protected $userClaimsStorage;
protected $config;
protected $scopeUtil;
/**
* Constructor
*
* @param TokenTypeInterface $tokenType
* @param AccessTokenInterface $tokenStorage
* @param UserClaimsInterface $userClaimsStorage
* @param array $config
* @param ScopeInterface $scopeUtil
*/
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null)
{
$this->tokenType = $tokenType;
$this->tokenStorage = $tokenStorage;
parent::__construct($tokenType, $tokenStorage, $config, $scopeUtil);
$this->userClaimsStorage = $userClaimsStorage;
$this->config = array_merge(array(
'www_realm' => 'Service',
), $config);
if (is_null($scopeUtil)) {
$scopeUtil = new Scope();
}
$this->scopeUtil = $scopeUtil;
}
/**
* Handle the user info request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return void
*/
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response)
{
if (!$this->verifyResourceRequest($request, $response, 'openid')) {

View File

@ -9,15 +9,22 @@ use OAuth2\ResponseInterface;
* This controller is called when the user claims for OpenID Connect's
* UserInfo endpoint should be returned.
*
* ex:
* > $response = new OAuth2\Response();
* > $userInfoController->handleUserInfoRequest(
* > OAuth2\Request::createFromGlobals(),
* > $response;
* > $response->send();
*
* @code
* $response = new OAuth2\Response();
* $userInfoController->handleUserInfoRequest(
* OAuth2\Request::createFromGlobals(),
* $response
* );
* $response->send();
* @endcode
*/
interface UserInfoControllerInterface
{
/**
* Handle user info request
*
* @param RequestInterface $request
* @param ResponseInterface $response
*/
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response);
}

View File

@ -6,11 +6,19 @@ use OAuth2\GrantType\AuthorizationCode as BaseAuthorizationCode;
use OAuth2\ResponseType\AccessTokenInterface;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class AuthorizationCode extends BaseAuthorizationCode
{
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{
$includeRefreshToken = true;

View File

@ -6,16 +6,26 @@ use OAuth2\ResponseType\AuthorizationCode as BaseAuthorizationCode;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCodeInterface
{
/**
* Constructor
*
* @param AuthorizationCodeStorageInterface $storage
* @param array $config
*/
public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array())
{
parent::__construct($storage, $config);
}
/**
* @param $params
* @param null $user_id
* @return array
*/
public function getAuthorizeResponse($params, $user_id = null)
{
// build the URL to redirect to
@ -35,18 +45,14 @@ class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCo
/**
* Handle the creation of the authorization code.
*
* @param $client_id
* Client identifier related to the authorization code
* @param $user_id
* User ID associated with the authorization code
* @param $redirect_uri
* An absolute URI to which the authorization server will redirect the
* @param mixed $client_id - Client identifier related to the authorization code
* @param mixed $user_id - User ID associated with the authorization code
* @param string $redirect_uri - An absolute URI to which the authorization server will redirect the
* user-agent to when the end-user authorization step is completed.
* @param $scope
* (optional) Scopes to be stored in space-separated string.
* @param $id_token
* (optional) The OpenID Connect id_token.
* @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
* @param string $id_token - OPTIONAL The OpenID Connect id_token.
*
* @return string
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4
*/

View File

@ -5,7 +5,6 @@ namespace OAuth2\OpenID\ResponseType;
use OAuth2\ResponseType\AuthorizationCodeInterface as BaseAuthorizationCodeInterface;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
@ -13,12 +12,13 @@ interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
/**
* Handle the creation of the authorization code.
*
* @param $client_id Client identifier related to the authorization code
* @param $user_id User ID associated with the authorization code
* @param $redirect_uri An absolute URI to which the authorization server will redirect the
* @param mixed $client_id - Client identifier related to the authorization code
* @param mixed $user_id - User ID associated with the authorization code
* @param string $redirect_uri - An absolute URI to which the authorization server will redirect the
* user-agent to when the end-user authorization step is completed.
* @param $scope OPTIONAL Scopes to be stored in space-separated string.
* @param $id_token OPTIONAL The OpenID Connect id_token.
* @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
* @param string $id_token - OPTIONAL The OpenID Connect id_token.
* @return string
*
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4

View File

@ -4,15 +4,31 @@ namespace OAuth2\OpenID\ResponseType;
class CodeIdToken implements CodeIdTokenInterface
{
/**
* @var AuthorizationCodeInterface
*/
protected $authCode;
/**
* @var IdTokenInterface
*/
protected $idToken;
/**
* @param AuthorizationCodeInterface $authCode
* @param IdTokenInterface $idToken
*/
public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken)
{
$this->authCode = $authCode;
$this->idToken = $idToken;
}
/**
* @param array $params
* @param mixed $user_id
* @return mixed
*/
public function getAuthorizeResponse($params, $user_id = null)
{
$result = $this->authCode->getAuthorizeResponse($params, $user_id);

View File

@ -6,14 +6,38 @@ use OAuth2\Encryption\EncryptionInterface;
use OAuth2\Encryption\Jwt;
use OAuth2\Storage\PublicKeyInterface;
use OAuth2\OpenID\Storage\UserClaimsInterface;
use LogicException;
class IdToken implements IdTokenInterface
{
/**
* @var UserClaimsInterface
*/
protected $userClaimsStorage;
/**
* @var PublicKeyInterface
*/
protected $publicKeyStorage;
/**
* @var array
*/
protected $config;
/**
* @var EncryptionInterface
*/
protected $encryptionUtil;
/**
* Constructor
*
* @param UserClaimsInterface $userClaimsStorage
* @param PublicKeyInterface $publicKeyStorage
* @param array $config
* @param EncryptionInterface $encryptionUtil
* @throws LogicException
*/
public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null)
{
$this->userClaimsStorage = $userClaimsStorage;
@ -24,13 +48,18 @@ class IdToken implements IdTokenInterface
$this->encryptionUtil = $encryptionUtil;
if (!isset($config['issuer'])) {
throw new \LogicException('config parameter "issuer" must be set');
throw new LogicException('config parameter "issuer" must be set');
}
$this->config = array_merge(array(
'id_lifetime' => 3600,
), $config);
}
/**
* @param array $params
* @param null $userInfo
* @return array|mixed
*/
public function getAuthorizeResponse($params, $userInfo = null)
{
// build the URL to redirect to
@ -50,6 +79,16 @@ class IdToken implements IdTokenInterface
return array($params['redirect_uri'], $result);
}
/**
* Create id token
*
* @param string $client_id
* @param mixed $userInfo
* @param mixed $nonce
* @param mixed $userClaims
* @param mixed $access_token
* @return mixed|string
*/
public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null)
{
// pull auth_time from user info if supplied
@ -79,6 +118,11 @@ class IdToken implements IdTokenInterface
return $this->encodeToken($token, $client_id);
}
/**
* @param $access_token
* @param null $client_id
* @return mixed|string
*/
protected function createAtHash($access_token, $client_id = null)
{
// maps HS256 and RS256 to sha256, etc.
@ -90,6 +134,11 @@ class IdToken implements IdTokenInterface
return $this->encryptionUtil->urlSafeB64Encode($at_hash);
}
/**
* @param array $token
* @param null $client_id
* @return mixed|string
*/
protected function encodeToken(array $token, $client_id = null)
{
$private_key = $this->publicKeyStorage->getPrivateKey($client_id);
@ -98,6 +147,11 @@ class IdToken implements IdTokenInterface
return $this->encryptionUtil->encode($token, $private_key, $algorithm);
}
/**
* @param $userInfo
* @return array
* @throws LogicException
*/
private function getUserIdAndAuthTime($userInfo)
{
$auth_time = null;
@ -105,7 +159,7 @@ class IdToken implements IdTokenInterface
// support an array for user_id / auth_time
if (is_array($userInfo)) {
if (!isset($userInfo['user_id'])) {
throw new \LogicException('if $user_id argument is an array, user_id index must be set');
throw new LogicException('if $user_id argument is an array, user_id index must be set');
}
$auth_time = isset($userInfo['auth_time']) ? $userInfo['auth_time'] : null;

View File

@ -15,12 +15,13 @@ interface IdTokenInterface extends ResponseTypeInterface
* If the Implicit Flow is used, the token and id_token are generated and
* returned together.
*
* @param string $client_id The client id.
* @param string $user_id The user id.
* @param string $nonce OPTIONAL The nonce.
* @param string $userClaims OPTIONAL Claims about the user.
* @param string $access_token OPTIONAL The access token, if known.
*
* @param string $client_id - The client id.
* @param mixed $userInfo - User info
* @param string $nonce - OPTIONAL The nonce.
* @param string $userClaims - OPTIONAL Claims about the user.
* @param string $access_token - OPTIONAL The access token, if known.
* @internal param string $user_id - The user id.
* @return string The ID Token represented as a JSON Web Token (JWT).
*
* @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken

View File

@ -6,15 +6,33 @@ use OAuth2\ResponseType\AccessTokenInterface;
class IdTokenToken implements IdTokenTokenInterface
{
/**
* @var AccessTokenInterface
*/
protected $accessToken;
/**
* @var IdTokenInterface
*/
protected $idToken;
/**
* Constructor
*
* @param AccessTokenInterface $accessToken
* @param IdTokenInterface $idToken
*/
public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken)
{
$this->accessToken = $accessToken;
$this->idToken = $idToken;
}
/**
* @param array $params
* @param mixed $user_id
* @return mixed
*/
public function getAuthorizeResponse($params, $user_id = null)
{
$result = $this->accessToken->getAuthorizeResponse($params, $user_id);

View File

@ -23,13 +23,13 @@ interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
*
* Required for OAuth2::GRANT_TYPE_AUTH_CODE.
*
* @param $code authorization code to be stored.
* @param $client_id client identifier to be stored.
* @param $user_id user identifier to be stored.
* @param string $redirect_uri redirect URI(s) to be stored in a space-separated string.
* @param int $expires expiration to be stored as a Unix timestamp.
* @param string $scope OPTIONAL scopes to be stored in space-separated string.
* @param string $id_token OPTIONAL the OpenID Connect id_token.
* @param string $code - authorization code to be stored.
* @param mixed $client_id - client identifier to be stored.
* @param mixed $user_id - user identifier to be stored.
* @param string $redirect_uri - redirect URI(s) to be stored in a space-separated string.
* @param int $expires - expiration to be stored as a Unix timestamp.
* @param string $scope - OPTIONAL scopes to be stored in space-separated string.
* @param string $id_token - OPTIONAL the OpenID Connect id_token.
*
* @ingroup oauth2_section_4
*/

View File

@ -23,14 +23,11 @@ interface UserClaimsInterface
* Groups of claims are returned based on the requested scopes. No group
* is required, and no claim is required.
*
* @param $user_id
* The id of the user for which claims should be returned.
* @param $scope
* The requested scope.
* @param mixed $user_id - The id of the user for which claims should be returned.
* @param string $scope - The requested scope.
* Scopes with matching claims: profile, email, address, phone.
*
* @return
* An array in the claim => value format.
* @return array - An array in the claim => value format.
*
* @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
*/

View File

@ -2,6 +2,8 @@
namespace OAuth2;
use LogicException;
/**
* OAuth2\Request
* This class is taken from the Symfony2 Framework and is part of the Symfony package.
@ -21,13 +23,14 @@ class Request implements RequestInterface
/**
* Constructor.
*
* @param array $query The GET parameters
* @param array $request The POST parameters
* @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
* @param array $cookies The COOKIE parameters
* @param array $files The FILES parameters
* @param array $server The SERVER parameters
* @param string $content The raw body data
* @param array $query - The GET parameters
* @param array $request - The POST parameters
* @param array $attributes - The request attributes (parameters parsed from the PATH_INFO, ...)
* @param array $cookies - The COOKIE parameters
* @param array $files - The FILES parameters
* @param array $server - The SERVER parameters
* @param string $content - The raw body data
* @param array $headers - The headers
*
* @api
*/
@ -41,13 +44,14 @@ class Request implements RequestInterface
*
* This method also re-initializes all properties.
*
* @param array $query The GET parameters
* @param array $request The POST parameters
* @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
* @param array $cookies The COOKIE parameters
* @param array $files The FILES parameters
* @param array $server The SERVER parameters
* @param string $content The raw body data
* @param array $query - The GET parameters
* @param array $request - The POST parameters
* @param array $attributes - The request attributes (parameters parsed from the PATH_INFO, ...)
* @param array $cookies - The COOKIE parameters
* @param array $files - The FILES parameters
* @param array $server - The SERVER parameters
* @param string $content - The raw body data
* @param array $headers - The headers
*
* @api
*/
@ -63,21 +67,41 @@ class Request implements RequestInterface
$this->headers = is_null($headers) ? $this->getHeadersFromServer($this->server) : $headers;
}
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function query($name, $default = null)
{
return isset($this->query[$name]) ? $this->query[$name] : $default;
}
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function request($name, $default = null)
{
return isset($this->request[$name]) ? $this->request[$name] : $default;
}
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function server($name, $default = null)
{
return isset($this->server[$name]) ? $this->server[$name] : $default;
}
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function headers($name, $default = null)
{
$headers = array_change_key_case($this->headers);
@ -86,6 +110,9 @@ class Request implements RequestInterface
return isset($headers[$name]) ? $headers[$name] : $default;
}
/**
* @return array
*/
public function getAllQueryParameters()
{
return $this->query;
@ -94,14 +121,15 @@ class Request implements RequestInterface
/**
* Returns the request body content.
*
* @param Boolean $asResource If true, a resource will be returned
* @param boolean $asResource - If true, a resource will be returned
* @return string|resource - The request body content or a resource to read the body stream.
*
* @return string|resource The request body content or a resource to read the body stream.
* @throws LogicException
*/
public function getContent($asResource = false)
{
if (false === $this->content || (true === $asResource && null !== $this->content)) {
throw new \LogicException('getContent() can only be called once when using the resource return type.');
throw new LogicException('getContent() can only be called once when using the resource return type.');
}
if (true === $asResource) {
@ -117,6 +145,10 @@ class Request implements RequestInterface
return $this->content;
}
/**
* @param array $server
* @return array
*/
private function getHeadersFromServer($server)
{
$headers = array();
@ -185,13 +217,15 @@ class Request implements RequestInterface
/**
* Creates a new request with values from PHP's super globals.
*
* @return Request A new request
* @return Request - A new request
*
* @api
*/
public static function createFromGlobals()
{
$class = get_called_class();
/** @var Request $request */
$request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER);
$contentType = $request->server('CONTENT_TYPE', '');

View File

@ -4,13 +4,36 @@ namespace OAuth2;
interface RequestInterface
{
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function query($name, $default = null);
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function request($name, $default = null);
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function server($name, $default = null);
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function headers($name, $default = null);
/**
* @return mixed
*/
public function getAllQueryParameters();
}

View File

@ -2,6 +2,8 @@
namespace OAuth2;
use InvalidArgumentException;
/**
* Class to handle OAuth2 Responses in a graceful way. Use this interface
* to output the proper OAuth2 responses.
@ -13,12 +15,34 @@ namespace OAuth2;
*/
class Response implements ResponseInterface
{
/**
* @var string
*/
public $version;
/**
* @var int
*/
protected $statusCode = 200;
/**
* @var string
*/
protected $statusText;
/**
* @var array
*/
protected $parameters = array();
/**
* @var array
*/
protected $httpHeaders = array();
/**
* @var array
*/
public static $statusTexts = array(
100 => 'Continue',
101 => 'Switching Protocols',
@ -63,6 +87,11 @@ class Response implements ResponseInterface
505 => 'HTTP Version Not Supported',
);
/**
* @param array $parameters
* @param int $statusCode
* @param array $headers
*/
public function __construct($parameters = array(), $statusCode = 200, $headers = array())
{
$this->setParameters($parameters);
@ -102,76 +131,128 @@ class Response implements ResponseInterface
return sprintf("%s: %s\n", $name, $value);
}
/**
* @return int
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* @param int $statusCode
* @param string $text
* @throws InvalidArgumentException
*/
public function setStatusCode($statusCode, $text = null)
{
$this->statusCode = (int) $statusCode;
if ($this->isInvalid()) {
throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode));
throw new InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode));
}
$this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text);
}
/**
* @return string
*/
public function getStatusText()
{
return $this->statusText;
}
/**
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* @param array $parameters
*/
public function setParameters(array $parameters)
{
$this->parameters = $parameters;
}
/**
* @param array $parameters
*/
public function addParameters(array $parameters)
{
$this->parameters = array_merge($this->parameters, $parameters);
}
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function getParameter($name, $default = null)
{
return isset($this->parameters[$name]) ? $this->parameters[$name] : $default;
}
/**
* @param string $name
* @param mixed $value
*/
public function setParameter($name, $value)
{
$this->parameters[$name] = $value;
}
/**
* @param array $httpHeaders
*/
public function setHttpHeaders(array $httpHeaders)
{
$this->httpHeaders = $httpHeaders;
}
/**
* @param string $name
* @param mixed $value
*/
public function setHttpHeader($name, $value)
{
$this->httpHeaders[$name] = $value;
}
/**
* @param array $httpHeaders
*/
public function addHttpHeaders(array $httpHeaders)
{
$this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders);
}
/**
* @return array
*/
public function getHttpHeaders()
{
return $this->httpHeaders;
}
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function getHttpHeader($name, $default = null)
{
return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default;
}
/**
* @param string $format
* @return mixed
* @throws InvalidArgumentException
*/
public function getResponseBody($format = 'json')
{
switch ($format) {
@ -187,10 +268,13 @@ class Response implements ResponseInterface
return $xml->asXML();
}
throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format));
throw new InvalidArgumentException(sprintf('The format %s is not supported', $format));
}
/**
* @param string $format
*/
public function send($format = 'json')
{
// headers have already been sent by the developer
@ -215,6 +299,14 @@ class Response implements ResponseInterface
echo $this->getResponseBody($format);
}
/**
* @param int $statusCode
* @param string $error
* @param string $errorDescription
* @param string $errorUri
* @return mixed
* @throws InvalidArgumentException
*/
public function setError($statusCode, $error, $errorDescription = null, $errorUri = null)
{
$parameters = array(
@ -239,14 +331,24 @@ class Response implements ResponseInterface
$this->addHttpHeaders($httpHeaders);
if (!$this->isClientError() && !$this->isServerError()) {
throw new \InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode));
throw new InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode));
}
}
/**
* @param int $statusCode
* @param string $url
* @param string $state
* @param string $error
* @param string $errorDescription
* @param string $errorUri
* @return mixed
* @throws InvalidArgumentException
*/
public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null)
{
if (empty($url)) {
throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
throw new InvalidArgumentException('Cannot redirect to an empty URL.');
}
$parameters = array();
@ -271,15 +373,16 @@ class Response implements ResponseInterface
$this->addHttpHeaders(array('Location' => $url));
if (!$this->isRedirection()) {
throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode));
throw new InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode));
}
}
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
/**
* @return Boolean
*
* @api
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
*/
public function isInvalid()
{
@ -336,8 +439,11 @@ class Response implements ResponseInterface
return $this->statusCode >= 500 && $this->statusCode < 600;
}
/*
* Functions from Symfony2 HttpFoundation - output pretty header
/**
* Function from Symfony2 HttpFoundation - output pretty header
*
* @param array $headers
* @return string
*/
private function getHttpHeadersAsString($headers)
{
@ -357,11 +463,23 @@ class Response implements ResponseInterface
return $content;
}
/**
* Function from Symfony2 HttpFoundation - output pretty header
*
* @param string $name
* @return mixed
*/
private function beautifyHeaderName($name)
{
return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name));
}
/**
* Function from Symfony2 HttpFoundation - output pretty header
*
* @param array $match
* @return string
*/
private function beautifyCallback($match)
{
return '-'.strtoupper($match[1]);

View File

@ -6,19 +6,48 @@ namespace OAuth2;
* Interface which represents an object response. Meant to handle and display the proper OAuth2 Responses
* for errors and successes
*
* @see OAuth2\Response
* @see \OAuth2\Response
*/
interface ResponseInterface
{
/**
* @param array $parameters
*/
public function addParameters(array $parameters);
/**
* @param array $httpHeaders
*/
public function addHttpHeaders(array $httpHeaders);
/**
* @param int $statusCode
*/
public function setStatusCode($statusCode);
/**
* @param int $statusCode
* @param string $name
* @param string $description
* @param string $uri
* @return mixed
*/
public function setError($statusCode, $name, $description = null, $uri = null);
/**
* @param int $statusCode
* @param string $url
* @param string $state
* @param string $error
* @param string $errorDescription
* @param string $errorUri
* @return mixed
*/
public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null);
/**
* @param string $name
* @return mixed
*/
public function getParameter($name);
}

View File

@ -4,28 +4,39 @@ namespace OAuth2\ResponseType;
use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
use OAuth2\Storage\RefreshTokenInterface;
use RuntimeException;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class AccessToken implements AccessTokenInterface
{
/**
* @var AccessTokenInterface
*/
protected $tokenStorage;
/**
* @var RefreshTokenInterface
*/
protected $refreshStorage;
/**
* @var array
*/
protected $config;
/**
* @param OAuth2\Storage\AccessTokenInterface $tokenStorage REQUIRED Storage class for saving access token information
* @param OAuth2\Storage\RefreshTokenInterface $refreshStorage OPTIONAL Storage class for saving refresh token information
* @param array $config OPTIONAL Configuration options for the server
* <code>
* @param AccessTokenStorageInterface $tokenStorage - REQUIRED Storage class for saving access token information
* @param RefreshTokenInterface $refreshStorage - OPTIONAL Storage class for saving refresh token information
* @param array $config - OPTIONAL Configuration options for the server
* @code
* $config = array(
* 'token_type' => 'bearer', // token type identifier
* 'access_lifetime' => 3600, // time before access token expires
* 'refresh_token_lifetime' => 1209600, // time before refresh token expires
* );
* </endcode>
* @endcode
*/
public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array())
{
@ -39,6 +50,13 @@ class AccessToken implements AccessTokenInterface
), $config);
}
/**
* Get authorize response
*
* @param array $params
* @param mixed $user_id
* @return array
*/
public function getAuthorizeResponse($params, $user_id = null)
{
// build the URL to redirect to
@ -64,10 +82,11 @@ class AccessToken implements AccessTokenInterface
/**
* Handle the creation of access token, also issue refresh token if supported / desirable.
*
* @param $client_id client identifier related to the access token.
* @param $user_id user ID associated with the access token
* @param $scope OPTIONAL scopes to be stored in space-separated string.
* @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user ID associated with the access token
* @param string $scope - OPTIONAL scopes to be stored in space-separated string.
* @param bool $includeRefreshToken - if true, a new refresh_token will be added to the response
* @return array
*
* @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5
@ -107,13 +126,18 @@ class AccessToken implements AccessTokenInterface
* Implementing classes may want to override this function to implement
* other access token generation schemes.
*
* @return
* An unique access token.
* @return string - A unique access token.
*
* @ingroup oauth2_section_4
*/
protected function generateAccessToken()
{
if (function_exists('random_bytes')) {
$randomData = random_bytes(20);
if ($randomData !== false && strlen($randomData) === 20) {
return bin2hex($randomData);
}
}
if (function_exists('openssl_random_pseudo_bytes')) {
$randomData = openssl_random_pseudo_bytes(20);
if ($randomData !== false && strlen($randomData) === 20) {
@ -144,8 +168,7 @@ class AccessToken implements AccessTokenInterface
* Implementing classes may want to override this function to implement
* other refresh token generation schemes.
*
* @return
* An unique refresh.
* @return string - A unique refresh token.
*
* @ingroup oauth2_section_4
* @see OAuth2::generateAccessToken()
@ -162,6 +185,7 @@ class AccessToken implements AccessTokenInterface
*
* @param $token
* @param null $tokenTypeHint
* @throws RuntimeException
* @return boolean
*/
public function revokeToken($token, $tokenTypeHint = null)
@ -174,7 +198,7 @@ class AccessToken implements AccessTokenInterface
/** @TODO remove in v2 */
if (!method_exists($this->tokenStorage, 'unsetAccessToken')) {
throw new \RuntimeException(
throw new RuntimeException(
sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage)
));
}

View File

@ -3,7 +3,6 @@
namespace OAuth2\ResponseType;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
interface AccessTokenInterface extends ResponseTypeInterface
@ -11,10 +10,10 @@ interface AccessTokenInterface extends ResponseTypeInterface
/**
* Handle the creation of access token, also issue refresh token if supported / desirable.
*
* @param $client_id client identifier related to the access token.
* @param $user_id user ID associated with the access token
* @param $scope OPTONAL scopes to be stored in space-separated string.
* @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user ID associated with the access token
* @param string $scope - OPTONAL scopes to be stored in space-separated string.
* @param bool $includeRefreshToken - if true, a new refresh_token will be added to the response
*
* @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5

View File

@ -5,7 +5,6 @@ namespace OAuth2\ResponseType;
use OAuth2\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class AuthorizationCode implements AuthorizationCodeInterface
@ -85,7 +84,9 @@ class AuthorizationCode implements AuthorizationCodeInterface
protected function generateAuthorizationCode()
{
$tokenLen = 40;
if (function_exists('openssl_random_pseudo_bytes')) {
if (function_exists('random_bytes')) {
$randomData = random_bytes(100);
} elseif (function_exists('openssl_random_pseudo_bytes')) {
$randomData = openssl_random_pseudo_bytes(100);
} elseif (function_exists('mcrypt_create_iv')) {
$randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM);

View File

@ -3,7 +3,6 @@
namespace OAuth2\ResponseType;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
interface AuthorizationCodeInterface extends ResponseTypeInterface
@ -17,11 +16,12 @@ interface AuthorizationCodeInterface extends ResponseTypeInterface
/**
* Handle the creation of the authorization code.
*
* @param $client_id client identifier related to the authorization code
* @param $user_id user id associated with the authorization code
* @param $redirect_uri an absolute URI to which the authorization server will redirect the
* @param mixed $client_id - Client identifier related to the authorization code
* @param mixed $user_id - User ID associated with the authorization code
* @param string $redirect_uri - An absolute URI to which the authorization server will redirect the
* user-agent to when the end-user authorization step is completed.
* @param $scope OPTIONAL scopes to be stored in space-separated string.
* @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
* @return string
*
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4

View File

@ -10,7 +10,6 @@ use OAuth2\Storage\PublicKeyInterface;
use OAuth2\Storage\Memory;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class JwtAccessToken extends AccessToken
@ -19,10 +18,13 @@ class JwtAccessToken extends AccessToken
protected $encryptionUtil;
/**
* @param $config
* - store_encrypted_token_string (bool true)
* @param PublicKeyInterface $publicKeyStorage -
* @param AccessTokenStorageInterface $tokenStorage -
* @param RefreshTokenInterface $refreshStorage -
* @param array $config - array with key store_encrypted_token_string (bool true)
* whether the entire encrypted string is stored,
* or just the token ID is stored
* @param EncryptionInterface $encryptionUtil -
*/
public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
{
@ -45,46 +47,31 @@ class JwtAccessToken extends AccessToken
/**
* Handle the creation of access token, also issue refresh token if supported / desirable.
*
* @param $client_id
* Client identifier related to the access token.
* @param $user_id
* User ID associated with the access token
* @param $scope
* (optional) Scopes to be stored in space-separated string.
* @param bool $includeRefreshToken
* If true, a new refresh_token will be added to the response
* @param mixed $client_id - Client identifier related to the access token.
* @param mixed $user_id - User ID associated with the access token
* @param string $scope - (optional) Scopes to be stored in space-separated string.
* @param bool $includeRefreshToken - If true, a new refresh_token will be added to the response
* @return array - The access token
*
* @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5
*/
public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
{
// token to encrypt
$expires = time() + $this->config['access_lifetime'];
$id = $this->generateAccessToken();
$jwtAccessToken = array(
'id' => $id, // for BC (see #591)
'jti' => $id,
'iss' => $this->config['issuer'],
'aud' => $client_id,
'sub' => $user_id,
'exp' => $expires,
'iat' => time(),
'token_type' => $this->config['token_type'],
'scope' => $scope
);
// payload to encrypt
$payload = $this->createPayload($client_id, $user_id, $scope);
/*
* Encode the token data into a single access_token string
* Encode the payload data into a single JWT access_token string
*/
$access_token = $this->encodeToken($jwtAccessToken, $client_id);
$access_token = $this->encodeToken($payload, $client_id);
/*
* Save the token to a secondary storage. This is implemented on the
* OAuth2\Storage\JwtAccessToken side, and will not actually store anything,
* if no secondary storage has been supplied
*/
$token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $jwtAccessToken['id'];
$token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $payload['id'];
$this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
// token to return to the client
@ -114,6 +101,11 @@ class JwtAccessToken extends AccessToken
return $token;
}
/**
* @param array $token
* @param mixed $client_id
* @return mixed
*/
protected function encodeToken(array $token, $client_id = null)
{
$private_key = $this->publicKeyStorage->getPrivateKey($client_id);
@ -121,4 +113,31 @@ class JwtAccessToken extends AccessToken
return $this->encryptionUtil->encode($token, $private_key, $algorithm);
}
/**
* This function can be used to create custom JWT payloads
*
* @param mixed $client_id - Client identifier related to the access token.
* @param mixed $user_id - User ID associated with the access token
* @param string $scope - (optional) Scopes to be stored in space-separated string.
* @return array - The access token
*/
protected function createPayload($client_id, $user_id, $scope = null)
{
// token to encrypt
$expires = time() + $this->config['access_lifetime'];
$id = $this->generateAccessToken();
return array(
'id' => $id, // for BC (see #591)
'jti' => $id,
'iss' => $this->config['issuer'],
'aud' => $client_id,
'sub' => $user_id,
'exp' => $expires,
'iat' => time(),
'token_type' => $this->config['token_type'],
'scope' => $scope
);
}
}

View File

@ -4,5 +4,10 @@ namespace OAuth2\ResponseType;
interface ResponseTypeInterface
{
/**
* @param array $params
* @param mixed $user_id
* @return mixed
*/
public function getAuthorizeResponse($params, $user_id = null);
}

View File

@ -2,19 +2,23 @@
namespace OAuth2;
use InvalidArgumentException;
use OAuth2\Storage\Memory;
use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
/**
* @see OAuth2\ScopeInterface
* @see ScopeInterface
*/
class Scope implements ScopeInterface
{
protected $storage;
/**
* @param mixed @storage
* Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface
* Constructor
*
* @param mixed $storage - Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface
*
* @throws InvalidArgumentException
*/
public function __construct($storage = null)
{
@ -23,7 +27,7 @@ class Scope implements ScopeInterface
}
if (!$storage instanceof ScopeStorageInterface) {
throw new \InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface");
throw new InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface");
}
$this->storage = $storage;
@ -32,12 +36,10 @@ class Scope implements ScopeInterface
/**
* Check if everything in required scope is contained in available scope.
*
* @param $required_scope
* A space-separated string of scopes.
*
* @return
* TRUE if everything in required scope is contained in available scope,
* and FALSE if it isn't.
* @param string $required_scope - A space-separated string of scopes.
* @param string $available_scope - A space-separated string of scopes.
* @return bool - TRUE if everything in required scope is contained in available scope and FALSE
* if it isn't.
*
* @see http://tools.ietf.org/html/rfc6749#section-7
*
@ -54,11 +56,8 @@ class Scope implements ScopeInterface
/**
* Check if the provided scope exists in storage.
*
* @param $scope
* A space-separated string of scopes.
*
* @return
* TRUE if it exists, FALSE otherwise.
* @param string $scope - A space-separated string of scopes.
* @return bool - TRUE if it exists, FALSE otherwise.
*/
public function scopeExists($scope)
{
@ -76,12 +75,20 @@ class Scope implements ScopeInterface
}
}
/**
* @param RequestInterface $request
* @return string
*/
public function getScopeFromRequest(RequestInterface $request)
{
// "scope" is valid if passed in either POST or QUERY
return $request->request('scope', $request->query('scope'));
}
/**
* @param null $client_id
* @return mixed
*/
public function getDefaultScope($client_id = null)
{
return $this->storage->getDefaultScope($client_id);
@ -93,8 +100,7 @@ class Scope implements ScopeInterface
* In case OpenID Connect is used, these scopes must include:
* 'openid', offline_access'.
*
* @return
* An array of reserved scopes.
* @return array - An array of reserved scopes.
*/
public function getReservedScopes()
{

View File

@ -7,19 +7,17 @@ use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
/**
* Class to handle scope implementation logic
*
* @see OAuth2\Storage\ScopeInterface
* @see \OAuth2\Storage\ScopeInterface
*/
interface ScopeInterface extends ScopeStorageInterface
{
/**
* Check if everything in required scope is contained in available scope.
*
* @param $required_scope
* A space-separated string of scopes.
*
* @return
* TRUE if everything in required scope is contained in available scope,
* and FALSE if it isn't.
* @param string $required_scope - A space-separated string of scopes.
* @param string $available_scope - A space-separated string of scopes.
* @return boolean - TRUE if everything in required scope is contained in available scope and FALSE
* if it isn't.
*
* @see http://tools.ietf.org/html/rfc6749#section-7
*
@ -30,11 +28,8 @@ interface ScopeInterface extends ScopeStorageInterface
/**
* Return scope info from request
*
* @param OAuth2\RequestInterface
* Request object to check
*
* @return
* string representation of requested scope
* @param RequestInterface $request - Request object to check
* @return string - representation of requested scope
*/
public function getScopeFromRequest(RequestInterface $request);
}

View File

@ -30,25 +30,28 @@ use OAuth2\GrantType\UserCredentials;
use OAuth2\GrantType\ClientCredentials;
use OAuth2\GrantType\RefreshToken;
use OAuth2\GrantType\AuthorizationCode;
use OAuth2\Storage\ClientCredentialsInterface;
use OAuth2\Storage\ClientInterface;
use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage;
use OAuth2\Storage\JwtAccessTokenInterface;
use InvalidArgumentException;
use LogicException;
/**
* Server class for OAuth2
* This class serves as a convience class which wraps the other Controller classes
*
* @see OAuth2\Controller\ResourceController
* @see OAuth2\Controller\AuthorizeController
* @see OAuth2\Controller\TokenController
* @see \OAuth2\Controller\ResourceController
* @see \OAuth2\Controller\AuthorizeController
* @see \OAuth2\Controller\TokenController
*/
class Server implements ResourceControllerInterface,
AuthorizeControllerInterface,
TokenControllerInterface,
UserInfoControllerInterface
{
// misc properties
/**
* @var Response
* @var ResponseInterface
*/
protected $response;
@ -62,7 +65,6 @@ class Server implements ResourceControllerInterface,
*/
protected $storages;
// servers
/**
* @var AuthorizeControllerInterface
*/
@ -83,17 +85,34 @@ class Server implements ResourceControllerInterface,
*/
protected $userInfoController;
// config classes
protected $grantTypes;
protected $responseTypes;
/**
* @var array
*/
protected $grantTypes = [];
/**
* @var array
*/
protected $responseTypes = [];
/**
* @var TokenTypeInterface
*/
protected $tokenType;
/**
* @var ScopeInterface
*/
protected $scopeUtil;
/**
* @var ClientAssertionTypeInterface
*/
protected $clientAssertionType;
/**
* @var array
*/
protected $storageMap = array(
'access_token' => 'OAuth2\Storage\AccessTokenInterface',
'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface',
@ -107,6 +126,9 @@ class Server implements ResourceControllerInterface,
'scope' => 'OAuth2\Storage\ScopeInterface',
);
/**
* @var array
*/
protected $responseTypeMap = array(
'token' => 'OAuth2\ResponseType\AccessTokenInterface',
'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface',
@ -120,11 +142,11 @@ class Server implements ResourceControllerInterface,
* required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum)
* @param array $config specify a different token lifetime, token header name, etc
* @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens
* @param array $responseTypes Response types to use. array keys should be "code" and and "token" for
* @param array $responseTypes Response types to use. array keys should be "code" and "token" for
* Access Token and Authorization Code response types
* @param \OAuth2\TokenType\TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac"
* @param \OAuth2\ScopeInterface $scopeUtil The scope utility class to use to validate scope
* @param \OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic
* @param TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac"
* @param ScopeInterface $scopeUtil The scope utility class to use to validate scope
* @param ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic
*
* @ingroup oauth2_section_7
*/
@ -172,6 +194,9 @@ class Server implements ResourceControllerInterface,
}
}
/**
* @return AuthorizeControllerInterface
*/
public function getAuthorizeController()
{
if (is_null($this->authorizeController)) {
@ -181,6 +206,9 @@ class Server implements ResourceControllerInterface,
return $this->authorizeController;
}
/**
* @return TokenController
*/
public function getTokenController()
{
if (is_null($this->tokenController)) {
@ -190,6 +218,9 @@ class Server implements ResourceControllerInterface,
return $this->tokenController;
}
/**
* @return ResourceControllerInterface
*/
public function getResourceController()
{
if (is_null($this->resourceController)) {
@ -199,6 +230,9 @@ class Server implements ResourceControllerInterface,
return $this->resourceController;
}
/**
* @return UserInfoControllerInterface
*/
public function getUserInfoController()
{
if (is_null($this->userInfoController)) {
@ -209,8 +243,6 @@ class Server implements ResourceControllerInterface,
}
/**
* every getter deserves a setter
*
* @param AuthorizeControllerInterface $authorizeController
*/
public function setAuthorizeController(AuthorizeControllerInterface $authorizeController)
@ -219,8 +251,6 @@ class Server implements ResourceControllerInterface,
}
/**
* every getter deserves a setter
*
* @param TokenControllerInterface $tokenController
*/
public function setTokenController(TokenControllerInterface $tokenController)
@ -229,8 +259,6 @@ class Server implements ResourceControllerInterface,
}
/**
* every getter deserves a setter
*
* @param ResourceControllerInterface $resourceController
*/
public function setResourceController(ResourceControllerInterface $resourceController)
@ -239,8 +267,6 @@ class Server implements ResourceControllerInterface,
}
/**
* every getter deserves a setter
*
* @param UserInfoControllerInterface $userInfoController
*/
public function setUserInfoController(UserInfoControllerInterface $userInfoController)
@ -252,12 +278,8 @@ class Server implements ResourceControllerInterface,
* Return claims about the authenticated end-user.
* This would be called from the "/UserInfo" endpoint as defined in the spec.
*
* @param $request - \OAuth2\RequestInterface
* Request object to grant access token
*
* @param $response - \OAuth2\ResponseInterface
* Response object containing error messages (failure) or user claims (success)
*
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object containing error messages (failure) or user claims (success)
* @return ResponseInterface
*
* @throws \InvalidArgumentException
@ -278,12 +300,8 @@ class Server implements ResourceControllerInterface,
* This would be called from the "/token" endpoint as defined in the spec.
* Obviously, you can call your endpoint whatever you want.
*
* @param $request - \OAuth2\RequestInterface
* Request object to grant access token
*
* @param $response - \OAuth2\ResponseInterface
* Response object containing error messages (failure) or access token (success)
*
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object containing error messages (failure) or access token (success)
* @return ResponseInterface
*
* @throws \InvalidArgumentException
@ -303,6 +321,11 @@ class Server implements ResourceControllerInterface,
return $this->response;
}
/**
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object
* @return mixed
*/
public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null)
{
$this->response = is_null($response) ? new Response() : $response;
@ -336,25 +359,18 @@ class Server implements ResourceControllerInterface,
* authorization server should call this function to redirect the user
* appropriately.
*
* @param $request
* The request should have the follow parameters set in the querystring:
* - response_type: The requested response: an access token, an
* authorization code, or both.
* @param RequestInterface $request - The request should have the follow parameters set in the querystring:
* - response_type: The requested response: an access token, an authorization code, or both.
* - client_id: The client identifier as described in Section 2.
* - redirect_uri: An absolute URI to which the authorization server
* will redirect the user-agent to when the end-user authorization
* step is completed.
* - scope: (optional) The scope of the resource request expressed as a
* list of space-delimited strings.
* - state: (optional) An opaque value used by the client to maintain
* state between the request and callback.
* @param ResponseInterface $response
* @param $is_authorized
* TRUE or FALSE depending on whether the user authorized the access.
* @param $user_id
* Identifier of user who authorized the client
* - redirect_uri: An absolute URI to which the authorization server will redirect the user-agent to when the
* end-user authorization step is completed.
* - scope: (optional) The scope of the resource request expressed as a list of space-delimited strings.
* - state: (optional) An opaque value used by the client to maintain state between the request and callback.
*
* @return Response
* @param ResponseInterface $response - Response object
* @param bool $is_authorized - TRUE or FALSE depending on whether the user authorized the access.
* @param mixed $user_id - Identifier of user who authorized the client
* @return ResponseInterface
*
* @see http://tools.ietf.org/html/rfc6749#section-4
*
@ -378,7 +394,10 @@ class Server implements ResourceControllerInterface,
* The draft specifies that the parameters should be retrieved from GET, override the Response
* object to change this
*
* @return
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @return bool
*
* The authorization parameters so the authorization server can prompt
* the user for approval if valid.
*
@ -395,6 +414,12 @@ class Server implements ResourceControllerInterface,
return $value;
}
/**
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @param string $scope - Scope
* @return mixed
*/
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null)
{
$this->response = is_null($response) ? new Response() : $response;
@ -403,6 +428,11 @@ class Server implements ResourceControllerInterface,
return $value;
}
/**
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @return mixed
*/
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null)
{
$this->response = is_null($response) ? new Response() : $response;
@ -411,10 +441,14 @@ class Server implements ResourceControllerInterface,
return $value;
}
/**
* @param GrantTypeInterface $grantType
* @param mixed $identifier
*/
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
{
if (!is_string($identifier)) {
$identifier = $grantType->getQuerystringIdentifier();
$identifier = $grantType->getQueryStringIdentifier();
}
$this->grantTypes[$identifier] = $grantType;
@ -428,11 +462,10 @@ class Server implements ResourceControllerInterface,
/**
* Set a storage object for the server
*
* @param $storage
* An object implementing one of the Storage interfaces
* @param $key
* If null, the storage is set to the key of each storage interface it implements
* @param object $storage - An object implementing one of the Storage interfaces
* @param mixed $key - If null, the storage is set to the key of each storage interface it implements
*
* @throws InvalidArgumentException
* @see storageMap
*/
public function addStorage($storage, $key = null)
@ -446,11 +479,11 @@ class Server implements ResourceControllerInterface,
// special logic to handle "client" and "client_credentials" strangeness
if ($key === 'client' && !isset($this->storages['client_credentials'])) {
if ($storage instanceof \OAuth2\Storage\ClientCredentialsInterface) {
if ($storage instanceof ClientCredentialsInterface) {
$this->storages['client_credentials'] = $storage;
}
} elseif ($key === 'client_credentials' && !isset($this->storages['client'])) {
if ($storage instanceof \OAuth2\Storage\ClientInterface) {
if ($storage instanceof ClientInterface) {
$this->storages['client'] = $storage;
}
}
@ -471,6 +504,12 @@ class Server implements ResourceControllerInterface,
}
}
/**
* @param ResponseTypeInterface $responseType
* @param mixed $key
*
* @throws InvalidArgumentException
*/
public function addResponseType(ResponseTypeInterface $responseType, $key = null)
{
$key = $this->normalizeResponseType($key);
@ -497,6 +536,9 @@ class Server implements ResourceControllerInterface,
}
}
/**
* @return ScopeInterface
*/
public function getScopeUtil()
{
if (!$this->scopeUtil) {
@ -508,8 +550,6 @@ class Server implements ResourceControllerInterface,
}
/**
* every getter deserves a setter
*
* @param ScopeInterface $scopeUtil
*/
public function setScopeUtil($scopeUtil)
@ -517,6 +557,10 @@ class Server implements ResourceControllerInterface,
$this->scopeUtil = $scopeUtil;
}
/**
* @return AuthorizeControllerInterface
* @throws LogicException
*/
protected function createDefaultAuthorizeController()
{
if (!isset($this->storages['client'])) {
@ -541,6 +585,10 @@ class Server implements ResourceControllerInterface,
return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
}
/**
* @return TokenControllerInterface
* @throws LogicException
*/
protected function createDefaultTokenController()
{
if (0 == count($this->grantTypes)) {
@ -562,7 +610,7 @@ class Server implements ResourceControllerInterface,
}
if (!isset($this->storages['client'])) {
throw new \LogicException('You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server');
throw new LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server");
}
$accessTokenResponseType = $this->getAccessTokenResponseType();
@ -570,6 +618,10 @@ class Server implements ResourceControllerInterface,
return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil());
}
/**
* @return ResourceControllerInterface
* @throws LogicException
*/
protected function createDefaultResourceController()
{
if ($this->config['use_jwt_access_tokens']) {
@ -590,6 +642,10 @@ class Server implements ResourceControllerInterface,
return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil());
}
/**
* @return UserInfoControllerInterface
* @throws LogicException
*/
protected function createDefaultUserInfoController()
{
if ($this->config['use_jwt_access_tokens']) {
@ -614,6 +670,9 @@ class Server implements ResourceControllerInterface,
return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil());
}
/**
* @return Bearer
*/
protected function getDefaultTokenType()
{
$config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name')));
@ -621,6 +680,10 @@ class Server implements ResourceControllerInterface,
return new Bearer($config);
}
/**
* @return array
* @throws LogicException
*/
protected function getDefaultResponseTypes()
{
$responseTypes = array();
@ -656,6 +719,10 @@ class Server implements ResourceControllerInterface,
return $responseTypes;
}
/**
* @return array
* @throws LogicException
*/
protected function getDefaultGrantTypes()
{
$grantTypes = array();
@ -692,6 +759,9 @@ class Server implements ResourceControllerInterface,
return $grantTypes;
}
/**
* @return AccessToken
*/
protected function getAccessTokenResponseType()
{
if (isset($this->responseTypes['token'])) {
@ -705,6 +775,9 @@ class Server implements ResourceControllerInterface,
return $this->createDefaultAccessTokenResponseType();
}
/**
* @return IdToken
*/
protected function getIdTokenResponseType()
{
if (isset($this->responseTypes['id_token'])) {
@ -714,6 +787,9 @@ class Server implements ResourceControllerInterface,
return $this->createDefaultIdTokenResponseType();
}
/**
* @return IdTokenToken
*/
protected function getIdTokenTokenResponseType()
{
if (isset($this->responseTypes['id_token token'])) {
@ -725,6 +801,9 @@ class Server implements ResourceControllerInterface,
/**
* For Resource Controller
*
* @return JwtAccessTokenStorage
* @throws LogicException
*/
protected function createDefaultJwtAccessTokenStorage()
{
@ -741,6 +820,9 @@ class Server implements ResourceControllerInterface,
/**
* For Authorize and Token Controllers
*
* @return JwtAccessToken
* @throws LogicException
*/
protected function createDefaultJwtAccessTokenResponseType()
{
@ -763,10 +845,14 @@ class Server implements ResourceControllerInterface,
return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config);
}
/**
* @return AccessToken
* @throws LogicException
*/
protected function createDefaultAccessTokenResponseType()
{
if (!isset($this->storages['access_token'])) {
throw new \LogicException('You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server');
throw new LogicException("You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server");
}
$refreshStorage = null;
@ -780,13 +866,17 @@ class Server implements ResourceControllerInterface,
return new AccessToken($this->storages['access_token'], $refreshStorage, $config);
}
/**
* @return IdToken
* @throws LogicException
*/
protected function createDefaultIdTokenResponseType()
{
if (!isset($this->storages['user_claims'])) {
throw new \LogicException('You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect');
throw new LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect");
}
if (!isset($this->storages['public_key'])) {
throw new \LogicException('You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect');
throw new LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect");
}
$config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime')));
@ -794,11 +884,17 @@ class Server implements ResourceControllerInterface,
return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config);
}
/**
* @return IdTokenToken
*/
protected function createDefaultIdTokenTokenResponseType()
{
return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType());
}
/**
* @throws InvalidArgumentException
*/
protected function validateOpenIdConnect()
{
$authCodeGrant = $this->getGrantType('authorization_code');
@ -807,6 +903,10 @@ class Server implements ResourceControllerInterface,
}
}
/**
* @param string $name
* @return string
*/
protected function normalizeResponseType($name)
{
// for multiple-valued response types - make them alphabetical
@ -819,36 +919,60 @@ class Server implements ResourceControllerInterface,
return $name;
}
/**
* @return mixed
*/
public function getResponse()
{
return $this->response;
}
/**
* @return array
*/
public function getStorages()
{
return $this->storages;
}
/**
* @param string $name
* @return object|null
*/
public function getStorage($name)
{
return isset($this->storages[$name]) ? $this->storages[$name] : null;
}
/**
* @return array
*/
public function getGrantTypes()
{
return $this->grantTypes;
}
/**
* @param string $name
* @return object|null
*/
public function getGrantType($name)
{
return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null;
}
/**
* @return array
*/
public function getResponseTypes()
{
return $this->responseTypes;
}
/**
* @param string $name
* @return object|null
*/
public function getResponseType($name)
{
// for multiple-valued response types - make them alphabetical
@ -857,21 +981,36 @@ class Server implements ResourceControllerInterface,
return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null;
}
/**
* @return TokenTypeInterface
*/
public function getTokenType()
{
return $this->tokenType;
}
/**
* @return ClientAssertionTypeInterface
*/
public function getClientAssertionType()
{
return $this->clientAssertionType;
}
/**
* @param string $name
* @param mixed $value
*/
public function setConfig($name, $value)
{
$this->config[$name] = $value;
}
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function getConfig($name, $default = null)
{
return isset($this->config[$name]) ? $this->config[$name] : $default;

View File

@ -15,17 +15,18 @@ interface AccessTokenInterface
*
* We need to retrieve access token data as we create and verify tokens.
*
* @param $oauth_token
* oauth_token to be check with.
* @param string $oauth_token - oauth_token to be check with.
*
* @return
* An associative array as below, and return NULL if the supplied oauth_token
* is invalid:
* - expires: Stored expiration in unix timestamp.
* - client_id: (optional) Stored client identifier.
* - user_id: (optional) Stored user identifier.
* - scope: (optional) Stored scope values in space-separated string.
* - id_token: (optional) Stored id_token (if "use_openid_connect" is true).
* @return array|null - An associative array as below, and return NULL if the supplied oauth_token is invalid:
* @code
* array(
* 'expires' => $expires, // Stored expiration in unix timestamp.
* 'client_id' => $client_id, // (optional) Stored client identifier.
* 'user_id' => $user_id, // (optional) Stored user identifier.
* 'scope' => $scope, // (optional) Stored scope values in space-separated string.
* 'id_token' => $id_token // (optional) Stored id_token (if "use_openid_connect" is true).
* );
* @endcode
*
* @ingroup oauth2_section_7
*/
@ -36,11 +37,11 @@ interface AccessTokenInterface
*
* We need to store access token data as we create and verify tokens.
*
* @param $oauth_token oauth_token to be stored.
* @param $client_id client identifier to be stored.
* @param $user_id user identifier to be stored.
* @param int $expires expiration to be stored as a Unix timestamp.
* @param string $scope OPTIONAL Scopes to be stored in space-separated string.
* @param string $oauth_token - oauth_token to be stored.
* @param mixed $client_id - client identifier to be stored.
* @param mixed $user_id - user identifier to be stored.
* @param int $expires - expiration to be stored as a Unix timestamp.
* @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
*
* @ingroup oauth2_section_4
*/

View File

@ -59,12 +59,12 @@ interface AuthorizationCodeInterface
*
* Required for OAuth2::GRANT_TYPE_AUTH_CODE.
*
* @param string $code Authorization code to be stored.
* @param mixed $client_id Client identifier to be stored.
* @param mixed $user_id User identifier to be stored.
* @param string $redirect_uri Redirect URI(s) to be stored in a space-separated string.
* @param int $expires Expiration to be stored as a Unix timestamp.
* @param string $scope OPTIONAL Scopes to be stored in space-separated string.
* @param string $code - Authorization code to be stored.
* @param mixed $client_id - Client identifier to be stored.
* @param mixed $user_id - User identifier to be stored.
* @param string $redirect_uri - Redirect URI(s) to be stored in a space-separated string.
* @param int $expires - Expiration to be stored as a Unix timestamp.
* @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
*
* @ingroup oauth2_section_4
*/

View File

@ -7,16 +7,17 @@ use phpcassa\ColumnSlice;
use phpcassa\Connection\ConnectionPool;
use OAuth2\OpenID\Storage\UserClaimsInterface;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
use InvalidArgumentException;
/**
* Cassandra storage for all storage types
*
* To use, install "thobbs/phpcassa" via composer
* To use, install "thobbs/phpcassa" via composer:
* <code>
* composer require thobbs/phpcassa:dev-master
* </code>
*
* Once this is done, instantiate the
* Once this is done, instantiate the connection:
* <code>
* $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160'));
* </code>
@ -43,17 +44,23 @@ class Cassandra implements AuthorizationCodeInterface,
private $cache;
/* The cassandra client */
/**
* @var ConnectionPool
*/
protected $cassandra;
/* Configuration array */
/**
* @var array
*/
protected $config;
/**
* Cassandra Storage! uses phpCassa
*
* @param \phpcassa\ConnectionPool $cassandra
* @param ConnectionPool|array $connection
* @param array $config
*
* @throws InvalidArgumentException
*/
public function __construct($connection = array(), array $config = array())
{
@ -61,7 +68,7 @@ class Cassandra implements AuthorizationCodeInterface,
$this->cassandra = $connection;
} else {
if (!is_array($connection)) {
throw new \InvalidArgumentException('First argument to OAuth2\Storage\Cassandra must be an instance of phpcassa\Connection\ConnectionPool or a configuration array');
throw new InvalidArgumentException('First argument to OAuth2\Storage\Cassandra must be an instance of phpcassa\Connection\ConnectionPool or a configuration array');
}
$connection = array_merge(array(
'keyspace' => 'oauth2',
@ -87,6 +94,10 @@ class Cassandra implements AuthorizationCodeInterface,
), $config);
}
/**
* @param $key
* @return bool|mixed
*/
protected function getValue($key)
{
if (isset($this->cache[$key])) {
@ -104,6 +115,12 @@ class Cassandra implements AuthorizationCodeInterface,
return json_decode($value, true);
}
/**
* @param $key
* @param $value
* @param int $expire
* @return bool
*/
protected function setValue($key, $value, $expire = 0)
{
$this->cache[$key] = $value;
@ -131,6 +148,10 @@ class Cassandra implements AuthorizationCodeInterface,
return true;
}
/**
* @param $key
* @return bool
*/
protected function expireValue($key)
{
unset($this->cache[$key]);
@ -151,12 +172,25 @@ class Cassandra implements AuthorizationCodeInterface,
return false;
}
/* AuthorizationCodeInterface */
/**
* @param string $code
* @return bool|mixed
*/
public function getAuthorizationCode($code)
{
return $this->getValue($this->config['code_key'] . $code);
}
/**
* @param string $authorization_code
* @param mixed $client_id
* @param mixed $user_id
* @param string $redirect_uri
* @param int $expires
* @param string $scope
* @param string $id_token
* @return bool
*/
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{
return $this->setValue(
@ -166,6 +200,10 @@ class Cassandra implements AuthorizationCodeInterface,
);
}
/**
* @param string $code
* @return bool
*/
public function expireAuthorizationCode($code)
{
$key = $this->config['code_key'] . $code;
@ -174,7 +212,11 @@ class Cassandra implements AuthorizationCodeInterface,
return $this->expireValue($key);
}
/* UserCredentialsInterface */
/**
* @param string $username
* @param string $password
* @return bool
*/
public function checkUserCredentials($username, $password)
{
if ($user = $this->getUser($username)) {
@ -184,7 +226,13 @@ class Cassandra implements AuthorizationCodeInterface,
return false;
}
// plaintext passwords are bad! Override this for your application
/**
* plaintext passwords are bad! Override this for your application
*
* @param array $user
* @param string $password
* @return bool
*/
protected function checkPassword($user, $password)
{
return $user['password'] == $this->hashPassword($password);
@ -196,11 +244,19 @@ class Cassandra implements AuthorizationCodeInterface,
return sha1($password);
}
/**
* @param string $username
* @return array|bool|false
*/
public function getUserDetails($username)
{
return $this->getUser($username);
}
/**
* @param string $username
* @return array|bool
*/
public function getUser($username)
{
if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) {
@ -213,6 +269,13 @@ class Cassandra implements AuthorizationCodeInterface,
), $userInfo);
}
/**
* @param string $username
* @param string $password
* @param string $first_name
* @param string $last_name
* @return bool
*/
public function setUser($username, $password, $first_name = null, $last_name = null)
{
$password = $this->hashPassword($password);
@ -223,7 +286,11 @@ class Cassandra implements AuthorizationCodeInterface,
);
}
/* ClientCredentialsInterface */
/**
* @param mixed $client_id
* @param string $client_secret
* @return bool
*/
public function checkClientCredentials($client_id, $client_secret = null)
{
if (!$client = $this->getClientDetails($client_id)) {
@ -234,6 +301,10 @@ class Cassandra implements AuthorizationCodeInterface,
&& $client['client_secret'] == $client_secret;
}
/**
* @param $client_id
* @return bool
*/
public function isPublicClient($client_id)
{
if (!$client = $this->getClientDetails($client_id)) {
@ -243,12 +314,24 @@ class Cassandra implements AuthorizationCodeInterface,
return empty($client['client_secret']);
}
/* ClientInterface */
/**
* @param $client_id
* @return array|bool|mixed
*/
public function getClientDetails($client_id)
{
return $this->getValue($this->config['client_key'] . $client_id);
}
/**
* @param $client_id
* @param null $client_secret
* @param null $redirect_uri
* @param null $grant_types
* @param null $scope
* @param null $user_id
* @return bool
*/
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
{
return $this->setValue(
@ -257,6 +340,11 @@ class Cassandra implements AuthorizationCodeInterface,
);
}
/**
* @param $client_id
* @param $grant_type
* @return bool
*/
public function checkRestrictedGrantType($client_id, $grant_type)
{
$details = $this->getClientDetails($client_id);
@ -270,12 +358,23 @@ class Cassandra implements AuthorizationCodeInterface,
return true;
}
/* RefreshTokenInterface */
/**
* @param $refresh_token
* @return bool|mixed
*/
public function getRefreshToken($refresh_token)
{
return $this->getValue($this->config['refresh_token_key'] . $refresh_token);
}
/**
* @param $refresh_token
* @param $client_id
* @param $user_id
* @param $expires
* @param null $scope
* @return bool
*/
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
{
return $this->setValue(
@ -285,17 +384,32 @@ class Cassandra implements AuthorizationCodeInterface,
);
}
/**
* @param $refresh_token
* @return bool
*/
public function unsetRefreshToken($refresh_token)
{
return $this->expireValue($this->config['refresh_token_key'] . $refresh_token);
}
/* AccessTokenInterface */
/**
* @param string $access_token
* @return array|bool|mixed|null
*/
public function getAccessToken($access_token)
{
return $this->getValue($this->config['access_token_key'].$access_token);
}
/**
* @param string $access_token
* @param mixed $client_id
* @param mixed $user_id
* @param int $expires
* @param null $scope
* @return bool
*/
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
{
return $this->setValue(
@ -305,12 +419,19 @@ class Cassandra implements AuthorizationCodeInterface,
);
}
/**
* @param $access_token
* @return bool
*/
public function unsetAccessToken($access_token)
{
return $this->expireValue($this->config['access_token_key'] . $access_token);
}
/* ScopeInterface */
/**
* @param $scope
* @return bool
*/
public function scopeExists($scope)
{
$scope = explode(' ', $scope);
@ -322,6 +443,10 @@ class Cassandra implements AuthorizationCodeInterface,
return (count(array_diff($scope, $supportedScope)) == 0);
}
/**
* @param null $client_id
* @return bool|mixed
*/
public function getDefaultScope($client_id = null)
{
if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) {
@ -331,6 +456,13 @@ class Cassandra implements AuthorizationCodeInterface,
return $result;
}
/**
* @param $scope
* @param null $client_id
* @param string $type
* @return bool
* @throws \InvalidArgumentException
*/
public function setScope($scope, $client_id = null, $type = 'supported')
{
if (!in_array($type, array('default', 'supported'))) {
@ -346,7 +478,11 @@ class Cassandra implements AuthorizationCodeInterface,
return $this->setValue($key, $scope);
}
/*JWTBearerInterface */
/**
* @param $client_id
* @param $subject
* @return bool|null
*/
public function getClientKey($client_id, $subject)
{
if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) {
@ -360,6 +496,12 @@ class Cassandra implements AuthorizationCodeInterface,
return null;
}
/**
* @param $client_id
* @param $key
* @param null $subject
* @return bool
*/
public function setClientKey($client_id, $key, $subject = null)
{
return $this->setValue($this->config['jwt_key'] . $client_id, array(
@ -368,7 +510,10 @@ class Cassandra implements AuthorizationCodeInterface,
));
}
/*ScopeInterface */
/**
* @param $client_id
* @return bool|null
*/
public function getClientScope($client_id)
{
if (!$clientDetails = $this->getClientDetails($client_id)) {
@ -382,19 +527,38 @@ class Cassandra implements AuthorizationCodeInterface,
return null;
}
/**
* @param $client_id
* @param $subject
* @param $audience
* @param $expiration
* @param $jti
* @throws \Exception
*/
public function getJti($client_id, $subject, $audience, $expiration, $jti)
{
//TODO: Needs cassandra implementation.
throw new \Exception('getJti() for the Cassandra driver is currently unimplemented.');
}
/**
* @param $client_id
* @param $subject
* @param $audience
* @param $expiration
* @param $jti
* @throws \Exception
*/
public function setJti($client_id, $subject, $audience, $expiration, $jti)
{
//TODO: Needs cassandra implementation.
throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.');
}
/* PublicKeyInterface */
/**
* @param string $client_id
* @return mixed
*/
public function getPublicKey($client_id = '')
{
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@ -407,6 +571,10 @@ class Cassandra implements AuthorizationCodeInterface,
}
}
/**
* @param string $client_id
* @return mixed
*/
public function getPrivateKey($client_id = '')
{
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@ -419,6 +587,10 @@ class Cassandra implements AuthorizationCodeInterface,
}
}
/**
* @param null $client_id
* @return mixed|string
*/
public function getEncryptionAlgorithm($client_id = null)
{
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@ -433,7 +605,11 @@ class Cassandra implements AuthorizationCodeInterface,
return 'RS256';
}
/* UserClaimsInterface */
/**
* @param mixed $user_id
* @param string $claims
* @return array|bool
*/
public function getUserClaims($user_id, $claims)
{
$userDetails = $this->getUserDetails($user_id);
@ -460,6 +636,11 @@ class Cassandra implements AuthorizationCodeInterface,
return $userClaims;
}
/**
* @param $claim
* @param $userDetails
* @return array
*/
protected function getUserClaim($claim, $userDetails)
{
$userClaims = array();
@ -476,5 +657,4 @@ class Cassandra implements AuthorizationCodeInterface,
return $userClaims;
}
}

View File

View File

@ -6,7 +6,6 @@ use OAuth2\Encryption\EncryptionInterface;
use OAuth2\Encryption\Jwt;
/**
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
class JwtAccessToken implements JwtAccessTokenInterface

View File

@ -4,6 +4,7 @@ namespace OAuth2\Storage;
use OAuth2\OpenID\Storage\UserClaimsInterface;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
use InvalidArgumentException;
/**
* Simple PDO storage for all storage types
@ -29,9 +30,22 @@ class Pdo implements
UserClaimsInterface,
OpenIDAuthorizationCodeInterface
{
/**
* @var \PDO
*/
protected $db;
/**
* @var array
*/
protected $config;
/**
* @param mixed $connection
* @param array $config
*
* @throws InvalidArgumentException
*/
public function __construct($connection, $config = array())
{
if (!$connection instanceof \PDO) {
@ -70,7 +84,11 @@ class Pdo implements
), $config);
}
/* OAuth2\Storage\ClientCredentialsInterface */
/**
* @param string $client_id
* @param null|string $client_secret
* @return bool
*/
public function checkClientCredentials($client_id, $client_secret = null)
{
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
@ -81,6 +99,10 @@ class Pdo implements
return $result && $result['client_secret'] == $client_secret;
}
/**
* @param string $client_id
* @return bool
*/
public function isPublicClient($client_id)
{
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
@ -93,7 +115,10 @@ class Pdo implements
return empty($result['client_secret']);
}
/* OAuth2\Storage\ClientInterface */
/**
* @param string $client_id
* @return array|mixed
*/
public function getClientDetails($client_id)
{
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
@ -102,6 +127,15 @@ class Pdo implements
return $stmt->fetch(\PDO::FETCH_ASSOC);
}
/**
* @param string $client_id
* @param null|string $client_secret
* @param null|string $redirect_uri
* @param null|array $grant_types
* @param null|string $scope
* @param null|string $user_id
* @return bool
*/
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
{
// if it exists, update it.
@ -114,6 +148,11 @@ class Pdo implements
return $stmt->execute(compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id'));
}
/**
* @param $client_id
* @param $grant_type
* @return bool
*/
public function checkRestrictedGrantType($client_id, $grant_type)
{
$details = $this->getClientDetails($client_id);
@ -127,7 +166,10 @@ class Pdo implements
return true;
}
/* OAuth2\Storage\AccessTokenInterface */
/**
* @param string $access_token
* @return array|bool|mixed|null
*/
public function getAccessToken($access_token)
{
$stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = :access_token', $this->config['access_token_table']));
@ -141,6 +183,14 @@ class Pdo implements
return $token;
}
/**
* @param string $access_token
* @param mixed $client_id
* @param mixed $user_id
* @param int $expires
* @param string $scope
* @return bool
*/
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
{
// convert expires to datestring
@ -156,6 +206,10 @@ class Pdo implements
return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope'));
}
/**
* @param $access_token
* @return bool
*/
public function unsetAccessToken($access_token)
{
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE access_token = :access_token', $this->config['access_token_table']));
@ -166,6 +220,10 @@ class Pdo implements
}
/* OAuth2\Storage\AuthorizationCodeInterface */
/**
* @param string $code
* @return mixed
*/
public function getAuthorizationCode($code)
{
$stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = :code', $this->config['code_table']));
@ -179,6 +237,16 @@ class Pdo implements
return $code;
}
/**
* @param string $code
* @param mixed $client_id
* @param mixed $user_id
* @param string $redirect_uri
* @param int $expires
* @param string $scope
* @param string $id_token
* @return bool|mixed
*/
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{
if (func_num_args() > 6) {
@ -199,6 +267,16 @@ class Pdo implements
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope'));
}
/**
* @param string $code
* @param mixed $client_id
* @param mixed $user_id
* @param string $redirect_uri
* @param string $expires
* @param string $scope
* @param string $id_token
* @return bool
*/
private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{
// convert expires to datestring
@ -214,6 +292,10 @@ class Pdo implements
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'));
}
/**
* @param string $code
* @return bool
*/
public function expireAuthorizationCode($code)
{
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE authorization_code = :code', $this->config['code_table']));
@ -221,7 +303,11 @@ class Pdo implements
return $stmt->execute(compact('code'));
}
/* OAuth2\Storage\UserCredentialsInterface */
/**
* @param string $username
* @param string $password
* @return bool
*/
public function checkUserCredentials($username, $password)
{
if ($user = $this->getUser($username)) {
@ -231,12 +317,20 @@ class Pdo implements
return false;
}
/**
* @param string $username
* @return array|bool
*/
public function getUserDetails($username)
{
return $this->getUser($username);
}
/* UserClaimsInterface */
/**
* @param mixed $user_id
* @param string $claims
* @return array|bool
*/
public function getUserClaims($user_id, $claims)
{
if (!$userDetails = $this->getUserDetails($user_id)) {
@ -262,6 +356,11 @@ class Pdo implements
return $userClaims;
}
/**
* @param string $claim
* @param array $userDetails
* @return array
*/
protected function getUserClaim($claim, $userDetails)
{
$userClaims = array();
@ -275,7 +374,10 @@ class Pdo implements
return $userClaims;
}
/* OAuth2\Storage\RefreshTokenInterface */
/**
* @param string $refresh_token
* @return bool|mixed
*/
public function getRefreshToken($refresh_token)
{
$stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table']));
@ -289,6 +391,14 @@ class Pdo implements
return $token;
}
/**
* @param string $refresh_token
* @param mixed $client_id
* @param mixed $user_id
* @param string $expires
* @param string $scope
* @return bool
*/
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
{
// convert expires to datestring
@ -299,6 +409,10 @@ class Pdo implements
return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'));
}
/**
* @param string $refresh_token
* @return bool
*/
public function unsetRefreshToken($refresh_token)
{
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table']));
@ -308,7 +422,13 @@ class Pdo implements
return $stmt->rowCount() > 0;
}
// plaintext passwords are bad! Override this for your application
/**
* plaintext passwords are bad! Override this for your application
*
* @param array $user
* @param string $password
* @return bool
*/
protected function checkPassword($user, $password)
{
return $user['password'] == $this->hashPassword($password);
@ -320,6 +440,10 @@ class Pdo implements
return sha1($password);
}
/**
* @param string $username
* @return array|bool
*/
public function getUser($username)
{
$stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table']));
@ -335,6 +459,15 @@ class Pdo implements
), $userInfo);
}
/**
* plaintext passwords are bad! Override this for your application
*
* @param string $username
* @param string $password
* @param string $firstName
* @param string $lastName
* @return bool
*/
public function setUser($username, $password, $firstName = null, $lastName = null)
{
// do not store in plaintext
@ -350,7 +483,10 @@ class Pdo implements
return $stmt->execute(compact('username', 'password', 'firstName', 'lastName'));
}
/* ScopeInterface */
/**
* @param string $scope
* @return bool
*/
public function scopeExists($scope)
{
$scope = explode(' ', $scope);
@ -365,6 +501,10 @@ class Pdo implements
return false;
}
/**
* @param mixed $client_id
* @return null|string
*/
public function getDefaultScope($client_id = null)
{
$stmt = $this->db->prepare(sprintf('SELECT scope FROM %s WHERE is_default=:is_default', $this->config['scope_table']));
@ -381,7 +521,11 @@ class Pdo implements
return null;
}
/* JWTBearerInterface */
/**
* @param mixed $client_id
* @param $subject
* @return string
*/
public function getClientKey($client_id, $subject)
{
$stmt = $this->db->prepare($sql = sprintf('SELECT public_key from %s where client_id=:client_id AND subject=:subject', $this->config['jwt_table']));
@ -391,6 +535,10 @@ class Pdo implements
return $stmt->fetchColumn();
}
/**
* @param mixed $client_id
* @return bool|null
*/
public function getClientScope($client_id)
{
if (!$clientDetails = $this->getClientDetails($client_id)) {
@ -404,6 +552,14 @@ class Pdo implements
return null;
}
/**
* @param mixed $client_id
* @param $subject
* @param $audience
* @param $expires
* @param $jti
* @return array|null
*/
public function getJti($client_id, $subject, $audience, $expires, $jti)
{
$stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE issuer=:client_id AND subject=:subject AND audience=:audience AND expires=:expires AND jti=:jti', $this->config['jti_table']));
@ -423,6 +579,14 @@ class Pdo implements
return null;
}
/**
* @param mixed $client_id
* @param $subject
* @param $audience
* @param $expires
* @param $jti
* @return bool
*/
public function setJti($client_id, $subject, $audience, $expires, $jti)
{
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (issuer, subject, audience, expires, jti) VALUES (:client_id, :subject, :audience, :expires, :jti)', $this->config['jti_table']));
@ -430,7 +594,10 @@ class Pdo implements
return $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti'));
}
/* PublicKeyInterface */
/**
* @param mixed $client_id
* @return mixed
*/
public function getPublicKey($client_id = null)
{
$stmt = $this->db->prepare($sql = sprintf('SELECT public_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
@ -441,6 +608,10 @@ class Pdo implements
}
}
/**
* @param mixed $client_id
* @return mixed
*/
public function getPrivateKey($client_id = null)
{
$stmt = $this->db->prepare($sql = sprintf('SELECT private_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
@ -451,6 +622,10 @@ class Pdo implements
}
}
/**
* @param mixed $client_id
* @return string
*/
public function getEncryptionAlgorithm($client_id = null)
{
$stmt = $this->db->prepare($sql = sprintf('SELECT encryption_algorithm FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
@ -467,6 +642,9 @@ class Pdo implements
* DDL to create OAuth2 database and tables for PDO storage
*
* @see https://github.com/dsquier/oauth2-server-php-mysql
*
* @param string $dbName
* @return string
*/
public function getBuildSql($dbName = 'oauth2_server_php')
{
@ -535,7 +713,7 @@ class Pdo implements
CREATE TABLE {$this->config['jti_table']} (
issuer VARCHAR(80) NOT NULL,
subject VARCHAR(80),
audience VARCHAR(80),
audiance VARCHAR(80),
expires TIMESTAMP NOT NULL,
jti VARCHAR(2000) NOT NULL
);
@ -546,7 +724,7 @@ class Pdo implements
private_key VARCHAR(2000),
encryption_algorithm VARCHAR(100) DEFAULT 'RS256'
)
";
";
return $sql;
}

View File

@ -10,7 +10,21 @@ namespace OAuth2\Storage;
*/
interface PublicKeyInterface
{
/**
* @param mixed $client_id
* @return mixed
*/
public function getPublicKey($client_id = null);
/**
* @param mixed $client_id
* @return mixed
*/
public function getPrivateKey($client_id = null);
/**
* @param mixed $client_id
* @return mixed
*/
public function getEncryptionAlgorithm($client_id = null);
}

View File

@ -37,8 +37,8 @@ interface UserCredentialsInterface
public function checkUserCredentials($username, $password);
/**
* @return
* ARRAY the associated "user_id" and optional "scope" values
* @param string $username - username to get details for
* @return array|false - the associated "user_id" and optional "scope" values
* This function MUST return FALSE if the requested user does not exist or is
* invalid. "scope" is a space-separated list of restricted scopes.
* @code

View File

@ -2,7 +2,9 @@
namespace OAuth2;
class AutoloadTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class AutoloadTest extends TestCase
{
public function testClassesExist()
{

View File

@ -10,8 +10,9 @@ use OAuth2\GrantType\AuthorizationCode;
use OAuth2\Request;
use OAuth2\Response;
use OAuth2\Request\TestRequest;
use PHPUnit\Framework\TestCase;
class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase
class AuthorizeControllerTest extends TestCase
{
public function testNoClientIdResponse()
{

View File

@ -7,8 +7,9 @@ use OAuth2\Server;
use OAuth2\GrantType\AuthorizationCode;
use OAuth2\Request;
use OAuth2\Response;
use PHPUnit\Framework\TestCase;
class ResourceControllerTest extends \PHPUnit_Framework_TestCase
class ResourceControllerTest extends TestCase
{
public function testNoAccessToken()
{

View File

@ -10,8 +10,9 @@ use OAuth2\GrantType\UserCredentials;
use OAuth2\Scope;
use OAuth2\Request\TestRequest;
use OAuth2\Response;
use PHPUnit\Framework\TestCase;
class TokenControllerTest extends \PHPUnit_Framework_TestCase
class TokenControllerTest extends TestCase
{
public function testNoGrantType()
{
@ -271,6 +272,48 @@ class TokenControllerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($response->getParameter('error_description'), 'The request method must be POST when revoking an access token');
}
public function testCanUseCrossOriginRequestForRevoke()
{
$server = $this->getTestServer();
$request = new TestRequest();
$request->setMethod('OPTIONS');
$server->handleRevokeRequest($request, $response = new Response());
$this->assertTrue($response instanceof Response);
$this->assertEquals(200, $response->getStatusCode(), var_export($response, 1));
$this->assertEquals($response->getHttpHeader('Allow'), 'POST, OPTIONS');
}
public function testInvalidRequestMethodForAccessToken()
{
$server = $this->getTestServer();
$request = new TestRequest();
$request->setQuery(array(
'token_type_hint' => 'access_token'
));
$server->handleTokenRequest($request, $response = new Response());
$this->assertTrue($response instanceof Response);
$this->assertEquals(405, $response->getStatusCode(), var_export($response, 1));
$this->assertEquals($response->getParameter('error'), 'invalid_request');
$this->assertEquals($response->getParameter('error_description'), 'The request method must be POST when requesting an access token');
}
public function testCanUseCrossOriginRequestForAccessToken()
{
$server = $this->getTestServer();
$request = new TestRequest();
$request->setMethod('OPTIONS');
$server->handleTokenRequest($request, $response = new Response());
$this->assertTrue($response instanceof Response);
$this->assertEquals(200, $response->getStatusCode(), var_export($response, 1));
$this->assertEquals($response->getHttpHeader('Allow'), 'POST, OPTIONS');
}
public function testCreateController()
{
$storage = Bootstrap::getInstance()->getMemoryStorage();

Some files were not shown because too many files have changed in this diff Show More