openrat-cms

# OpenRat Content Management System
git clone http://git.code.weiherhei.de/openrat-cms.git
Log | Files | Refs

commit 722259b87d7e4dbf2660e87e82f845cd323f9e5e
parent f2a2360ffeccccf0496f6564825298bebb28989e
Author: Jan Dankert <develop@jandankert.de>
Date:   Sat, 22 Feb 2020 23:58:02 +0100

Refactoring: Namespacing for module 'util'.

Diffstat:
modules/cms-api/API.class.php | 10+++++-----
modules/cms-core/Dispatcher.class.php | 10+++++-----
modules/cms-core/action/Action.class.php | 8++++----
modules/cms-core/action/ConfigurationAction.class.php | 10+++++-----
modules/cms-core/action/ElementAction.class.php | 16++++++++--------
modules/cms-core/action/FileAction.class.php | 14+++++++-------
modules/cms-core/action/FolderAction.class.php | 34+++++++++++++++++-----------------
modules/cms-core/action/GroupAction.class.php | 4++--
modules/cms-core/action/ImageAction.class.php | 6+++---
modules/cms-core/action/LanguageAction.class.php | 4++--
modules/cms-core/action/LanguagelistAction.class.php | 4++--
modules/cms-core/action/LinkAction.class.php | 4++--
modules/cms-core/action/LoginAction.class.php | 36++++++++++++++++++------------------
modules/cms-core/action/ModelAction.class.php | 4++--
modules/cms-core/action/ModellistAction.class.php | 4++--
modules/cms-core/action/ObjectAction.class.php | 18+++++++++---------
modules/cms-core/action/PageAction.class.php | 8++++----
modules/cms-core/action/PageelementAction.class.php | 16++++++++--------
modules/cms-core/action/ProfileAction.class.php | 6+++---
modules/cms-core/action/ProjectlistAction.class.php | 6+++---
modules/cms-core/action/RequestParams.class.php | 2+-
modules/cms-core/action/SearchAction.class.php | 4++--
modules/cms-core/action/StartAction.class.php | 24++++++++++++------------
modules/cms-core/action/TemplateAction.class.php | 10+++++-----
modules/cms-core/action/TemplatelistAction.class.php | 4++--
modules/cms-core/action/TextAction.class.php | 2+-
modules/cms-core/action/TreeAction.class.php | 4++--
modules/cms-core/action/UrlAction.class.php | 4++--
modules/cms-core/action/UserAction.class.php | 10+++++-----
modules/cms-core/auth/HttpAuth.class.php | 2++
modules/cms-core/auth/IdentAuth.class.php | 2++
modules/cms-core/auth/LdapAuth.class.php | 2++
modules/cms-core/auth/LdapUserDNAuth.class.php | 2++
modules/cms-core/auth/OpenIdAuth.class.php | 12+++++++-----
modules/cms-core/functions/common.inc.php | 2++
modules/cms-core/init.php | 2++
modules/cms-core/model/BaseObject.class.php | 16++++++++--------
modules/cms-core/model/Element.class.php | 4++--
modules/cms-core/model/File.class.php | 12++++++------
modules/cms-core/model/Language.class.php | 2+-
modules/cms-core/model/Page.class.php | 6+++---
modules/cms-core/model/Pageelement.class.php | 2+-
modules/cms-core/model/Project.class.php | 4++--
modules/cms-core/model/User.class.php | 4++--
modules/cms-core/model/Value.class.php | 36++++++++++++++++++------------------
modules/cms-macros/MacroRunner.class.php | 4+++-
modules/cms-macros/macro/Album.class.php | 1+
modules/cms-macros/macro/Atom.class.php | 1+
modules/cms-macros/macro/BlockMenu.class.php | 1+
modules/cms-macros/macro/BreadCrumb.class.php | 1+
modules/cms-macros/macro/CSVTable.class.php | 1+
modules/cms-macros/macro/ClassicMenu.class.php | 1+
modules/cms-macros/macro/CommonMenu.class.php | 1+
modules/cms-macros/macro/DoiMenu.class.php | 1+
modules/cms-macros/macro/GoogleMaps.class.php | 2+-
modules/cms-macros/macro/LanguageLinksForPage.class.php | 1+
modules/cms-macros/macro/LastChanges.class.php | 2++
modules/cms-macros/macro/LastPage.class.php | 1+
modules/cms-macros/macro/Link.class.php | 1+
modules/cms-macros/macro/LinkList.class.php | 1+
modules/cms-macros/macro/ListMenu.class.php | 1+
modules/cms-macros/macro/MainMenu.class.php | 1+
modules/cms-macros/macro/NextPage.class.php | 1+
modules/cms-macros/macro/OpenStreetMap.class.php | 2+-
modules/cms-macros/macro/PagesNavigation.class.php | 1+
modules/cms-macros/macro/RSSCreate.class.php | 1+
modules/cms-macros/macro/RSSReader.class.php | 2+-
modules/cms-macros/macro/SearchIndex.class.php | 1+
modules/cms-macros/macro/Sitemap.class.php | 1+
modules/cms-macros/macro/TableFromFile.class.php | 1+
modules/cms-macros/macro/TagCloud.class.php | 1+
modules/cms-macros/macro/TagList.class.php | 1+
modules/cms-macros/macro/TeaserList.class.php | 2++
modules/cms-macros/macro/Youtube.class.php | 2+-
modules/cms-publish/FolderPublisher.class.php | 3+++
modules/cms-publish/Ftp.class.php | 415++++++++++++++++++++++++++++++++++++++++---------------------------------------
modules/cms-publish/PublishPreview.class.php | 10+++++-----
modules/cms-publish/PublishPublic.class.php | 6+++---
modules/cms-publish/filter/JavascriptMinifierFilter.class.php | 2+-
modules/cms-publish/filter/LessFilter.class.php | 2+-
modules/cms-ui/UI.class.php | 10+++++-----
modules/cms-ui/action/IndexAction.class.php | 10+++++-----
modules/cms-ui/action/TitleAction.class.php | 4++--
modules/cms-ui/themes/default/layout/index.php | 2+-
modules/configuration/ConfigurationLoader.class.php | 1+
modules/database/DbVersion.class.php | 2+-
modules/language/Language.class.php | 2+-
modules/template_engine/TemplateCompiler.php | 2+-
modules/template_engine/components/XSDGenerator.php | 2++
modules/util/Api.class.php | 38++++++++++++++++++++------------------
modules/util/ArchiveTar.class.php | 791+++++++++++++++++++++++++++++++++++++++----------------------------------------
modules/util/ArchiveUnzip.class.php | 896++++++++++++++++++++++++++++++++++++++++---------------------------------------
modules/util/ArchiveZip.class.php | 176++++++++++++++++++++++++++++++++++++++++----------------------------------------
modules/util/ArrayUtils.class.php | 86+++++++++++++++++++++++++++++++++++++------------------------------------------
modules/util/Browser.class.php | 100++++++++++++++++++++++++++++++++++++++++---------------------------------------
modules/util/ClassUtils.class.php | 20+++++++++++---------
modules/util/Code.class.php | 31++++++++++++++++++-------------
modules/util/Dynamic.class.php | 7+++++--
modules/util/FileUtils.class.php | 127+++++++++++++++++++++++++++++++++++++++----------------------------------------
modules/util/GlobalFunctions.class.php | 27++++++++++++---------------
modules/util/Html.class.php | 105+++++++++++++++++++++++++++++++++++++------------------------------------------
modules/util/Http.class.php | 400+++++++++++++++++++++++++++++++++++--------------------------------------------
modules/util/JSqueeze.class.php | 2025++++++++++++++++++++++++++++++++++++++++---------------------------------------
modules/util/Ldap.class.php | 359+++++++++++++++++++++++++++++++++++++++----------------------------------------
modules/util/Line.class.php | 153-------------------------------------------------------------------------------
modules/util/Macro.class.php | 71+++++++++++++++++++++++++++++++++++++----------------------------------
modules/util/Mail.class.php | 478++++++++++++++++++++++++++++++++++++-------------------------------------------
modules/util/Mustache.class.php | 2+-
modules/util/Parsedown.class.php | 3741++++++++++++++++++++++++++++++++++++++-----------------------------------------
modules/util/Session.class.php | 87+++++++++++++++++++++++++++++++++++++++----------------------------------------
modules/util/Text.class.php | 351+++++++++++++++++++++++++++++++++++--------------------------------------------
modules/util/Transformer.class.php | 62++++++++++++++++++++++++++++++--------------------------------
modules/util/Tree.class.php | 1188++++++++++++++++++++++++++++++++++++++++----------------------------------------
modules/util/TreeElement.class.php | 149++++++++++++++++++++++++++++++++++++++++---------------------------------------
modules/util/UIUtils.class.php | 2+-
modules/util/Upload.class.php | 103+++++++++++++++++++++++++++++++++++++++++--------------------------------------
modules/util/XML.class.php | 98++++++++++++++++++++++++++++++++++++-------------------------------------------
modules/util/YAML.class.php | 8+++++---
modules/util/cache/FileCache.class.php | 4++--
modules/util/exception/OpenRatException.class.php | 13+++++++++----
modules/util/exception/SecurityException.class.php | 3+++
modules/util/exception/ValidationException.class.php | 15++++++++++-----
modules/util/require.php | 38--------------------------------------
modules/wikiparser/parser/WikiParser.class.php | 4++--
modules/wikiparser/renderer/DocBookRenderer.class.php | 2+-
modules/wikiparser/renderer/HtmlRenderer.class.php | 2+-
modules/wikiparser/renderer/LatexRenderer.class.php | 2+-
modules/wikiparser/renderer/XhtmlRenderer.class.php | 2+-
modules/wikiparser/util/Line.class.php | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
129 files changed, 6266 insertions(+), 6539 deletions(-)

diff --git a/modules/cms-api/API.class.php b/modules/cms-api/API.class.php @@ -6,13 +6,13 @@ use BadMethodCallException; use cms\action\RequestParams; use cms\Dispatcher; use Exception; -use Http; +use util\Http; use JSON; use Logger; use ObjectNotFoundException; -use OpenRatException; -use SecurityException; -use XML; +use util\exception\OpenRatException; +use util\exception\SecurityException; +use util\XML; define('CMS_API_REQ_PARAM_SUBACTION', 'subaction'); define('CMS_API_REQ_PARAM_ACTION', 'action'); @@ -125,7 +125,7 @@ class API case CMS_API_OUTPUT_YAML: header('Content-Type: application/yaml; charset=UTF-8'); - $output = \YAML::dump($data); + $output = \util\YAML::dump($data); break; } diff --git a/modules/cms-core/Dispatcher.class.php b/modules/cms-core/Dispatcher.class.php @@ -11,12 +11,12 @@ use cms\action\RequestParams; use ConfigurationLoader; use database\Database; use DbUpdate; -use Http; +use util\Http; use Logger; use LogicException; -use OpenRatException; -use SecurityException; -use Session; +use util\exception\OpenRatException; +use util\exception\SecurityException; +use util\Session; /** @@ -320,7 +320,7 @@ class Dispatcher $method->invoke($do); // <== Executing the Action } - catch (\ValidationException $ve) + catch (\util\exception\ValidationException $ve) { $do->addValidationError( $ve->fieldName ); } diff --git a/modules/cms-core/action/Action.class.php b/modules/cms-core/action/Action.class.php @@ -18,11 +18,11 @@ namespace { namespace cms\action { use cms\model\User; - use \Html; - use \Session; + use util\Html; + use util\Session; use \Logger; - use \Http; - use \Text; + use util\Http; + use util\Text; /** diff --git a/modules/cms-core/action/ConfigurationAction.class.php b/modules/cms-core/action/ConfigurationAction.class.php @@ -18,7 +18,7 @@ namespace cms\action; // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -use Session; +use util\Session; /** * Action-Klasse fuer die Bearbeitung eines Template-Elementes. * @@ -69,9 +69,9 @@ class ConfigurationAction extends BaseAction $pad = str_repeat("\xC2\xA0",10); // Hard spaces - $flatDefaultConfig = \ArrayUtils::dryFlattenArray( $conf_default , $pad ); - $flatCMSConfig = \ArrayUtils::dryFlattenArray( Session::getConfig(), $pad ); - $flatConfig = \ArrayUtils::dryFlattenArray( $conf_cms , $pad ); + $flatDefaultConfig = \util\ArrayUtils::dryFlattenArray( $conf_default , $pad ); + $flatCMSConfig = \util\ArrayUtils::dryFlattenArray( Session::getConfig(), $pad ); + $flatConfig = \util\ArrayUtils::dryFlattenArray( $conf_cms , $pad ); $config = array(); foreach( $flatConfig as $key=>$val ) @@ -97,7 +97,7 @@ class ConfigurationAction extends BaseAction } }); - $this->setTemplateVar('source',\YAML::dump($conf,4,0,true)); + $this->setTemplateVar('source', \util\YAML::dump($conf,4,0,true)); } diff --git a/modules/cms-core/action/ElementAction.class.php b/modules/cms-core/action/ElementAction.class.php @@ -10,7 +10,7 @@ use cms\model\Folder; use cms\model\BaseObject; use ReflectionClass; use ReflectionProperty; -use Text; +use util\Text; @@ -43,7 +43,7 @@ class ElementAction extends BaseAction public function init() { if ( $this->getRequestId() == 0 ) - throw new \ValidationException('no element-id available'); + throw new \util\exception\ValidationException('no element-id available'); $this->element = new Element( $this->getRequestId() ); $this->element->load(); @@ -68,7 +68,7 @@ class ElementAction extends BaseAction public function removePost() { if ( !$this->hasRequestVar('confirm') ) - throw new \ValidationException('confirm'); + throw new \util\exception\ValidationException('confirm'); $type = $this->getRequestVar('type','abc'); @@ -265,7 +265,7 @@ class ElementAction extends BaseAction case Element::ELEMENT_TYPE_DYNAMIC: $files = Array(); - $macroFiles = \FileUtils::readDir(__DIR__.'/../../cms-macros/macro'); + $macroFiles = \util\FileUtils::readDir(__DIR__.'/../../cms-macros/macro'); foreach( $macroFiles as $macroFile ) { $file = substr($macroFile,0,strlen($macroFile)-10); @@ -350,8 +350,8 @@ class ElementAction extends BaseAction if ( $this->element->typeid != Element::ELEMENT_TYPE_LONGTEXT ) unset( $formats[ Element::ELEMENT_FORMAT_HTML ] ); - foreach( $formats as $t=>$v ) - $formats[$t] = array('lang'=>'EL_PROP_FORMAT_'.$v); + //foreach( $formats as $t=>$v ) + // $formats[$t] = array('lang'=>'EL_PROP_FORMAT_'.$v); $this->setTemplateVar('formatlist', $formats); break; @@ -455,7 +455,7 @@ class ElementAction extends BaseAction $this->setTemplateVar('dynamic_class_description',$description ); $this->setTemplateVar('dynamic_class_parameters' ,$paramList ); - $this->setTemplateVar('parameters' ,\YAML::dump($parameters) ); + $this->setTemplateVar('parameters' , \util\YAML::dump($parameters) ); break; @@ -610,7 +610,7 @@ class ElementAction extends BaseAction { if ( !$this->userIsAdmin() && $this->getRequestVar('type') == 'code' ) // Code-Elemente fuer Nicht-Administratoren nicht benutzbar - throw new \ValidationException('type'); + throw new \util\exception\ValidationException('type'); $this->element->typeid = $this->getRequestId('typeid'); diff --git a/modules/cms-core/action/FileAction.class.php b/modules/cms-core/action/FileAction.class.php @@ -8,10 +8,10 @@ use cms\model\File; use cms\publish\PublishPreview; use cms\publish\PublishPublic; -use Http; -use \Html; -use Upload; -use ValidationException; +use util\Http; +use util\Html; +use util\Upload; +use util\exception\ValidationException; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de @@ -364,7 +364,7 @@ class FileAction extends ObjectAction break; default: - throw new \OpenRatException( 'cannot uncompress file with extension: '.$this->file->extension ); + throw new \util\exception\OpenRatException( 'cannot uncompress file with extension: '.$this->file->extension ); } $this->addNotice('file',$this->file->name,'DONE',OR_NOTICE_OK); @@ -443,7 +443,7 @@ class FileAction extends ObjectAction break; default: - throw new \OpenRatException( 'cannot extract file with extension: '.$this->file->extension ); + throw new \util\exception\OpenRatException( 'cannot extract file with extension: '.$this->file->extension ); } $this->callSubAction('edit'); } @@ -515,7 +515,7 @@ class FileAction extends ObjectAction break; default: - throw new \OpenRatException( 'unknown compress type: '.$format ); + throw new \util\exception\OpenRatException( 'unknown compress type: '.$format ); } $this->addNotice('file',$this->file->name,'DONE',OR_NOTICE_OK); diff --git a/modules/cms-core/action/FolderAction.class.php b/modules/cms-core/action/FolderAction.class.php @@ -2,7 +2,7 @@ namespace cms\action; -use ArchiveTar; +use util\ArchiveTar; use cms\model\Acl; use cms\model\Image; use cms\model\Language; @@ -17,11 +17,11 @@ use cms\model\Link; use cms\model\Text; use cms\model\Url; use cms\publish\PublishPublic; -use Http; +use util\Http; use Publish; -use Session; -use \Html; -use Upload; +use util\Session; +use util\Html; +use util\Upload; /** * Action-Klasse zum Bearbeiten eines Ordners. @@ -1006,9 +1006,9 @@ class FolderAction extends ObjectAction if ( $o->hasRight(Acl::ACL_READ) ) { - $list[$id]['name'] = \Text::maxLength($o->name, 30); - $list[$id]['filename'] = \Text::maxLength($o->filename, 20); - $list[$id]['desc'] = \Text::maxLength($o->desc, 30); + $list[$id]['name'] = \util\Text::maxLength($o->name, 30); + $list[$id]['filename'] = \util\Text::maxLength($o->filename, 20); + $list[$id]['desc'] = \util\Text::maxLength($o->desc, 30); if ( $list[$id]['desc'] == '' ) $list[$id]['desc'] = lang('NO_DESCRIPTION_AVAILABLE'); $list[$id]['desc'] = $list[$id]['desc'].' - '.lang('IMAGE').' '.$id; @@ -1067,9 +1067,9 @@ class FolderAction extends ObjectAction if ( $o->hasRight(Acl::ACL_READ) ) { - $list[$id]['name'] = \Text::maxLength($o->name, 30); - $list[$id]['filename'] = \Text::maxLength($o->filename, 20); - $list[$id]['desc'] = \Text::maxLength($o->desc, 30); + $list[$id]['name'] = \util\Text::maxLength($o->name, 30); + $list[$id]['filename'] = \util\Text::maxLength($o->filename, 20); + $list[$id]['desc'] = \util\Text::maxLength($o->desc, 30); if ( $list[$id]['desc'] == '' ) $list[$id]['desc'] = lang('NO_DESCRIPTION_AVAILABLE'); $list[$id]['desc'] = $list[$id]['desc'].' - '.lang('IMAGE').' '.$id; @@ -1221,9 +1221,9 @@ class FolderAction extends ObjectAction if ( $o->hasRight(Acl::ACL_READ) ) { $list[$id]['id' ] = $id; - $list[$id]['name'] = \Text::maxLength( $o->name ,30); - $list[$id]['filename'] = \Text::maxLength( $o->filename ,20); - $list[$id]['desc'] = \Text::maxLength( $o->desc ,30); + $list[$id]['name'] = \util\Text::maxLength( $o->name ,30); + $list[$id]['filename'] = \util\Text::maxLength( $o->filename ,20); + $list[$id]['desc'] = \util\Text::maxLength( $o->desc ,30); if ( $list[$id]['desc'] == '' ) $list[$id]['desc'] = lang('NO_DESCRIPTION_AVAILABLE'); $list[$id]['desc'] = 'ID '.$id.' - '.$list[$id]['desc']; @@ -1340,7 +1340,7 @@ class FolderAction extends ObjectAction public function pubPost() { if ( !$this->folder->hasRight( Acl::ACL_PUBLISH ) ) - throw new \SecurityException('no rights for publish'); + throw new \util\exception\SecurityException('no rights for publish'); $subdirs = ( $this->hasRequestVar('subdirs') ); $pages = ( $this->hasRequestVar('pages' ) ); @@ -1451,13 +1451,13 @@ class FolderAction extends ObjectAction public function removePost() { if ( !$this->hasRequestVar('delete') ) - throw new \ValidationException("delete"); + throw new \util\exception\ValidationException("delete"); if ( $this->hasRequestVar( 'withChildren')) $this->folder->deleteAll(); // Delete with children else if ( $this->folder->hasChildren() ) - throw new \ValidationException("withChildren"); + throw new \util\exception\ValidationException("withChildren"); else $this->folder->delete(); // Only delete current folder. diff --git a/modules/cms-core/action/GroupAction.class.php b/modules/cms-core/action/GroupAction.class.php @@ -9,7 +9,7 @@ use cms\model\Group; use cms\model\BaseObject; use cms\model\Language; -use \Html; +use util\Html; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de // @@ -86,7 +86,7 @@ class GroupAction extends BaseAction public function propPost() { if ( ! $this->getRequestVar('name') ) - throw new \ValidationException('name'); + throw new \util\exception\ValidationException('name'); $this->group->name = $this->getRequestVar('name'); $this->group->save(); diff --git a/modules/cms-core/action/ImageAction.class.php b/modules/cms-core/action/ImageAction.class.php @@ -7,9 +7,9 @@ use cms\model\Image; use cms\model\BaseObject; use cms\model\File; -use Http; -use \Html; -use Upload; +use util\Http; +use util\Html; +use util\Upload; /** diff --git a/modules/cms-core/action/LanguageAction.class.php b/modules/cms-core/action/LanguageAction.class.php @@ -4,8 +4,8 @@ namespace cms\action; use cms\model\Language; use cms\model\Project; -use Session; -use \Html; +use util\Session; +use util\Html; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de // diff --git a/modules/cms-core/action/LanguagelistAction.class.php b/modules/cms-core/action/LanguagelistAction.class.php @@ -6,8 +6,8 @@ use cms\model\Language; use cms\model\Project; -use Session; -use \Html; +use util\Session; +use util\Html; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de diff --git a/modules/cms-core/action/LinkAction.class.php b/modules/cms-core/action/LinkAction.class.php @@ -7,8 +7,8 @@ use cms\model\Folder; use cms\model\Link; -use Html; -use Session; +use util\Html; +use util\Session; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de diff --git a/modules/cms-core/action/LoginAction.class.php b/modules/cms-core/action/LoginAction.class.php @@ -18,16 +18,16 @@ use \database\Database; use \DB; use \DbUpdate; use \Exception; -use \Http; +use util\Http; use \InternalAuth; use \Logger; use \ObjectNotFoundException; -use \OpenRatException; +use util\exception\OpenRatException; use \security\Password; -use \Session; -use \Html; -use \Mail; -use \Text; +use util\Session; +use util\Html; +use util\Mail; +use util\Text; // OpenRat Content Management System @@ -191,7 +191,7 @@ class LoginAction extends BaseAction $authid = $this->getRequestVar( $sso['auth_param_name']); if ( empty( $authid) ) - throw new \SecurityException( 'no authorization data (no auth-id)'); + throw new \util\exception\SecurityException( 'no authorization data (no auth-id)'); if ( $sso['auth_param_serialized'] ) $authid = unserialize( $authid ); @@ -239,19 +239,19 @@ class LoginAction extends BaseAction $html = implode('',$inhalt); if ( !preg_match($sso['expect_regexp'],$html) ) - throw new \SecurityException('auth failed'); + throw new \util\exception\SecurityException('auth failed'); $treffer=0; if ( !preg_match($sso['username_regexp'],$html,$treffer) ) - throw new \SecurityException('auth failed'); + throw new \util\exception\SecurityException('auth failed'); if ( !isset($treffer[1]) ) - throw new \SecurityException('authorization failed'); + throw new \util\exception\SecurityException('authorization failed'); $username = $treffer[1]; $user = User::loadWithName( $username ); if ( ! $user->isValid( )) - throw new \SecurityException('authorization failed: user not found: '.$username); + throw new \util\exception\SecurityException('authorization failed: user not found: '.$username); $user->setCurrent(); @@ -267,7 +267,7 @@ class LoginAction extends BaseAction $username = getenv( $ssl_user_var ); if ( empty($username) ) - throw new \SecurityException( 'no username in client certificate ('.$ssl_user_var.') (or there is no client certificate...?)' ); + throw new \util\exception\SecurityException( 'no username in client certificate ('.$ssl_user_var.') (or there is no client certificate...?)' ); $user = User::loadWithName( $username ); @@ -488,7 +488,7 @@ class LoginAction extends BaseAction if ( !$openId->checkAuthentication() ) { - throw new \SecurityException('OpenId-Login failed' ); + throw new \util\exception\SecurityException('OpenId-Login failed' ); } //Html::debug($openId); @@ -502,7 +502,7 @@ class LoginAction extends BaseAction if ( empty($username) ) { // Es konnte kein Benutzername ermittelt werden. - throw new \SecurityException('no username supplied by openid provider' ); + throw new \util\exception\SecurityException('no username supplied by openid provider' ); } $user = User::loadWithName( $username ); @@ -523,7 +523,7 @@ class LoginAction extends BaseAction { Logger::debug("OpenId-Login failed for $username"); // Benutzer ist nicht in Benutzertabelle vorhanden (und angelegt werden soll er auch nicht). - throw new \SecurityException('user',$username,'LOGIN_OPENID_FAILED','error',array('name'=>$username) ); + throw new \util\exception\SecurityException('user',$username,'LOGIN_OPENID_FAILED','error',array('name'=>$username) ); } } else @@ -559,7 +559,7 @@ class LoginAction extends BaseAction Session::setUser(''); if ( $conf['login']['nologin'] ) - throw new \SecurityException('login disabled'); + throw new \util\exception\SecurityException('login disabled'); $openid_user = $this->getRequestVar('openid_url' ); $loginName = $this->getRequestVar('login_name' ,OR_FILTER_ALPHANUM); @@ -647,7 +647,7 @@ class LoginAction extends BaseAction Session::setUser(''); // Altes Login entfernen. if ( $conf['login']['nologin'] ) - throw new \SecurityException('login disabled'); + throw new \util\exception\SecurityException('login disabled'); $loginName = $this->getRequestVar('login_name' ,OR_FILTER_ALPHANUM); $loginPassword = $this->getRequestVar('login_password',OR_FILTER_ALPHANUM); @@ -1057,7 +1057,7 @@ class LoginAction extends BaseAction $user = Session::getUser(); if ( ! $user->isAdmin ) - throw new \SecurityException("Switching the user is only possible for admins."); + throw new \util\exception\SecurityException("Switching the user is only possible for admins."); $this->recreateSession(); diff --git a/modules/cms-core/action/ModelAction.class.php b/modules/cms-core/action/ModelAction.class.php @@ -6,8 +6,8 @@ use cms\model\Model; -use Session; -use \Html; +use util\Session; +use util\Html; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de diff --git a/modules/cms-core/action/ModellistAction.class.php b/modules/cms-core/action/ModellistAction.class.php @@ -4,8 +4,8 @@ namespace cms\action; use cms\model\Model; use cms\model\Project; -use Html; -use Session; +use util\Html; +use util\Session; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de diff --git a/modules/cms-core/action/ObjectAction.class.php b/modules/cms-core/action/ObjectAction.class.php @@ -2,7 +2,7 @@ namespace cms\action; -use ArrayUtils; +use util\ArrayUtils; use cms\model\Acl; use cms\model\Project; use cms\model\User; @@ -13,9 +13,9 @@ use cms\model\BaseObject; use cms\model\Language; use cms\model\File; use cms\model\Link; -use Html; -use Http; -use Session; +use util\Html; +use util\Http; +use util\Session; /** @@ -241,7 +241,7 @@ class ObjectAction extends BaseAction $o = new BaseObject( $acl->objectid ); if ( !$o->hasRight( Acl::ACL_GRANT ) ) - throw new \SecurityException('Not allowed to insert permissions.'); // Scheiss Hacker ;) + throw new \util\exception\SecurityException('Not allowed to insert permissions.'); // Scheiss Hacker ;) // Handelt es sich um eine Benutzer- oder Gruppen ACL? switch( $this->getRequestVar('type') ) @@ -485,7 +485,7 @@ class ObjectAction extends BaseAction public function propPost() { if ( ! $this->hasRequestVar('filename' ) ) - throw new \ValidationException('filename'); + throw new \util\exception\ValidationException('filename'); $this->baseObject->filename = BaseObject::urlify( $this->getRequestVar('filename') ); $this->baseObject->save(); @@ -517,7 +517,7 @@ class ObjectAction extends BaseAction public function namePost() { if ( ! $this->hasRequestVar('name' ) ) - throw new \ValidationException('name'); + throw new \util\exception\ValidationException('name'); $name = $this->baseObject->getNameForLanguage( $this->getRequestId('languageid')); @@ -586,11 +586,11 @@ class ObjectAction extends BaseAction // Validate YAML-Settings try { - \YAML::parse( $this->baseObject->settings); + \util\YAML::parse( $this->baseObject->settings); } catch( \Exception $e ) { - throw new \ValidationException( 'settings' ); + throw new \util\exception\ValidationException( 'settings' ); } // Gültigkeitszeiträume speichern. diff --git a/modules/cms-core/action/PageAction.class.php b/modules/cms-core/action/PageAction.class.php @@ -14,10 +14,10 @@ use cms\model\Language; use cms\model\Model; use cms\publish\PublishPreview; use cms\publish\PublishPublic; -use \Html; -use Http; +use util\Html; +use util\Http; use Logger; -use Session; +use util\Session; /** @@ -769,7 +769,7 @@ class PageAction extends ObjectAction function pubPost() { if ( !$this->page->hasRight( Acl::ACL_PUBLISH ) ) - throw new \SecurityException( 'no right for publish' ); + throw new \util\exception\SecurityException( 'no right for publish' ); Session::close(); diff --git a/modules/cms-core/action/PageelementAction.class.php b/modules/cms-core/action/PageelementAction.class.php @@ -14,13 +14,13 @@ use cms\model\BaseObject; use cms\publish\PublishEdit; use cms\publish\PublishPreview; use cms\publish\PublishShow; -use Html; -use Http; +use util\Html; +use util\Http; use LogicException; -use Session; -use Transformer; -use \Text; -use ValidationException; +use util\Session; +use util\Transformer; +use util\Text; +use util\exception\ValidationException; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de @@ -701,7 +701,7 @@ class PageelementAction extends BaseAction // Pruefen, ob Berechtigung zum Freigeben besteht if ( !$this->page->hasRight(Acl::ACL_RELEASE) ) - throw new \SecurityException( 'Cannot release','no right' ); + throw new \util\exception\SecurityException( 'Cannot release','no right' ); // Inhalt freigeben $this->value->release(); @@ -1309,7 +1309,7 @@ class PageelementAction extends BaseAction function pubPost() { if ( !$this->page->hasRight( Acl::ACL_PUBLISH ) ) - throw new \SecurityException( 'no right for publish' ); + throw new \util\exception\SecurityException( 'no right for publish' ); $this->page->public = true; $this->page->publish(); diff --git a/modules/cms-core/action/ProfileAction.class.php b/modules/cms-core/action/ProfileAction.class.php @@ -23,10 +23,10 @@ use cms\model\BaseObject; use cms\model\User; use language\Language; use LogicException; -use Mail; -use modules\util\UIUtils; +use util\Mail; +use util\UIUtils; use security\Base2n; -use \Session; +use util\Session; /** diff --git a/modules/cms-core/action/ProjectlistAction.class.php b/modules/cms-core/action/ProjectlistAction.class.php @@ -77,7 +77,7 @@ class ProjectlistAction extends BaseAction function addView() { if( ! $this->userIsAdmin() ) - throw new \SecurityException('user is not allowed to add a project'); + throw new \util\exception\SecurityException('user is not allowed to add a project'); $this->setTemplateVar( 'projects',Project::getAllProjects() ); } @@ -90,14 +90,14 @@ class ProjectlistAction extends BaseAction function addPost() { if( !$this->userIsAdmin()) - throw new \SecurityException("user is not allowed to add a project"); + throw new \util\exception\SecurityException("user is not allowed to add a project"); switch( $this->getRequestVar('type') ) { case 'empty': case '': if ( !$this->hasRequestVar('name') ) - throw new \ValidationException('name'); + throw new \util\exception\ValidationException('name'); $project = new Project(); $project->name = $this->getRequestVar('name'); diff --git a/modules/cms-core/action/RequestParams.class.php b/modules/cms-core/action/RequestParams.class.php @@ -32,7 +32,7 @@ namespace { namespace cms\action { - use Text; + use util\Text; class RequestParams { diff --git a/modules/cms-core/action/SearchAction.class.php b/modules/cms-core/action/SearchAction.class.php @@ -12,8 +12,8 @@ use cms\model\File; -use Session; -use \Html; +use util\Session; +use util\Html; diff --git a/modules/cms-core/action/StartAction.class.php b/modules/cms-core/action/StartAction.class.php @@ -13,12 +13,12 @@ use cms\model\Model; use database\Database; -use Http; +use util\Http; use Logger; use \security\Password; -use Session; -use \Html; -use \Mail; +use util\Session; +use util\Html; +use util\Mail; // OpenRat Content Management System // Copyright (C) 2002-2007 Jan Dankert, jandankert@jandankert.de @@ -206,7 +206,7 @@ class StartAction extends BaseAction $authid = $this->getRequestVar( $sso['auth_param_name']); if ( empty( $authid) ) - throw new \SecurityException( 'no authorization data (no auth-id)'); + throw new \util\exception\SecurityException( 'no authorization data (no auth-id)'); if ( $sso['auth_param_serialized'] ) $authid = unserialize( $authid ); @@ -256,12 +256,12 @@ class StartAction extends BaseAction $html = implode('',$inhalt); // Html::debug($html); if ( !preg_match($sso['expect_regexp'],$html) ) - throw new \SecurityException('auth failed'); + throw new \util\exception\SecurityException('auth failed'); $treffer=0; if ( !preg_match($sso['username_regexp'],$html,$treffer) ) - throw new \SecurityException('auth failed'); + throw new \util\exception\SecurityException('auth failed'); if ( !isset($treffer[1]) ) - throw new \SecurityException('authorization failed'); + throw new \util\exception\SecurityException('authorization failed'); $username = $treffer[1]; @@ -271,7 +271,7 @@ class StartAction extends BaseAction $user = User::loadWithName( $username ); if ( ! $user->isValid( )) - throw new \SecurityException('authorization failed: user not found: '.$username); + throw new \util\exception\SecurityException('authorization failed: user not found: '.$username); $user->setCurrent(); @@ -287,7 +287,7 @@ class StartAction extends BaseAction $username = getenv( $ssl_user_var ); if ( empty($username) ) - throw new \SecurityException( 'no username in client certificate ('.$ssl_user_var.') (or there is no client certificate...?)' ); + throw new \util\exception\SecurityException( 'no username in client certificate ('.$ssl_user_var.') (or there is no client certificate...?)' ); $this->setDefaultDb(); @@ -565,7 +565,7 @@ class StartAction extends BaseAction Session::setUser(''); if ( $conf['login']['nologin'] ) - throw new \SecurityException('login disabled'); + throw new \util\exception\SecurityException('login disabled'); $openid_user = $this->getRequestVar('openid_url' ); $loginName = $this->getRequestVar('login_name' ,OR_FILTER_ALPHANUM); @@ -841,7 +841,7 @@ class StartAction extends BaseAction $user = Session::getUser(); if ( ! $user->isAdmin ) - throw new \SecurityException(""); + throw new \util\exception\SecurityException(""); $this->recreateSession(); diff --git a/modules/cms-core/action/TemplateAction.class.php b/modules/cms-core/action/TemplateAction.class.php @@ -12,9 +12,9 @@ use cms\model\Page; use cms\model\TemplateModel; use cms\publish\PublishPublic; -use Session; -use \Html; -use \Text; +use util\Session; +use util\Html; +use util\Text; // OpenRat Content Management System // Copyright (C) 2002-2009 Jan Dankert @@ -236,7 +236,7 @@ class TemplateAction extends BaseAction if ( in_array($input, $extensions) ) { $this->addNotice('template',$this->template->name,'DUPLICATE_INPUT','error'); - throw new \ValidationException( $modelName ); + throw new \util\exception\ValidationException( $modelName ); } $extensions[ $modelId ] = $input; @@ -292,7 +292,7 @@ class TemplateAction extends BaseAction $name = $this->getRequestVar('name',OR_FILTER_ALPHANUM); if ( empty($name) ) - throw new \ValidationException('name'); + throw new \util\exception\ValidationException('name'); $newElement = $this->template->addElement( $name,$this->getRequestVar('description'),$this->getRequestVar('typeid') ); diff --git a/modules/cms-core/action/TemplatelistAction.class.php b/modules/cms-core/action/TemplatelistAction.class.php @@ -5,7 +5,7 @@ namespace cms\action; use cms\model\Element; use cms\model\Project; use cms\model\Template; -use Session; +use util\Session; // OpenRat Content Management System // Copyright (C) 2002-2009 Jan Dankert @@ -111,7 +111,7 @@ class TemplatelistAction extends BaseAction { // Hinzufuegen eines Templates if ( $this->getRequestVar('name') == '' ) - throw new \ValidationException('name'); + throw new \util\exception\ValidationException('name'); // Hinzufuegen eines Templates switch( $this->getRequestVar('type') ) diff --git a/modules/cms-core/action/TextAction.class.php b/modules/cms-core/action/TextAction.class.php @@ -10,7 +10,7 @@ namespace cms\action use cms\model\BaseObject; use cms\model\Text; - use \Html; + use util\Html; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de diff --git a/modules/cms-core/action/TreeAction.class.php b/modules/cms-core/action/TreeAction.class.php @@ -12,11 +12,11 @@ use cms\model\Project; use cms\model\Template; use cms\model\User; use cms\model\Value; -use Tree; +use util\Tree; use cms\model\Language; use cms\model\Model; -use Session; +use util\Session; // OpenRat Content Management System // Copyright (C) 2002 Jan Dankert, jandankert@jandankert.de diff --git a/modules/cms-core/action/UrlAction.class.php b/modules/cms-core/action/UrlAction.class.php @@ -7,8 +7,8 @@ use cms\model\Folder; use cms\model\Url; -use Html; -use Session; +use util\Html; +use util\Session; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de diff --git a/modules/cms-core/action/UserAction.class.php b/modules/cms-core/action/UserAction.class.php @@ -10,12 +10,12 @@ use cms\model\BaseObject; use cms\model\Language; -use Http; +use util\Http; use security\Base2n; use \security\Password; -use \Session; -use \Html; -use \Mail; +use util\Session; +use util\Html; +use util\Mail; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de @@ -73,7 +73,7 @@ class UserAction extends BaseAction public function propPost() { if ( ! $this->getRequestVar('name') ) - throw new \ValidationException( 'name'); + throw new \util\exception\ValidationException( 'name'); // Benutzer speichern $this->user->name = $this->getRequestVar('name' ); diff --git a/modules/cms-core/auth/HttpAuth.class.php b/modules/cms-core/auth/HttpAuth.class.php @@ -1,5 +1,7 @@ <?php +use util\Http; + /** * HTTP-Authentifzierung. * diff --git a/modules/cms-core/auth/IdentAuth.class.php b/modules/cms-core/auth/IdentAuth.class.php @@ -1,5 +1,7 @@ <?php +use util\Http; + /** * Authentifizierung via Ident-Server. * diff --git a/modules/cms-core/auth/LdapAuth.class.php b/modules/cms-core/auth/LdapAuth.class.php @@ -1,5 +1,7 @@ <?php +use util\Ldap; + class LdapAuth implements Auth { diff --git a/modules/cms-core/auth/LdapUserDNAuth.class.php b/modules/cms-core/auth/LdapUserDNAuth.class.php @@ -1,5 +1,7 @@ <?php +use util\Ldap; + /** * Authentifizierung gegen einen LDAP-Server. * diff --git a/modules/cms-core/auth/OpenIdAuth.class.php b/modules/cms-core/auth/OpenIdAuth.class.php @@ -1,5 +1,7 @@ <?php +use util\Http; + /** * Open-Id Authentisierung gem�� OpenId-Spezifikation 1.0. @@ -374,17 +376,17 @@ class OpenIdAuth implements Auth if ( $queryVars['openid.invalidate_handle'] != $this->handle ) { - throw new \SecurityException('Association-Handle mismatch.'); + throw new \util\exception\SecurityException('Association-Handle mismatch.'); } if ( $queryVars['openid.mode'] != 'id_res' ) { - throw new \SecurityException('Open-Id: Unknown mode:'.$queryVars['openid.mode']); + throw new \util\exception\SecurityException('Open-Id: Unknown mode:'.$queryVars['openid.mode']); } if ( $this->provider=='identity' && $queryVars['openid.identity'] != $this->identity ) { - throw new \SecurityException('Open-Id: Identity mismatch. Wrong identity:'.$queryVars['openid.identity']); + throw new \util\exception\SecurityException('Open-Id: Identity mismatch. Wrong identity:'.$queryVars['openid.identity']); } @@ -441,7 +443,7 @@ class OpenIdAuth implements Auth if ( !array_key_exists('is_valid',$result) ) { // Zeile nicht gefunden. - throw new \SecurityException('Undefined Open-Id response: "is_valid" expected, but not found'); + throw new \util\exception\SecurityException('Undefined Open-Id response: "is_valid" expected, but not found'); } elseif ( $result['is_valid'] == 'true' ) { @@ -451,7 +453,7 @@ class OpenIdAuth implements Auth else { // Bestaetigung wurde durch den OpenId-Provider abgelehnt. - throw new \SecurityException('Server refused login.'); + throw new \util\exception\SecurityException('Server refused login.'); } } diff --git a/modules/cms-core/functions/common.inc.php b/modules/cms-core/functions/common.inc.php @@ -1,5 +1,7 @@ <?php +use util\Session; + /** * F�gt einen Slash ("/") an das Ende an, sofern nicht bereits vorhanden. diff --git a/modules/cms-core/init.php b/modules/cms-core/init.php @@ -15,6 +15,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +use util\exception\ValidationException; + define('MIN_VERSION','5.4'); if ( version_compare(phpversion(),MIN_VERSION,"<") ) diff --git a/modules/cms-core/model/BaseObject.class.php b/modules/cms-core/model/BaseObject.class.php @@ -3,11 +3,11 @@ namespace cms\model; -use ArrayUtils; +use util\ArrayUtils; use cms\publish\Publish; use phpseclib\Math\BigInteger; use util\VariableResolver; -use YAML; +use util\YAML; use template_engine\components\ElseComponent; /** @@ -272,7 +272,7 @@ class BaseObject extends ModelBase { if ( is_null($this->aclMask) ) { - $user = \Session::getUser(); + $user = \util\Session::getUser(); if ( ! $user ) { @@ -882,7 +882,7 @@ SQL else $stmt->setInt ('parentid',$this->parentid ); - $user = \Session::getUser(); + $user = \util\Session::getUser(); $this->lastchangeUser = $user; $this->lastchangeDate = now(); $stmt->setInt ('time' , $this->lastchangeDate ); @@ -913,7 +913,7 @@ SQL ' lastchange_userid = {userid} '. ' WHERE id={objectid}'); - $user = \Session::getUser(); + $user = \util\Session::getUser(); $this->lastchangeUser = $user; $this->lastchangeDate = now(); @@ -950,7 +950,7 @@ SQL ' published_userid = {userid} '. ' WHERE id={objectid}'); - $user = \Session::getUser(); + $user = \util\Session::getUser(); $this->publishedUser = $user; $this->publishedDate = now(); @@ -1104,10 +1104,10 @@ SQL $sql->setString('projectid', $this->projectid); $sql->setInt ('orderid' , 99999 ); $sql->setInt ('time' , now() ); - $user = \Session::getUser(); + $user = \util\Session::getUser(); $sql->setInt ('createuserid' , $user->userid ); $sql->setInt ('createtime' , now() ); - $user = \Session::getUser(); + $user = \util\Session::getUser(); $sql->setInt ('userid' , $user->userid ); $sql->setInt( 'typeid',$this->getTypeid()); diff --git a/modules/cms-core/model/Element.class.php b/modules/cms-core/model/Element.class.php @@ -2,7 +2,7 @@ namespace cms\model; -use ArrayUtils; +use util\ArrayUtils; use Logger; /** @@ -537,7 +537,7 @@ SQL // Fixing old syntax ("key:value") to valid YAML syntax. $this->code = preg_replace( '/^(\w+)\:(.+)$/m','${1}: ${2}', $this->code ); - $items = \YAML::parse( $this->code ); + $items = \util\YAML::parse( $this->code ); Logger::trace('dynamic-parameters: '.print_r($items,true)); diff --git a/modules/cms-core/model/File.class.php b/modules/cms-core/model/File.class.php @@ -24,10 +24,10 @@ use cms\publish\PublishEdit; use cms\publish\PublishPreview; use cms\publish\PublishPublic; use cms\publish\PublishShow; -use JSqueeze; -use Less_Parser; +use util\JSqueeze; +use \Less_Parser; use Logger; -use util\FileCache; +use util\cache\FileCache; define('OR_FILE_DEFAULT_MIMETYPE','application/octet-stream'); @@ -91,7 +91,7 @@ class File extends BaseObject * @return FileCache */ public function getCache() { - $cacheKey = array('db'=>db()->id,'file'=>$this->objectid,'publish'=>\ClassUtils::getSimpleClassName($this->publisher)); + $cacheKey = array('db'=>db()->id,'file'=>$this->objectid,'publish'=> \util\ClassUtils::getSimpleClassName($this->publisher)); return new FileCache( $cacheKey,function() { return $this->loadValueFromDatabase(); @@ -549,9 +549,9 @@ SQL private function filterValue() { - $publishType = strtolower(substr(\ClassUtils::getSimpleClassName($this->publisher),7)); + $publishType = strtolower(substr(\util\ClassUtils::getSimpleClassName($this->publisher),7)); - foreach(\ArrayUtils::getSubArray($this->getTotalSettings(), array( 'filter')) as $filterEntry ) + foreach(\util\ArrayUtils::getSubArray($this->getTotalSettings(), array( 'filter')) as $filterEntry ) { $filterName = @$filterEntry['name']; $extension = @$filterEntry['extension']; diff --git a/modules/cms-core/model/Language.class.php b/modules/cms-core/model/Language.class.php @@ -149,7 +149,7 @@ class Language extends ModelBase $isocode = str_replace('_','',$isocode); $this->isocode = $isocode; - $codes = \GlobalFunctions::getIsoCodes(); + $codes = \util\GlobalFunctions::getIsoCodes(); $this->name = $codes[ $isocode ]; } diff --git a/modules/cms-core/model/Page.class.php b/modules/cms-core/model/Page.class.php @@ -16,11 +16,11 @@ namespace cms\model; // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -use cms\mustache\Mustache; +use util\Mustache; use cms\publish\PublishPreview;use cms\publish\PublishPublic; use http\Exception\RuntimeException; use Logger; -use util\FileCache; +use util\cache\FileCache; /** @@ -107,7 +107,7 @@ class Page extends BaseObject 'page' =>$this->objectid, 'language' =>$this->languageid, 'model' =>$this->modelid, - 'publish' =>\ClassUtils::getSimpleClassName($this->publisher) ); + 'publish' => \util\ClassUtils::getSimpleClassName($this->publisher) ); return new FileCache( $cacheKey,function() { return $this->generateValue(); diff --git a/modules/cms-core/model/Pageelement.class.php b/modules/cms-core/model/Pageelement.class.php @@ -19,7 +19,7 @@ namespace cms\model; use cms\mustache\Mustache; use cms\publish\PublishPreview;use cms\publish\PublishPublic; use Logger; -use util\FileCache; +use util\cache\FileCache; /** diff --git a/modules/cms-core/model/Project.class.php b/modules/cms-core/model/Project.class.php @@ -3,7 +3,7 @@ namespace cms\model; use database\Database; -use Session; +use util\Session; /** @@ -1045,7 +1045,7 @@ SQL $f->load(); $names = $f->parentObjectNames(true,true); foreach( $names as $fid=>$name ) - $names[$fid] = \Text::maxLength($name,15,'..',STR_PAD_BOTH); + $names[$fid] = \util\Text::maxLength($name,15,'..',STR_PAD_BOTH); $folders[ $id ] = implode( ' &raquo; ',$names ); $folders[ $id ] .= ' &raquo; '; } diff --git a/modules/cms-core/model/User.class.php b/modules/cms-core/model/User.class.php @@ -113,7 +113,7 @@ class User extends ModelBase { $this->loginDate = time(); - \Session::setUser( $this ); + \util\Session::setUser( $this ); } @@ -236,7 +236,7 @@ SQL $stmt->setInt( 'expires' ,time() + ($expirationPeriodDays*24*60*60) ); $stmt->setInt( 'create_date',time() ); - $browser = new \Browser(); + $browser = new \util\Browser(); $stmt->setString( 'platform',$browser->platform ); $stmt->setString( 'name' ,$browser->name ); $row = $stmt->getRow(); diff --git a/modules/cms-core/model/Value.class.php b/modules/cms-core/model/Value.class.php @@ -1,16 +1,16 @@ <?php namespace cms\model; -use ArrayUtils; +use util\ArrayUtils; use cms\publish\Publish; use MacroRunner; use \ObjectNotFoundException; use \Logger; -use \Text; -use \Html; -use \Http; -use \Transformer; -use \Code; -use util\FileCache; +use util\Text; +use util\Html; +use util\Http; +use util\Transformer; +use util\Code; +use util\cache\FileCache; // OpenRat Content Management System // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de @@ -436,7 +436,7 @@ SQL $sql->setBoolean( 'publish' ,$this->publish ); $sql->setInt ( 'lastchange_date' ,now() ); - $user = \Session::getUser(); + $user = \util\Session::getUser(); $sql->setInt ( 'lastchange_userid',$user->userid ); $sql->query(); @@ -553,7 +553,7 @@ SQL 'el'=>is_object($this->element)?$this->element->elementid:0, 'language'=>$this->languageid, 'model' =>is_object($this->page)?$this->page->modelid:0, - 'publish'=>\ClassUtils::getSimpleClassName($this->publisher) ); + 'publish'=> \util\ClassUtils::getSimpleClassName($this->publisher) ); return new FileCache( $cacheKey,function() { return $this->generateValue(); },$this->lastchangeTimeStamp ); @@ -1159,7 +1159,7 @@ SQL $mdConfig = Config()->subset('editor')->subset('markdown'); - $parser = new \Parsedown(); + $parser = new \util\Parsedown(); $parser->setUrlsLinked( $mdConfig->is('urls-linked',true)); $parser->setMarkupEscaped( !$this->element->html ); @@ -1280,7 +1280,7 @@ SQL try { $inhalt .= $runner->executeMacro($macroName, $macroSettings,$this->page); } - catch( \OpenRatException $e ) { + catch( \util\exception\OpenRatException $e ) { if ( !$this->publisher->isPublic() ) $inhalt = lang($e->key).' ('.$e->getMessage().')'; // Inform the viewer else @@ -1385,7 +1385,7 @@ SQL break; case 'edit_url': $raw = true; - $db = \Session::getDatabase(); + $db = \util\Session::getDatabase(); $inhalt = Html::url('page',null,$this->page->objectid,array('dbid'=>$db->id)); break; case 'edit_fullurl': @@ -1462,27 +1462,27 @@ SQL break; case 'act_user_username': - $user = \Session::getUser(); + $user = \util\Session::getUser(); if ( $user ) $inhalt = $user->name; break; case 'act_user_fullname': - $user = \Session::getUser(); + $user = \util\Session::getUser(); if ( $user ) $inhalt = $user->fullname; break; case 'act_user_mail': - $user = \Session::getUser(); + $user = \util\Session::getUser(); if ( $user ) $inhalt = $user->mail; break; case 'act_user_desc': - $user = \Session::getUser(); + $user = \util\Session::getUser(); if ( $user ) $inhalt = $user->desc; break; case 'act_user_tel': - $user = \Session::getUser(); + $user = \util\Session::getUser(); if ( $user ) $inhalt = $user->tel; break; @@ -1645,7 +1645,7 @@ SQL function tmpfile() { $db = db_connection(); - $filename = \FileUtils::getTempFileName( ); + $filename = \util\FileUtils::getTempFileName( ); return $filename; } diff --git a/modules/cms-macros/MacroRunner.class.php b/modules/cms-macros/MacroRunner.class.php @@ -4,6 +4,8 @@ use cms\model\Element; use cms\model\Template; use cms\model\Value; +use util\ArrayUtils; +use util\exception\OpenRatException; use util\VariableResolver; class MacroRunner @@ -27,7 +29,7 @@ class MacroRunner throw new OpenRatException('ERROR_IN_ELEMENT', 'class not found:' . $className); - /** @var \Macro $macro */ + /** @var \util\Macro $macro */ $macro = new $className; if (!method_exists($macro, 'execute')) diff --git a/modules/cms-macros/macro/Album.class.php b/modules/cms-macros/macro/Album.class.php @@ -19,6 +19,7 @@ use cms\model\BaseObject; use cms\model\File; use cms\model\Folder; use cms\model\Image; +use util\Macro; /** diff --git a/modules/cms-macros/macro/Atom.class.php b/modules/cms-macros/macro/Atom.class.php @@ -22,6 +22,7 @@ use cms\model\Folder; use cms\model\BaseObject; use cms\model\Page; +use util\Macro; /** diff --git a/modules/cms-macros/macro/BlockMenu.class.php b/modules/cms-macros/macro/BlockMenu.class.php @@ -29,6 +29,7 @@ // --------------------------------------------------------------------------- use cms\model\Folder; use cms\model\BaseObject; +use util\Macro; /** diff --git a/modules/cms-macros/macro/BreadCrumb.class.php b/modules/cms-macros/macro/BreadCrumb.class.php @@ -31,6 +31,7 @@ // // --------------------------------------------------------------------------- use cms\model\Folder; +use util\Macro; /** diff --git a/modules/cms-macros/macro/CSVTable.class.php b/modules/cms-macros/macro/CSVTable.class.php @@ -16,6 +16,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use cms\model\File; +use util\Macro; /** diff --git a/modules/cms-macros/macro/ClassicMenu.class.php b/modules/cms-macros/macro/ClassicMenu.class.php @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use cms\model\Folder; use cms\model\Page; +use util\Macro; /** diff --git a/modules/cms-macros/macro/CommonMenu.class.php b/modules/cms-macros/macro/CommonMenu.class.php @@ -32,6 +32,7 @@ // --------------------------------------------------------------------------- use cms\model\Folder; use cms\model\Page; +use util\Macro; /** diff --git a/modules/cms-macros/macro/DoiMenu.class.php b/modules/cms-macros/macro/DoiMenu.class.php @@ -36,6 +36,7 @@ use cms\model\File; use cms\model\Folder; use cms\model\Page; +use util\Macro; /** diff --git a/modules/cms-macros/macro/GoogleMaps.class.php b/modules/cms-macros/macro/GoogleMaps.class.php @@ -19,7 +19,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // --------------------------------------------------------------------------- - +use util\Macro; /** diff --git a/modules/cms-macros/macro/LanguageLinksForPage.class.php b/modules/cms-macros/macro/LanguageLinksForPage.class.php @@ -23,6 +23,7 @@ use cms\model\Language; use cms\model\Page; use cms\model\Project; +use util\Macro; /** * Erstellen einer Liste von Language-Links auf die selbe Seite. diff --git a/modules/cms-macros/macro/LastChanges.class.php b/modules/cms-macros/macro/LastChanges.class.php @@ -20,6 +20,8 @@ use cms\model\Folder; use cms\model\Link; use cms\model\Page; use cms\model\Project; +use util\Macro; +use util\Text; /** diff --git a/modules/cms-macros/macro/LastPage.class.php b/modules/cms-macros/macro/LastPage.class.php @@ -28,6 +28,7 @@ // // --------------------------------------------------------------------------- use cms\model\Folder; +use util\Macro; /** diff --git a/modules/cms-macros/macro/Link.class.php b/modules/cms-macros/macro/Link.class.php @@ -28,6 +28,7 @@ // // --------------------------------------------------------------------------- use cms\model\BaseObject; +use util\Macro; /** diff --git a/modules/cms-macros/macro/LinkList.class.php b/modules/cms-macros/macro/LinkList.class.php @@ -32,6 +32,7 @@ // --------------------------------------------------------------------------- use cms\model\Folder; use cms\model\BaseObject; +use util\Macro; /** diff --git a/modules/cms-macros/macro/ListMenu.class.php b/modules/cms-macros/macro/ListMenu.class.php @@ -32,6 +32,7 @@ // --------------------------------------------------------------------------- use cms\model\Folder; use cms\model\BaseObject; +use util\Macro; /** diff --git a/modules/cms-macros/macro/MainMenu.class.php b/modules/cms-macros/macro/MainMenu.class.php @@ -29,6 +29,7 @@ // --------------------------------------------------------------------------- use cms\model\Folder; use cms\model\BaseObject; +use util\Macro; /** diff --git a/modules/cms-macros/macro/NextPage.class.php b/modules/cms-macros/macro/NextPage.class.php @@ -28,6 +28,7 @@ // // --------------------------------------------------------------------------- use cms\model\Folder; +use util\Macro; /** diff --git a/modules/cms-macros/macro/OpenStreetMap.class.php b/modules/cms-macros/macro/OpenStreetMap.class.php @@ -19,7 +19,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // --------------------------------------------------------------------------- - +use util\Macro; /** diff --git a/modules/cms-macros/macro/PagesNavigation.class.php b/modules/cms-macros/macro/PagesNavigation.class.php @@ -28,6 +28,7 @@ // // --------------------------------------------------------------------------- use cms\model\Folder; +use util\Macro; /** diff --git a/modules/cms-macros/macro/RSSCreate.class.php b/modules/cms-macros/macro/RSSCreate.class.php @@ -34,6 +34,7 @@ // // --------------------------------------------------------------------------- use cms\model\Folder; +use util\Macro; /** diff --git a/modules/cms-macros/macro/RSSReader.class.php b/modules/cms-macros/macro/RSSReader.class.php @@ -27,7 +27,7 @@ // Lesen eines RSS-Feeds und erzeugen eines HTML-Abschnittes dafuer // // --------------------------------------------------------------------------- - +use util\Macro; /** diff --git a/modules/cms-macros/macro/SearchIndex.class.php b/modules/cms-macros/macro/SearchIndex.class.php @@ -5,6 +5,7 @@ use cms\model\Name; use cms\model\Page; use cms\model\Project; use cms\publish\PublishEdit; +use util\Macro; /** diff --git a/modules/cms-macros/macro/Sitemap.class.php b/modules/cms-macros/macro/Sitemap.class.php @@ -30,6 +30,7 @@ use cms\model\Folder; use cms\model\BaseObject; use cms\model\Page; +use util\Macro; /** diff --git a/modules/cms-macros/macro/TableFromFile.class.php b/modules/cms-macros/macro/TableFromFile.class.php @@ -16,6 +16,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use cms\model\File; +use util\Macro; /** diff --git a/modules/cms-macros/macro/TagCloud.class.php b/modules/cms-macros/macro/TagCloud.class.php @@ -16,6 +16,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use cms\model\Folder; +use util\Macro; /** diff --git a/modules/cms-macros/macro/TagList.class.php b/modules/cms-macros/macro/TagList.class.php @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use cms\model\Folder; use cms\model\Link; +use util\Macro; /** diff --git a/modules/cms-macros/macro/TeaserList.class.php b/modules/cms-macros/macro/TeaserList.class.php @@ -17,6 +17,8 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use cms\model\Folder; use cms\model\Page; +use util\Macro; +use util\Text; /** diff --git a/modules/cms-macros/macro/Youtube.class.php b/modules/cms-macros/macro/Youtube.class.php @@ -19,7 +19,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // --------------------------------------------------------------------------- - +use util\Macro; /** diff --git a/modules/cms-publish/FolderPublisher.class.php b/modules/cms-publish/FolderPublisher.class.php @@ -1,4 +1,7 @@ <?php + +use util\Text; + /** * Created by PhpStorm. * User: dankert diff --git a/modules/cms-publish/Ftp.class.php b/modules/cms-publish/Ftp.class.php @@ -1,208 +1,209 @@ -<?php -// OpenRat Content Management System -// Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -/** - * Darstellen einer FTP-Verbindung, das beinhaltet - * das Login, das Kopieren von Dateien sowie praktische - * FTP-Funktionen - * - * @author $Author$ - * @version $Revision$ - * @package openrat.services - */ -class Ftp -{ - var $verb; - var $url; - var $log = array(); - - var $passive = false; - - var $ok = true; - - private $path; - - - // Konstruktor - public function __construct( $url ) - { - $this->connect( $url ); - } - - - // Aufbauen der Verbindung - private function connect( $url ) - { - $this->url = $url; - - global $conf; - - $conf_ftp = $conf['publish']['ftp']; - $ftp = parse_url( $this->url ); - - // Die projektspezifischen Werte gewinnen bei �berschneidungen mit den Default-Werten - $ftp = array_merge($conf_ftp,$ftp); - - // Nur FTP und FTPS (seit PHP 4.3) erlaubt - if ( !in_array(@$ftp['scheme'],array('ftp','ftps')) ) - { - throw new OpenRatException( 'ERROR_PUBLISH','Unknown scheme in FTP Url: '.@$ftp['scheme']. - '. Only FTP (and FTPS, if compiled in) are supported'); - } - - if ( function_exists('ftp_ssl_connect') && $ftp['scheme'] == 'ftps' ) - $this->verb = @ftp_ssl_connect( $ftp['host'],$ftp['port'] ); - else - $this->verb = @ftp_connect( $ftp['host'],$ftp['port'] ); - - if ( !$this->verb ) - { - Logger::error('Cannot connect to '.$ftp['host'].':'.$ftp['port']); - throw new OpenRatException('ERROR_PUBLISH','Cannot connect to '.$ftp['scheme'].'-server: '.$ftp['host'].':'.$ftp['port']); - } - - $this->log[] = 'Connected to FTP server '.$ftp['host'].':'.$ftp['port']; - - if ( empty($ftp['user']) ) - { - $ftp['user'] = 'anonymous'; - $ftp['pass'] = 'openrat@openrat.de'; - } - - if ( ! ftp_login( $this->verb,$ftp['user'],$ftp['pass'] ) ) - throw new OpenRatException('ERROR_PUBLISH','Unable to login as user '.$ftp['user']); - - $this->log[] = 'Logged in as user '.$ftp['user']; - - $pasv = (!empty($ftp['fragment']) && $ftp['fragment'] == 'passive' ); - - $this->log[] = 'entering passive mode '.($pasv?'on':'off'); - if ( ! ftp_pasv($this->verb,true) ) - throw new OpenRatException('ERROR_PUBLISH','Cannot switch to FTP PASV mode'); - - if ( !empty($ftp['query']) ) - { - parse_str( $ftp['query'],$ftp_var ); - - if ( isset( $ftp_var['site'] ) ) - { - $site_commands = explode( ',',$ftp_var['site'] ); - foreach( $site_commands as $cmd ) - { - if ( ! @ftp_site( $this->verb,$cmd ) ) - throw new OpenRatException('ERROR_PUBLISH','unable to do SITE command: '.$cmd); - } - } - } - - $this->path = rtrim( $ftp['path'],'/' ); - - $this->log[] = 'Changing directory to '.$this->path; - - if ( ! @ftp_chdir( $this->verb,$this->path ) ) - throw new OpenRatException('ERROR_PUBLISH','unable CHDIR to directory: '.$this->path); - } - - - /** - * Kopieren einer Datei vom lokalen System auf den FTP-Server. - * - * @param String Quelle - * @param String Ziel - * @param int FTP-Mode (BINARY oder ASCII) - */ - public function put( $source,$dest ) - { - $dest = $this->path.'/'.$dest; - - $this->log .= "Copying file: $source -&gt; $dest ...\n"; - - $mode = FTP_BINARY; - $p = strrpos( basename($dest),'.' ); // Letzten Punkt suchen - - if ($p!==false) // Wennn letzten Punkt gefunden, dann dort aufteilen - { - $extension = substr( basename($dest),$p+1 ); - $type = config('mime-types',$extension); - if ( substr($type,0,5) == 'text/') - $mode = FTP_ASCII; - } - - Logger::debug("FTP PUT target:$dest mode:".(($mode==FTP_ASCII)?'ascii':'binary')); - - if ( !@ftp_put( $this->verb,$dest,$source,$mode ) ) - { - if ( !$this->mkdirs( dirname($dest) ) ) - return; // Fehler. - - ftp_chdir( $this->verb,$this->path ); - - if ( ! @ftp_put( $this->verb,$dest,$source,$mode ) ) - throw new OpenRatException('ERROR_PUBLISH', - "FTP PUT failed.\n". - "source : $source\n". - "destination: $dest"); - - } - } - - - - /** - * Private Methode zum rekursiven Anlegen von Verzeichnissen. - * - * @param String Pfad - * @return boolean true, wenn ok - */ - private function mkdirs( $strPath ) - { - if ( @ftp_chdir($this->verb,$strPath) ) - return true; // Verzeichnis existiert schon :) - - $pStrPath = dirname($strPath); - - if ( !$this->mkdirs($pStrPath) ) - return false; - - if ( ! @ftp_mkdir($this->verb,$strPath) ) - throw new OpenRatException('ERROR_PUBLISH',"failed to create remote directory: $strPath"); - - return true; - } - - - - /** - * Schliessen der FTP-Verbindung.<br> - * Sollte unbedingt aufgerufen werden, damit keine unn�tigen Sockets aufbleiben. - */ - public function close() - { - if ( ! @ftp_quit( $this->verb ) ) - { - // Closing not possible. - // Only logging. Maybe we could throw an Exception here? - Logger::warn('Failed to close FTP connection. Continueing...'); - return; - } - } -} - - +<?php +// OpenRat Content Management System +// Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +use util\exception\OpenRatException; + + +/** + * Darstellen einer FTP-Verbindung, das beinhaltet + * das Login, das Kopieren von Dateien sowie praktische + * FTP-Funktionen + * + * @author $Author$ + * @version $Revision$ + * @package openrat.services + */ +class Ftp +{ + var $verb; + var $url; + var $log = array(); + + var $passive = false; + + var $ok = true; + + private $path; + + + // Konstruktor + public function __construct( $url ) + { + $this->connect( $url ); + } + + + // Aufbauen der Verbindung + private function connect( $url ) + { + $this->url = $url; + + global $conf; + + $conf_ftp = $conf['publish']['ftp']; + $ftp = parse_url( $this->url ); + + // Die projektspezifischen Werte gewinnen bei �berschneidungen mit den Default-Werten + $ftp = array_merge($conf_ftp,$ftp); + + // Nur FTP und FTPS (seit PHP 4.3) erlaubt + if ( !in_array(@$ftp['scheme'],array('ftp','ftps')) ) + { + throw new OpenRatException( 'ERROR_PUBLISH','Unknown scheme in FTP Url: '.@$ftp['scheme']. + '. Only FTP (and FTPS, if compiled in) are supported'); + } + + if ( function_exists('ftp_ssl_connect') && $ftp['scheme'] == 'ftps' ) + $this->verb = @ftp_ssl_connect( $ftp['host'],$ftp['port'] ); + else + $this->verb = @ftp_connect( $ftp['host'],$ftp['port'] ); + + if ( !$this->verb ) + { + Logger::error('Cannot connect to '.$ftp['host'].':'.$ftp['port']); + throw new OpenRatException('ERROR_PUBLISH','Cannot connect to '.$ftp['scheme'].'-server: '.$ftp['host'].':'.$ftp['port']); + } + + $this->log[] = 'Connected to FTP server '.$ftp['host'].':'.$ftp['port']; + + if ( empty($ftp['user']) ) + { + $ftp['user'] = 'anonymous'; + $ftp['pass'] = 'openrat@openrat.de'; + } + + if ( ! ftp_login( $this->verb,$ftp['user'],$ftp['pass'] ) ) + throw new OpenRatException('ERROR_PUBLISH','Unable to login as user '.$ftp['user']); + + $this->log[] = 'Logged in as user '.$ftp['user']; + + $pasv = (!empty($ftp['fragment']) && $ftp['fragment'] == 'passive' ); + + $this->log[] = 'entering passive mode '.($pasv?'on':'off'); + if ( ! ftp_pasv($this->verb,true) ) + throw new OpenRatException('ERROR_PUBLISH','Cannot switch to FTP PASV mode'); + + if ( !empty($ftp['query']) ) + { + parse_str( $ftp['query'],$ftp_var ); + + if ( isset( $ftp_var['site'] ) ) + { + $site_commands = explode( ',',$ftp_var['site'] ); + foreach( $site_commands as $cmd ) + { + if ( ! @ftp_site( $this->verb,$cmd ) ) + throw new OpenRatException('ERROR_PUBLISH','unable to do SITE command: '.$cmd); + } + } + } + + $this->path = rtrim( $ftp['path'],'/' ); + + $this->log[] = 'Changing directory to '.$this->path; + + if ( ! @ftp_chdir( $this->verb,$this->path ) ) + throw new OpenRatException('ERROR_PUBLISH','unable CHDIR to directory: '.$this->path); + } + + + /** + * Kopieren einer Datei vom lokalen System auf den FTP-Server. + * + * @param String Quelle + * @param String Ziel + * @param int FTP-Mode (BINARY oder ASCII) + */ + public function put( $source,$dest ) + { + $dest = $this->path.'/'.$dest; + + $this->log .= "Copying file: $source -&gt; $dest ...\n"; + + $mode = FTP_BINARY; + $p = strrpos( basename($dest),'.' ); // Letzten Punkt suchen + + if ($p!==false) // Wennn letzten Punkt gefunden, dann dort aufteilen + { + $extension = substr( basename($dest),$p+1 ); + $type = config('mime-types',$extension); + if ( substr($type,0,5) == 'text/') + $mode = FTP_ASCII; + } + + Logger::debug("FTP PUT target:$dest mode:".(($mode==FTP_ASCII)?'ascii':'binary')); + + if ( !@ftp_put( $this->verb,$dest,$source,$mode ) ) + { + if ( !$this->mkdirs( dirname($dest) ) ) + return; // Fehler. + + ftp_chdir( $this->verb,$this->path ); + + if ( ! @ftp_put( $this->verb,$dest,$source,$mode ) ) + throw new OpenRatException('ERROR_PUBLISH', + "FTP PUT failed.\n". + "source : $source\n". + "destination: $dest"); + + } + } + + + + /** + * Private Methode zum rekursiven Anlegen von Verzeichnissen. + * + * @param String Pfad + * @return boolean true, wenn ok + */ + private function mkdirs( $strPath ) + { + if ( @ftp_chdir($this->verb,$strPath) ) + return true; // Verzeichnis existiert schon :) + + $pStrPath = dirname($strPath); + + if ( !$this->mkdirs($pStrPath) ) + return false; + + if ( ! @ftp_mkdir($this->verb,$strPath) ) + throw new OpenRatException('ERROR_PUBLISH',"failed to create remote directory: $strPath"); + + return true; + } + + + + /** + * Schliessen der FTP-Verbindung.<br> + * Sollte unbedingt aufgerufen werden, damit keine unn�tigen Sockets aufbleiben. + */ + public function close() + { + if ( ! @ftp_quit( $this->verb ) ) + { + // Closing not possible. + // Only logging. Maybe we could throw an Exception here? + Logger::warn('Failed to close FTP connection. Continueing...'); + return; + } + } +} + + ?> \ No newline at end of file diff --git a/modules/cms-publish/PublishPreview.class.php b/modules/cms-publish/PublishPreview.class.php @@ -37,10 +37,10 @@ class PublishPreview extends Publish case BaseObject::TYPEID_FILE: case BaseObject::TYPEID_IMAGE: case BaseObject::TYPEID_TEXT: - $inhalt = \Html::url('file','show',$to->objectid,$param); + $inhalt = \util\Html::url('file','show',$to->objectid,$param); break; case BaseObject::TYPEID_PAGE: - $inhalt = \Html::url('page','show',$to->objectid,$param); + $inhalt = \util\Html::url('page','show',$to->objectid,$param); break; case BaseObject::TYPEID_LINK: @@ -53,14 +53,14 @@ class PublishPreview extends Publish switch( $linkedObject->typeid ) { case BaseObject::TYPEID_FILE: - $inhalt = \Html::url('file','show',$link->linkedObjectId,$param); + $inhalt = \util\Html::url('file','show',$link->linkedObjectId,$param); break; case BaseObject::TYPEID_PAGE: - $inhalt = \Html::url('page','show',$link->linkedObjectId,$param); + $inhalt = \util\Html::url('page','show',$link->linkedObjectId,$param); break; case BaseObject::TYPEID_URL: - $inhalt = \Html::url('url','show',$link->linkedObjectId,$param); + $inhalt = \util\Html::url('url','show',$link->linkedObjectId,$param); break; default: $inhalt = 'Unknown link type: '.$linkedObject->typeid; diff --git a/modules/cms-publish/PublishPublic.class.php b/modules/cms-publish/PublishPublic.class.php @@ -9,11 +9,11 @@ use cms\model\Link; use cms\model\Page; use cms\model\Project; use cms\model\Url; -use FileUtils; +use util\FileUtils; use Ftp; use Logger; -use OpenRatException; -use Session; +use util\exception\OpenRatException; +use util\Session; diff --git a/modules/cms-publish/filter/JavascriptMinifierFilter.class.php b/modules/cms-publish/filter/JavascriptMinifierFilter.class.php @@ -4,7 +4,7 @@ namespace cms\publish\filter; -use JSqueeze; +use util\JSqueeze; class JavascriptMinifierFilter extends AbstractFilter { diff --git a/modules/cms-publish/filter/LessFilter.class.php b/modules/cms-publish/filter/LessFilter.class.php @@ -4,7 +4,7 @@ namespace cms\publish\filter; -use Less_Parser; +use \Less_Parser; class LessFilter extends AbstractFilter { diff --git a/modules/cms-ui/UI.class.php b/modules/cms-ui/UI.class.php @@ -7,14 +7,14 @@ use cms\action\RequestParams; use cms\Dispatcher; use DomainException; use Exception; -use Http; -use Less_Parser; +use util\Http; +use \Less_Parser; use Logger; use LogicException; use ObjectNotFoundException; -use OpenRatException; -use SecurityException; -use template_engine\TemplateEngine; +use util\exception\OpenRatException; +use util\exception\SecurityException; +use template_engine\engine\TemplateEngine; use template_engine\TemplateEngineInfo; diff --git a/modules/cms-ui/action/IndexAction.class.php b/modules/cms-ui/action/IndexAction.class.php @@ -9,12 +9,12 @@ use cms\model\User; use cms\model\Value; use Exception; use JSON; -use JSqueeze; -use Less_Parser; +use util\JSqueeze; +use \Less_Parser; use Logger; -use modules\util\UIUtils; +use util\UIUtils; use ObjectNotFoundException; -use Session; +use util\Session; use template_engine\TemplateEngineInfo; @@ -180,7 +180,7 @@ class IndexAction extends Action $css = array(); - $styleFiles = \FileUtils::readDir(OR_THEMES_DIR . 'default/style'); + $styleFiles = \util\FileUtils::readDir(OR_THEMES_DIR . 'default/style'); foreach( $styleFiles as $styleFile ) { if (substr($styleFile,-5) == '.less' ) $css[] = OR_THEMES_DIR . 'default/style'.'/'.substr($styleFile,0,-5); diff --git a/modules/cms-ui/action/TitleAction.class.php b/modules/cms-ui/action/TitleAction.class.php @@ -7,8 +7,8 @@ use cms\model\BaseObject; use cms\model\Language; use cms\model\Model; -use Session; -use \Html; +use util\Session; +use util\Html; // OpenRat Content Management System // Copyright (C) 2002-2009 Jan Dankert, jandankert@jandankert.de // diff --git a/modules/cms-ui/themes/default/layout/index.php b/modules/cms-ui/themes/default/layout/index.php @@ -1,5 +1,5 @@ <?php - extract($output); + use util\Html;extract($output); if (!defined('OR_VERSION')) die('Forbidden'); if (!headers_sent()) header('Content-Type: text/html; charset=UTF-8') ?><!DOCTYPE html> diff --git a/modules/configuration/ConfigurationLoader.class.php b/modules/configuration/ConfigurationLoader.class.php @@ -1,6 +1,7 @@ <?php use util\VariableResolver; +use util\YAML; /** diff --git a/modules/database/DbVersion.class.php b/modules/database/DbVersion.class.php @@ -19,7 +19,7 @@ namespace database { define('OR_DB_COLUMN_NOT_NULLABLE',false); - use Http; + use util\Http; abstract class DbVersion { diff --git a/modules/language/Language.class.php b/modules/language/Language.class.php @@ -3,7 +3,7 @@ namespace language; use LogicException; -use YAML; +use util\YAML; class Language { diff --git a/modules/template_engine/TemplateCompiler.php b/modules/template_engine/TemplateCompiler.php @@ -12,7 +12,7 @@ ini_set('display_startup_errors', 1); require('../../modules/autoload.php'); use template_engine\engine\TemplateEngine; - +use util\FileUtils; $dir = __DIR__.'/../../modules/cms-ui/themes/default/html/views'; diff --git a/modules/template_engine/components/XSDGenerator.php b/modules/template_engine/components/XSDGenerator.php @@ -3,6 +3,8 @@ * Using the Component classes and generating a XSD-File. */ +use util\FileUtils; + error_reporting(E_ALL); require('../../util/FileUtils.class.php'); diff --git a/modules/util/Api.class.php b/modules/util/Api.class.php @@ -15,6 +15,8 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +namespace util; + use cms\model\Folder; use cms\model\Project; @@ -29,10 +31,10 @@ use cms\model\Project; */ class Api { - var $output = ''; + var $output = ''; var $objectid = 0; var $page; - + function db() { return db_connection(); @@ -50,14 +52,14 @@ class Api return $this->objectid; } - function setObjectId( $objectid ) + function setObjectId($objectid) { $this->objectid = $objectid; } function getRootObjectId() { - $project = new Project( $this->page->projectid); + $project = new Project($this->page->projectid); return $project::getRootObjectId(); } @@ -68,29 +70,29 @@ class Api } - function execute( $code ) + function execute($code) { global $conf_tmpdir; - $code = "<?php\n".$code."\n?>"; + $code = "<?php\n" . $code . "\n?>"; + + $tmp = $conf_tmpdir . '/' . md5(microtime()) . '.tmp'; + $f = fopen($tmp, 'w'); + fwrite($f, $code); + fclose($f); - $tmp = $conf_tmpdir.'/'.md5(microtime()).'.tmp'; - $f = fopen( $tmp,'w' ); - fwrite( $f,$code ); - fclose( $f ); - - require( $tmp ); // Ausfuehren des temporaeren PHP-Codes + require($tmp); // Ausfuehren des temporaeren PHP-Codes - unlink( $tmp ); + unlink($tmp); $inhalt = Api::getOutput(); - $this->output( $inhalt ); - } - + $this->output($inhalt); + } + function delOutput() { $this->output = ''; } - - function output( $text ) + + function output($text) { $this->output .= $text; } diff --git a/modules/util/ArchiveTar.class.php b/modules/util/ArchiveTar.class.php @@ -1,397 +1,396 @@ -<?php -/* -======================================================================= -Name: - tar Class - -Author: - Josh Barger <joshb@npt.com> - -Description: - This class reads and writes Tape-Archive (TAR) Files and Gzip - compressed TAR files, which are mainly used on UNIX systems. - This class works on both windows AND unix systems, and does - NOT rely on external applications!! Woohoo! - -Usage: - Copyright (C) 2002 Josh Barger - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details at: - http://www.gnu.org/copyleft/lesser.html - - If you use this script in your application/website, please - send me an e-mail letting me know about it :) - -Bugs: - Please report any bugs you might find to my e-mail address - at joshb@npt.com. If you have already created a fix/patch - for the bug, please do send it to me so I can incorporate it into my release. - -Version History: - 1.0 04/10/2002 - InitialRelease - - 2.0 04/11/2002 - Merged both tarReader and tarWriter - classes into one - - Added support for gzipped tar files - Remember to name for .tar.gz or .tgz - if you use gzip compression! - :: THIS REQUIRES ZLIB EXTENSION :: - - Added additional comments to - functions to help users - - Added ability to remove files and - directories from archive - 2.1 04/12/2002 - Fixed serious bug in generating tar - - Created another example file - - Added check to make sure ZLIB is - installed before running GZIP - compression on TAR - 2.2 05/07/2002 - Added automatic detection of Gzipped - tar files (Thanks go to J�rgen Falch - for the idea) - - Changed "private" functions to have - special function names beginning with - two underscores -======================================================================= -*/ - - -class ArchiveTar -{ - // Unprocessed Archive Information - var $filename; - var $isGzipped; - var $tar_file; - - // Processed Archive Information - var $files; - var $directories; - var $numFiles; - var $numDirectories; - - - // Class Constructor -- Does nothing... - function tar() { - return true; - } - - - // Computes the unsigned Checksum of a file's header - // to try to ensure valid file - // PRIVATE ACCESS FUNCTION - function __computeUnsignedChecksum($bytestring) - { - $unsigned_chksum=0; - for($i=0; $i<512; $i++) - $unsigned_chksum += ord($bytestring[$i]); - for($i=0; $i<8; $i++) - $unsigned_chksum -= ord($bytestring[148 + $i]); - $unsigned_chksum += ord(" ") * 8; - - return $unsigned_chksum; - } - - - // Converts a NULL padded string to a non-NULL padded string - // PRIVATE ACCESS FUNCTION - function __parseNullPaddedString($string) - { - $position = strpos($string,chr(0)); - return substr($string,0,$position); - } - - - // This function parses the current TAR file - // PRIVATE ACCESS FUNCTION - function __parseTar() - { - // Read Files from archive - $this->numFiles=0; - $tar_length = strlen($this->tar_file); - $main_offset = 0; - while($main_offset < $tar_length) { - // If we read a block of 512 nulls, we are at the end of the archive - if(substr($this->tar_file,$main_offset,512) == str_repeat(chr(0),512)) - break; - - // Parse file name - $file_name = $this->__parseNullPaddedString(substr($this->tar_file,$main_offset,100)); - - // Parse the file mode - $file_mode = substr($this->tar_file,$main_offset + 100,8); - - // Parse the file user ID - $file_uid = octdec(substr($this->tar_file,$main_offset + 108,8)); - - // Parse the file group ID - $file_gid = octdec(substr($this->tar_file,$main_offset + 116,8)); - - // Parse the file size - $file_size = octdec(substr($this->tar_file,$main_offset + 124,12)); - - // Parse the file update time - unix timestamp format - $file_time = octdec(substr($this->tar_file,$main_offset + 136,12)); - - // Parse Checksum - $file_chksum = octdec(substr($this->tar_file,$main_offset + 148,6)); - - // Parse user name - $file_uname = $this->__parseNullPaddedString(substr($this->tar_file,$main_offset + 265,32)); - - // Parse Group name - $file_gname = $this->__parseNullPaddedString(substr($this->tar_file,$main_offset + 297,32)); - - // Make sure our file is valid - if($this->__computeUnsignedChecksum(substr($this->tar_file,$main_offset,512)) != $file_chksum) - return false; - - // Parse File Contents - $file_contents = substr($this->tar_file,$main_offset + 512,$file_size); - - /* ### Unused Header Information ### - $activeFile["typeflag"] = substr($this->tar_file,$main_offset + 156,1); - $activeFile["linkname"] = substr($this->tar_file,$main_offset + 157,100); - $activeFile["magic"] = substr($this->tar_file,$main_offset + 257,6); - $activeFile["version"] = substr($this->tar_file,$main_offset + 263,2); - $activeFile["devmajor"] = substr($this->tar_file,$main_offset + 329,8); - $activeFile["devminor"] = substr($this->tar_file,$main_offset + 337,8); - $activeFile["prefix"] = substr($this->tar_file,$main_offset + 345,155); - $activeFile["endheader"] = substr($this->tar_file,$main_offset + 500,12); - */ - - if($file_size > 0) { - // Increment number of files - $this->numFiles++; - - // Create us a new file in our array - $activeFile = &$this->files[]; - - // Asign Values - $activeFile["name"] = $file_name; - $activeFile["mode"] = $file_mode; - $activeFile["size"] = $file_size; - $activeFile["time"] = $file_time; - $activeFile["user_id"] = $file_uid; - $activeFile["group_id"] = $file_gid; - $activeFile["user_name"] = $file_uname; - $activeFile["group_name"] = $file_gname; - $activeFile["checksum"] = $file_chksum; - $activeFile["file"] = $file_contents; - - } else { - // Increment number of directories - $this->numDirectories++; - - // Create a new directory in our array - $activeDir = &$this->directories[]; - - // Assign values - $activeDir["name"] = $file_name; - $activeDir["mode"] = $file_mode; - $activeDir["time"] = $file_time; - $activeDir["user_id"] = $file_uid; - $activeDir["group_id"] = $file_gid; - $activeDir["user_name"] = $file_uname; - $activeDir["group_name"] = $file_gname; - $activeDir["checksum"] = $file_chksum; - } - - // Move our offset the number of blocks we have processed - $main_offset += 512 + (ceil($file_size / 512) * 512); - } - - return true; - } - - - // Read a non gzipped tar file in for processing - // PRIVATE ACCESS FUNCTION - function __readTar($filename='') - { - // Set the filename to load - // Read in the TAR file - - if($this->tar_file[0] == chr(31) && $this->tar_file[1] == chr(139) && $this->tar_file[2] == chr(8)) { - if(!function_exists("gzinflate")) - return false; - - $this->isGzipped = TRUE; - - $this->tar_file = gzinflate(substr($this->tar_file,10,-4)); - } - - // Parse the TAR file - $this->__parseTar(); - - return true; - } - - - // Generates a TAR file from the processed data - // PRIVATE ACCESS FUNCTION - function __generateTAR() - { - // Clear any data currently in $this->tar_file - unset($this->tar_file); - - // Generate Records for each directory, if we have directories - if($this->numDirectories > 0) { - foreach($this->directories as $key => $information) { - unset($header); - - // Generate tar header for this directory - // Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end - $header .= str_pad($information["name"],100,chr(0)); - $header .= str_pad(decoct($information["mode"]),7,"0",STR_PAD_LEFT) . chr(0); - $header .= str_pad(decoct($information["user_id"]),7,"0",STR_PAD_LEFT) . chr(0); - $header .= str_pad(decoct($information["group_id"]),7,"0",STR_PAD_LEFT) . chr(0); - $header .= str_pad(decoct(0),11,"0",STR_PAD_LEFT) . chr(0); - $header .= str_pad(decoct($information["time"]),11,"0",STR_PAD_LEFT) . chr(0); - $header .= str_repeat(" ",8); - $header .= "5"; - $header .= str_repeat(chr(0),100); - $header .= str_pad("ustar",6,chr(32)); - $header .= chr(32) . chr(0); - $header .= str_pad("",32,chr(0)); - $header .= str_pad("",32,chr(0)); - $header .= str_repeat(chr(0),8); - $header .= str_repeat(chr(0),8); - $header .= str_repeat(chr(0),155); - $header .= str_repeat(chr(0),12); - - // Compute header checksum - $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT); - for($i=0; $i<6; $i++) { - $header[(148 + $i)] = substr($checksum,$i,1); - } - $header[154] = chr(0); - $header[155] = chr(32); - - // Add new tar formatted data to tar file contents - $this->tar_file .= $header; - } - } - - // Generate Records for each file, if we have files (We should...) - if($this->numFiles > 0) - { - foreach($this->files as $key => $information) - { - unset($header); - $header = ''; - - // Generate the TAR header for this file - // Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end - $header .= str_pad($information["name"],100,chr(0)); - $header .= str_pad(decoct($information["mode"]),7,"0",STR_PAD_LEFT) . chr(0); - $header .= str_pad(decoct($information["user_id"]),7,"0",STR_PAD_LEFT) . chr(0); - $header .= str_pad(decoct($information["group_id"]),7,"0",STR_PAD_LEFT) . chr(0); - $header .= str_pad(decoct($information["size"]),11,"0",STR_PAD_LEFT) . chr(0); - $header .= str_pad(decoct($information["time"]),11,"0",STR_PAD_LEFT) . chr(0); - $header .= str_repeat(" ",8); - $header .= "0"; - $header .= str_repeat(chr(0),100); - $header .= str_pad("ustar",6,chr(32)); - $header .= chr(32) . chr(0); - $header .= str_pad($information["user_name"],32,chr(0)); // How do I get a file's user name from PHP? - $header .= str_pad($information["group_name"],32,chr(0)); // How do I get a file's group name from PHP? - $header .= str_repeat(chr(0),8); - $header .= str_repeat(chr(0),8); - $header .= str_repeat(chr(0),155); - $header .= str_repeat(chr(0),12); - - // Compute header checksum - $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT); - for($i=0; $i<6; $i++) - { - $header[(148 + $i)] = substr($checksum,$i,1); - } - $header[154] = chr(0); - $header[155] = chr(32); - - // Pad file contents to byte count divisible by 512 - $file_contents = str_pad($information["file"],(ceil($information["size"] / 512) * 512),chr(0)); - - // Add new tar formatted data to tar file contents - $this->tar_file .= $header . $file_contents; - } - } - - // Add 512 bytes of NULLs to designate EOF - $this->tar_file .= str_repeat(chr(0),512); - - return true; - } - - - // Open a TAR file - function openTAR($value) - { - // Clear any values from previous tar archives - unset($this->filename); - unset($this->isGzipped); - unset($this->tar_file); - unset($this->files); - unset($this->directories); - unset($this->numFiles); - unset($this->numDirectories); - - $this->filename = 'none'; - $this->tar_file = $value; - // Parse this file - $this->__readTar(); - - return true; - } - - - // Write the currently loaded tar archive to disk - function saveTar() - { - if(!$this->filename) - return false; - - // Write tar to current file using specified gzip compression - $this->toTar($this->filename,$this->isGzipped); - - return true; - } - - - // Saves tar archive to a different file than the current file - function toTar($filename,$useGzip) - { - if(!$filename) - return false; - - // Encode processed files into TAR file format - $this->__generateTar(); - - // GZ Compress the data if we need to - if($useGzip) { - // Make sure we have gzip support - if(!function_exists("gzencode")) - return false; - - $file = gzencode($this->tar_file); - } else { - $file = $this->tar_file; - } - - // Write the TAR file - $fp = fopen($filename,"wb"); - fwrite($fp,$file); - fclose($fp); - - return true; - } -} - +<?php +/* +======================================================================= +Name: + tar Class + +Author: + Josh Barger <joshb@npt.com> + +Description: + This class reads and writes Tape-Archive (TAR) Files and Gzip + compressed TAR files, which are mainly used on UNIX systems. + This class works on both windows AND unix systems, and does + NOT rely on external applications!! Woohoo! + +Usage: + Copyright (C) 2002 Josh Barger + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details at: + http://www.gnu.org/copyleft/lesser.html + + If you use this script in your application/website, please + send me an e-mail letting me know about it :) + +Bugs: + Please report any bugs you might find to my e-mail address + at joshb@npt.com. If you have already created a fix/patch + for the bug, please do send it to me so I can incorporate it into my release. + +Version History: + 1.0 04/10/2002 - InitialRelease + + 2.0 04/11/2002 - Merged both tarReader and tarWriter + classes into one + - Added support for gzipped tar files + Remember to name for .tar.gz or .tgz + if you use gzip compression! + :: THIS REQUIRES ZLIB EXTENSION :: + - Added additional comments to + functions to help users + - Added ability to remove files and + directories from archive + 2.1 04/12/2002 - Fixed serious bug in generating tar + - Created another example file + - Added check to make sure ZLIB is + installed before running GZIP + compression on TAR + 2.2 05/07/2002 - Added automatic detection of Gzipped + tar files (Thanks go to J�rgen Falch + for the idea) + - Changed "private" functions to have + special function names beginning with + two underscores +======================================================================= +*/ + + +namespace util; +class ArchiveTar +{ + // Unprocessed Archive Information + var $filename; + var $isGzipped; + var $tar_file; + + // Processed Archive Information + var $files; + var $directories; + var $numFiles; + var $numDirectories; + + + // Class Constructor -- Does nothing... + function tar() + { + return true; + } + + + // Computes the unsigned Checksum of a file's header + // to try to ensure valid file + // PRIVATE ACCESS FUNCTION + function __computeUnsignedChecksum($bytestring) + { + $unsigned_chksum = 0; + for ($i = 0; $i < 512; $i++) + $unsigned_chksum += ord($bytestring[$i]); + for ($i = 0; $i < 8; $i++) + $unsigned_chksum -= ord($bytestring[148 + $i]); + $unsigned_chksum += ord(" ") * 8; + + return $unsigned_chksum; + } + + + // Converts a NULL padded string to a non-NULL padded string + // PRIVATE ACCESS FUNCTION + function __parseNullPaddedString($string) + { + $position = strpos($string, chr(0)); + return substr($string, 0, $position); + } + + + // This function parses the current TAR file + // PRIVATE ACCESS FUNCTION + function __parseTar() + { + // Read Files from archive + $this->numFiles = 0; + $tar_length = strlen($this->tar_file); + $main_offset = 0; + while ($main_offset < $tar_length) { + // If we read a block of 512 nulls, we are at the end of the archive + if (substr($this->tar_file, $main_offset, 512) == str_repeat(chr(0), 512)) + break; + + // Parse file name + $file_name = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset, 100)); + + // Parse the file mode + $file_mode = substr($this->tar_file, $main_offset + 100, 8); + + // Parse the file user ID + $file_uid = octdec(substr($this->tar_file, $main_offset + 108, 8)); + + // Parse the file group ID + $file_gid = octdec(substr($this->tar_file, $main_offset + 116, 8)); + + // Parse the file size + $file_size = octdec(substr($this->tar_file, $main_offset + 124, 12)); + + // Parse the file update time - unix timestamp format + $file_time = octdec(substr($this->tar_file, $main_offset + 136, 12)); + + // Parse Checksum + $file_chksum = octdec(substr($this->tar_file, $main_offset + 148, 6)); + + // Parse user name + $file_uname = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset + 265, 32)); + + // Parse Group name + $file_gname = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset + 297, 32)); + + // Make sure our file is valid + if ($this->__computeUnsignedChecksum(substr($this->tar_file, $main_offset, 512)) != $file_chksum) + return false; + + // Parse File Contents + $file_contents = substr($this->tar_file, $main_offset + 512, $file_size); + + /* ### Unused Header Information ### + $activeFile["typeflag"] = substr($this->tar_file,$main_offset + 156,1); + $activeFile["linkname"] = substr($this->tar_file,$main_offset + 157,100); + $activeFile["magic"] = substr($this->tar_file,$main_offset + 257,6); + $activeFile["version"] = substr($this->tar_file,$main_offset + 263,2); + $activeFile["devmajor"] = substr($this->tar_file,$main_offset + 329,8); + $activeFile["devminor"] = substr($this->tar_file,$main_offset + 337,8); + $activeFile["prefix"] = substr($this->tar_file,$main_offset + 345,155); + $activeFile["endheader"] = substr($this->tar_file,$main_offset + 500,12); + */ + + if ($file_size > 0) { + // Increment number of files + $this->numFiles++; + + // Create us a new file in our array + $activeFile = &$this->files[]; + + // Asign Values + $activeFile["name"] = $file_name; + $activeFile["mode"] = $file_mode; + $activeFile["size"] = $file_size; + $activeFile["time"] = $file_time; + $activeFile["user_id"] = $file_uid; + $activeFile["group_id"] = $file_gid; + $activeFile["user_name"] = $file_uname; + $activeFile["group_name"] = $file_gname; + $activeFile["checksum"] = $file_chksum; + $activeFile["file"] = $file_contents; + + } else { + // Increment number of directories + $this->numDirectories++; + + // Create a new directory in our array + $activeDir = &$this->directories[]; + + // Assign values + $activeDir["name"] = $file_name; + $activeDir["mode"] = $file_mode; + $activeDir["time"] = $file_time; + $activeDir["user_id"] = $file_uid; + $activeDir["group_id"] = $file_gid; + $activeDir["user_name"] = $file_uname; + $activeDir["group_name"] = $file_gname; + $activeDir["checksum"] = $file_chksum; + } + + // Move our offset the number of blocks we have processed + $main_offset += 512 + (ceil($file_size / 512) * 512); + } + + return true; + } + + + // Read a non gzipped tar file in for processing + // PRIVATE ACCESS FUNCTION + function __readTar($filename = '') + { + // Set the filename to load + // Read in the TAR file + + if ($this->tar_file[0] == chr(31) && $this->tar_file[1] == chr(139) && $this->tar_file[2] == chr(8)) { + if (!function_exists("gzinflate")) + return false; + + $this->isGzipped = TRUE; + + $this->tar_file = gzinflate(substr($this->tar_file, 10, -4)); + } + + // Parse the TAR file + $this->__parseTar(); + + return true; + } + + + // Generates a TAR file from the processed data + // PRIVATE ACCESS FUNCTION + function __generateTAR() + { + // Clear any data currently in $this->tar_file + unset($this->tar_file); + + // Generate Records for each directory, if we have directories + if ($this->numDirectories > 0) { + foreach ($this->directories as $key => $information) { + unset($header); + + // Generate tar header for this directory + // Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end + $header .= str_pad($information["name"], 100, chr(0)); + $header .= str_pad(decoct($information["mode"]), 7, "0", STR_PAD_LEFT) . chr(0); + $header .= str_pad(decoct($information["user_id"]), 7, "0", STR_PAD_LEFT) . chr(0); + $header .= str_pad(decoct($information["group_id"]), 7, "0", STR_PAD_LEFT) . chr(0); + $header .= str_pad(decoct(0), 11, "0", STR_PAD_LEFT) . chr(0); + $header .= str_pad(decoct($information["time"]), 11, "0", STR_PAD_LEFT) . chr(0); + $header .= str_repeat(" ", 8); + $header .= "5"; + $header .= str_repeat(chr(0), 100); + $header .= str_pad("ustar", 6, chr(32)); + $header .= chr(32) . chr(0); + $header .= str_pad("", 32, chr(0)); + $header .= str_pad("", 32, chr(0)); + $header .= str_repeat(chr(0), 8); + $header .= str_repeat(chr(0), 8); + $header .= str_repeat(chr(0), 155); + $header .= str_repeat(chr(0), 12); + + // Compute header checksum + $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)), 6, "0", STR_PAD_LEFT); + for ($i = 0; $i < 6; $i++) { + $header[(148 + $i)] = substr($checksum, $i, 1); + } + $header[154] = chr(0); + $header[155] = chr(32); + + // Add new tar formatted data to tar file contents + $this->tar_file .= $header; + } + } + + // Generate Records for each file, if we have files (We should...) + if ($this->numFiles > 0) { + foreach ($this->files as $key => $information) { + unset($header); + $header = ''; + + // Generate the TAR header for this file + // Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end + $header .= str_pad($information["name"], 100, chr(0)); + $header .= str_pad(decoct($information["mode"]), 7, "0", STR_PAD_LEFT) . chr(0); + $header .= str_pad(decoct($information["user_id"]), 7, "0", STR_PAD_LEFT) . chr(0); + $header .= str_pad(decoct($information["group_id"]), 7, "0", STR_PAD_LEFT) . chr(0); + $header .= str_pad(decoct($information["size"]), 11, "0", STR_PAD_LEFT) . chr(0); + $header .= str_pad(decoct($information["time"]), 11, "0", STR_PAD_LEFT) . chr(0); + $header .= str_repeat(" ", 8); + $header .= "0"; + $header .= str_repeat(chr(0), 100); + $header .= str_pad("ustar", 6, chr(32)); + $header .= chr(32) . chr(0); + $header .= str_pad($information["user_name"], 32, chr(0)); // How do I get a file's user name from PHP? + $header .= str_pad($information["group_name"], 32, chr(0)); // How do I get a file's group name from PHP? + $header .= str_repeat(chr(0), 8); + $header .= str_repeat(chr(0), 8); + $header .= str_repeat(chr(0), 155); + $header .= str_repeat(chr(0), 12); + + // Compute header checksum + $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)), 6, "0", STR_PAD_LEFT); + for ($i = 0; $i < 6; $i++) { + $header[(148 + $i)] = substr($checksum, $i, 1); + } + $header[154] = chr(0); + $header[155] = chr(32); + + // Pad file contents to byte count divisible by 512 + $file_contents = str_pad($information["file"], (ceil($information["size"] / 512) * 512), chr(0)); + + // Add new tar formatted data to tar file contents + $this->tar_file .= $header . $file_contents; + } + } + + // Add 512 bytes of NULLs to designate EOF + $this->tar_file .= str_repeat(chr(0), 512); + + return true; + } + + + // Open a TAR file + function openTAR($value) + { + // Clear any values from previous tar archives + unset($this->filename); + unset($this->isGzipped); + unset($this->tar_file); + unset($this->files); + unset($this->directories); + unset($this->numFiles); + unset($this->numDirectories); + + $this->filename = 'none'; + $this->tar_file = $value; + // Parse this file + $this->__readTar(); + + return true; + } + + + // Write the currently loaded tar archive to disk + function saveTar() + { + if (!$this->filename) + return false; + + // Write tar to current file using specified gzip compression + $this->toTar($this->filename, $this->isGzipped); + + return true; + } + + + // Saves tar archive to a different file than the current file + function toTar($filename, $useGzip) + { + if (!$filename) + return false; + + // Encode processed files into TAR file format + $this->__generateTar(); + + // GZ Compress the data if we need to + if ($useGzip) { + // Make sure we have gzip support + if (!function_exists("gzencode")) + return false; + + $file = gzencode($this->tar_file); + } else { + $file = $this->tar_file; + } + + // Write the TAR file + $fp = fopen($filename, "wb"); + fwrite($fp, $file); + fclose($fp); + + return true; + } +} + ?> \ No newline at end of file diff --git a/modules/util/ArchiveUnzip.class.php b/modules/util/ArchiveUnzip.class.php @@ -1,447 +1,451 @@ -<?php -// 28/11/2005 (2.4) -// - dUnzip2 is now compliant with wrong placed "Data Description", made by some compressors, -// like the classes ZipLib and ZipLib2 by 'Hasin Hayder'. Thanks to Ricardo Parreno for pointing it. -// 09/11/2005 (2.3) -// - Added optional parameter '$stopOnFile' on method 'getList()'. -// If given, file listing will stop when find given filename. (Useful to open and unzip an exact file) -// 06/11/2005 (2.21) -// - Added support to PK00 file format (Packed to Removable Disk) (thanks to Lito [PHPfileNavigator]) -// - Method 'getExtraInfo': If requested file doesn't exist, return FALSE instead of Array() -// 31/10/2005 (2.2) -// - Removed redundant 'file_name' on centralDirs declaration (thanks to Lito [PHPfileNavigator]) -// - Fixed redeclaration of file_put_contents when in PHP4 (not returning true) - -############################################################## -# Class dUnzip2 v2.4 -# -# Author: Alexandre Tedeschi (d) -# E-Mail: alexandrebr at gmail dot com -# Londrina - PR / Brazil -# -# Objective: -# This class allows programmer to easily unzip files on the fly. -# -# Requirements: -# This class requires extension ZLib Enabled. It is default -# for most site hosts around the world, and for the PHP Win32 dist. -# -# To do: -# * Error handling -# * Write a PHP-Side gzinflate, to completely avoid any external extensions -# * Write other decompress algorithms -# -# If you modify this class, or have any ideas to improve it, please contact me! -# You are allowed to redistribute this class, if you keep my name and contact e-mail on it. -############################################################## - -class ArchiveUnzip{ - - // Public - var $files = array(); - var $value = ''; - var $fileName; - var $compressedList; // You will problably use only this one! - var $centralDirList; // Central dir list... It's a kind of 'extra attributes' for a set of files - var $endOfCentral; // End of central dir, contains ZIP Comments - var $debug; - - // Private - var $fh; - var $zipSignature = "\x50\x4b\x03\x04"; // local file header signature - var $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature - var $dirSignatureE= "\x50\x4b\x05\x06"; // end of central dir signature - - // Public - Function __construct() - { - $this->compressedList = - $this->centralDirList = - $this->endOfCentral = Array(); - } - - function open( $value ) - { - $this->fileName = tempnam('/tmp','unzip'); -// echo $this->fileName; - $fo = fopen( $this->fileName,'w'); - fwrite($fo,$value); - $this->unzipAll(); - } - - - Function getList($stopOnFile=false){ - if(sizeof($this->compressedList)){ - $this->debugMsg(1, "Returning already loaded file list."); - return $this->compressedList; - } - - // Open file, and set file handler - $fh = fopen($this->fileName, "r"); - $this->fh = &$fh; - if(!$fh){ - $this->debugMsg(2, "Failed to load file."); - return false; - } - - // Loop the file, looking for files and folders - $ddTry = false; - fseek($fh, 0); - for(;;){ - // Check if the signature is valid... - $signature = fread($fh, 4); - if(feof($fh)){ -# $this->debugMsg(1, "Reached end of file"); - break; - } - - // If signature is a 'Packed to Removable Disk', just ignore it and move to the next. - if($signature == 'PK00'){ - $this->debugMsg(1, "Found PK00: Packed to Removable Disk"); - continue; - } - - // If signature of a 'Local File Header' - if($signature == $this->zipSignature){ - # $this->debugMsg(1, "Zip Signature!"); - - // Get information about the zipped file - $file['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract - $file['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag - $file['compression_method'] = unpack("v", fread($fh, 2)); // compression method - $file['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time - $file['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date - $file['crc-32'] = fread($fh, 4); // crc-32 - $file['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size - $file['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size - $fileNameLength = unpack("v", fread($fh, 2)); // filename length - $extraFieldLength = unpack("v", fread($fh, 2)); // extra field length - $file['file_name'] = fread($fh, $fileNameLength[1]); // filename - $file['extra_field'] = $extraFieldLength[1]?fread($fh, $extraFieldLength[1]):''; // extra field - $file['contents-startOffset']= ftell($fh); - - // Bypass the whole compressed contents, and look for the next file - fseek($fh, $file['compressed_size'][1], SEEK_CUR); - - // Convert the date and time, from MS-DOS format to UNIX Timestamp - $BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT); - $BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT); - $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980; - $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4)); - $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5)); - $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5)); - $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6)); - $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5)); - - // Mount file table - $this->compressedList[$file['file_name']] = Array( - 'file_name' =>$file['file_name'], - 'compression_method'=>$file['compression_method'][1], - 'version_needed' =>$file['version_needed'][1], - 'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY), - 'crc-32' =>str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT). - str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT). - str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT). - str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT), - 'compressed_size' =>$file['compressed_size'][1], - 'uncompressed_size' =>$file['uncompressed_size'][1], - 'extra_field' =>$file['extra_field'], - 'general_bit_flag' =>str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT), - 'contents-startOffset'=>$file['contents-startOffset'] - ); - - if($stopOnFile) if($file['file_name'] == $stopOnFile){ - $this->debugMsg(1, "Stopping on file..."); - break; - } - } - - // If signature of a 'Central Directory Structure' - elseif($signature == $this->dirSignature){ - # $this->debugMsg(1, "Dir Signature!"); - - $dir['version_madeby'] = unpack("v", fread($fh, 2)); // version made by - $dir['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract - $dir['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag - $dir['compression_method'] = unpack("v", fread($fh, 2)); // compression method - $dir['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time - $dir['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date - $dir['crc-32'] = fread($fh, 4); // crc-32 - $dir['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size - $dir['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size - $fileNameLength = unpack("v", fread($fh, 2)); // filename length - $extraFieldLength = unpack("v", fread($fh, 2)); // extra field length - $fileCommentLength = unpack("v", fread($fh, 2)); // file comment length - $dir['disk_number_start'] = unpack("v", fread($fh, 2)); // disk number start - $dir['internal_attributes'] = unpack("v", fread($fh, 2)); // internal file attributes-byte1 - $dir['external_attributes1']= unpack("v", fread($fh, 2)); // external file attributes-byte2 - $dir['external_attributes2']= unpack("v", fread($fh, 2)); // external file attributes - $dir['relative_offset'] = unpack("V", fread($fh, 4)); // relative offset of local header - $dir['file_name'] = fread($fh, $fileNameLength[1]); // filename - $dir['extra_field'] = $extraFieldLength[1] ?fread($fh, $extraFieldLength[1]) :''; // extra field - $dir['file_comment'] = $fileCommentLength[1]?fread($fh, $fileCommentLength[1]):''; // file comment - - // Convert the date and time, from MS-DOS format to UNIX Timestamp - $BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT); - $BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT); - $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980; - $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4)); - $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5)); - $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5)); - $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6)); - $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5)); - - $this->centralDirList[$dir['file_name']] = Array( - 'version_madeby'=>$dir['version_madeby'][1], - 'version_needed'=>$dir['version_needed'][1], - 'general_bit_flag'=>str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT), - 'compression_method'=>$dir['compression_method'][1], - 'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY), - 'crc-32' =>str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT). - str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT). - str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT). - str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT), - 'compressed_size'=>$dir['compressed_size'][1], - 'uncompressed_size'=>$dir['uncompressed_size'][1], - 'disk_number_start'=>$dir['disk_number_start'][1], - 'internal_attributes'=>$dir['internal_attributes'][1], - 'external_attributes1'=>$dir['external_attributes1'][1], - 'external_attributes2'=>$dir['external_attributes2'][1], - 'relative_offset'=>$dir['relative_offset'][1], - 'file_name'=>$dir['file_name'], - 'extra_field'=>$dir['extra_field'], - 'file_comment'=>$dir['file_comment'], - ); - } - - elseif($signature == $this->dirSignatureE){ - # $this->debugMsg(1, "EOF Dir Signature!"); - - $eodir['disk_number_this'] = unpack("v", fread($fh, 2)); // number of this disk - $eodir['disk_number'] = unpack("v", fread($fh, 2)); // number of the disk with the start of the central directory - $eodir['total_entries_this'] = unpack("v", fread($fh, 2)); // total number of entries in the central dir on this disk - $eodir['total_entries'] = unpack("v", fread($fh, 2)); // total number of entries in - $eodir['size_of_cd'] = unpack("V", fread($fh, 4)); // size of the central directory - $eodir['offset_start_cd'] = unpack("V", fread($fh, 4)); // offset of start of central directory with respect to the starting disk number - $zipFileCommentLenght = unpack("v", fread($fh, 2)); // zipfile comment length - $eodir['zipfile_comment'] = $zipFileCommentLenght[1]?fread($fh, $zipFileCommentLenght[1]):''; // zipfile comment - $this->endOfCentral = Array( - 'disk_number_this'=>$eodir['disk_number_this'][1], - 'disk_number'=>$eodir['disk_number'][1], - 'total_entries_this'=>$eodir['total_entries_this'][1], - 'total_entries'=>$eodir['total_entries'][1], - 'size_of_cd'=>$eodir['size_of_cd'][1], - 'offset_start_cd'=>$eodir['offset_start_cd'][1], - 'zipfile_comment'=>$eodir['zipfile_comment'], - ); - } - else{ - if(!$ddTry){ - $this->debugMsg(1, "Unexpected header. Trying to detect wrong placed 'Data Descriptor'...\n"); - $ddTry = true; - fseek($fh, 12-4, SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4) - continue; - } - $this->debugMsg(1, "Unexpected header, ending loop at offset ".ftell($fh)); - break; - } - $ddTry = false; - } - - if($this->debug){ - #------- Debug compressedList - $kkk = 0; - echo "<table border='0' style='font: 11px Verdana; border: 1px solid #000'>"; - foreach($this->compressedList as $fileName=>$item){ - if(!$kkk && $kkk=1){ - echo "<tr style='background: #ADA'>"; - foreach($item as $fieldName=>$value) - echo "<td>$fieldName</td>"; - echo '</tr>'; - } - echo "<tr style='background: #CFC'>"; - foreach($item as $fieldName=>$value){ - if($fieldName == 'lastmod_datetime') - echo "<td title='$fieldName' nowrap='nowrap'>".date("d/m/Y H:i:s", $value)."</td>"; - else - echo "<td title='$fieldName' nowrap='nowrap'>$value</td>"; - } - echo "</tr>"; - } - echo "</table>"; - - #------- Debug centralDirList - $kkk = 0; - if(sizeof($this->centralDirList)){ - echo "<table border='0' style='font: 11px Verdana; border: 1px solid #000'>"; - foreach($this->centralDirList as $fileName=>$item){ - if(!$kkk && $kkk=1){ - echo "<tr style='background: #AAD'>"; - foreach($item as $fieldName=>$value) - echo "<td>$fieldName</td>"; - echo '</tr>'; - } - echo "<tr style='background: #CCF'>"; - foreach($item as $fieldName=>$value){ - if($fieldName == 'lastmod_datetime') - echo "<td title='$fieldName' nowrap='nowrap'>".date("d/m/Y H:i:s", $value)."</td>"; - else - echo "<td title='$fieldName' nowrap='nowrap'>$value</td>"; - } - echo "</tr>"; - } - echo "</table>"; - } - - #------- Debug endOfCentral - $kkk = 0; - if(sizeof($this->endOfCentral)){ - echo "<table border='0' style='font: 11px Verdana' style='border: 1px solid #000'>"; - echo "<tr style='background: #DAA'><td colspan='2'>dUnzip - End of file</td></tr>"; - foreach($this->endOfCentral as $field=>$value){ - echo "<tr>"; - echo "<td style='background: #FCC'>$field</td>"; - echo "<td style='background: #FDD'>$value</td>"; - echo "</tr>"; - } - echo "</table>"; - } - } - - return $this->compressedList; - } - - - Function getExtraInfo($compressedFileName) - { - return - isset($this->centralDirList[$compressedFileName])? - $this->centralDirList[$compressedFileName]: - false; - } - - - Function getZipInfo($detail=false) - { - return $detail? - $this->endOfCentral[$detail]: - $this->endOfCentral; - } - - - Function unzip($compressedFileName, $targetFileName=false){ - $fdetails = &$this->compressedList[$compressedFileName]; - - if(!sizeof($this->compressedList)){ - $this->debugMsg(1, "Trying to unzip before loading file list... Loading it!"); - $this->getList(false, $compressedFileName); - } - if(!isset($this->compressedList[$compressedFileName])){ - $this->debugMsg(2, "File '<b>$compressedFileName</b>' is not compressed in the zip."); - return false; - } - if(substr($compressedFileName, -1) == "/"){ - $this->debugMsg(2, "Trying to unzip a folder name '<b>$compressedFileName</b>'."); - return false; - } - if(!$fdetails['uncompressed_size']){ - $this->debugMsg(1, "File '<b>$compressedFileName</b>' is empty."); - return ""; - } - - fseek($this->fh, $fdetails['contents-startOffset']); - return $this->uncompress( - fread($this->fh, $fdetails['compressed_size']), - $fdetails['compression_method'], - $fdetails['uncompressed_size'] ); - } - - - Function unzipAll($targetDir=false, $baseDir="", $maintainStructure=true, $chmod=false){ - if($targetDir === false) - $targetDir = dirname(__FILE__)."/"; - - $lista = $this->getList(); - if(sizeof($lista)) foreach($lista as $fileName=>$trash){ - $dirname = dirname($fileName); - $outDN = "$targetDir/$dirname"; - - if(substr($dirname, 0, strlen($baseDir)) != $baseDir) - continue; - - if(!is_dir($outDN) && $maintainStructure){ - $str = ""; - $folders = explode("/", $dirname); - foreach($folders as $folder){ - $str = $str?"$str/$folder":$folder; - if(!is_dir("$targetDir/$str")){ - $this->debugMsg(1, "Creating folder: $targetDir/$str"); - mkdir("$targetDir/$str"); - if($chmod) - chmod("$targetDir/$str", $chmod); - } - } - } - if(substr($fileName, -1, 1) == "/") - continue; - - $maintainStructure? - $this->unzip($fileName, "$targetDir/$fileName"): - $this->unzip($fileName, "$targetDir/".basename($fileName)); - - if($chmod) - chmod($maintainStructure?"$targetDir/$fileName":"$targetDir/".basename($fileName), $chmod); - } - } - - Function close(){ // Free the file resource - if($this->fh) - fclose($this->fh); - } - - // Private (you should NOT call these methods): - Function uncompress($content, $mode, $uncompressedSize, $targetFileName=false){ - switch($mode){ - case 0: - // Not compressed - return $content; - case 1: - $this->debugMsg(2, "Shrunk mode is not supported... yet?"); - return false; - case 2: - case 3: - case 4: - case 5: - $this->debugMsg(2, "Compression factor ".($mode-1)." is not supported... yet?"); - return false; - case 6: - $this->debugMsg(2, "Implode is not supported... yet?"); - return false; - case 7: - $this->debugMsg(2, "Tokenizing compression algorithm is not supported... yet?"); - return false; - case 8: - // Deflate - return gzinflate($content, $uncompressedSize); - case 9: - $this->debugMsg(2, "Enhanced Deflating is not supported... yet?"); - return false; - case 10: - $this->debugMsg(2, "PKWARE Date Compression Library Impoloding is not supported... yet?"); - return false; - default: - $this->debugMsg(2, "Unknown uncompress method: $mode"); - return false; - } - } - - - Function debugMsg($level, $string){ - if($this->debug) - if($level == 1) - echo "<b style='color: #777'>dUnzip2:</b> $string<br>"; - if($level == 2) - echo "<b style='color: #F00'>dUnzip2:</b> $string<br>"; - } -} +<?php +// 28/11/2005 (2.4) +// - dUnzip2 is now compliant with wrong placed "Data Description", made by some compressors, +// like the classes ZipLib and ZipLib2 by 'Hasin Hayder'. Thanks to Ricardo Parreno for pointing it. +// 09/11/2005 (2.3) +// - Added optional parameter '$stopOnFile' on method 'getList()'. +// If given, file listing will stop when find given filename. (Useful to open and unzip an exact file) +// 06/11/2005 (2.21) +// - Added support to PK00 file format (Packed to Removable Disk) (thanks to Lito [PHPfileNavigator]) +// - Method 'getExtraInfo': If requested file doesn't exist, return FALSE instead of Array() +// 31/10/2005 (2.2) +// - Removed redundant 'file_name' on centralDirs declaration (thanks to Lito [PHPfileNavigator]) +// - Fixed redeclaration of file_put_contents when in PHP4 (not returning true) + +############################################################## +# Class dUnzip2 v2.4 +# +# Author: Alexandre Tedeschi (d) +# E-Mail: alexandrebr at gmail dot com +# Londrina - PR / Brazil +# +# Objective: +# This class allows programmer to easily unzip files on the fly. +# +# Requirements: +# This class requires extension ZLib Enabled. It is default +# for most site hosts around the world, and for the PHP Win32 dist. +# +# To do: +# * Error handling +# * Write a PHP-Side gzinflate, to completely avoid any external extensions +# * Write other decompress algorithms +# +# If you modify this class, or have any ideas to improve it, please contact me! +# You are allowed to redistribute this class, if you keep my name and contact e-mail on it. +############################################################## + +namespace util; +class ArchiveUnzip +{ + + // Public + var $files = array(); + var $value = ''; + var $fileName; + var $compressedList; // You will problably use only this one! + var $centralDirList; // Central dir list... It's a kind of 'extra attributes' for a set of files + var $endOfCentral; // End of central dir, contains ZIP Comments + var $debug; + + // Private + var $fh; + var $zipSignature = "\x50\x4b\x03\x04"; // local file header signature + var $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature + var $dirSignatureE = "\x50\x4b\x05\x06"; // end of central dir signature + + // Public + Function __construct() + { + $this->compressedList = + $this->centralDirList = + $this->endOfCentral = Array(); + } + + function open($value) + { + $this->fileName = tempnam('/tmp', 'unzip'); +// echo $this->fileName; + $fo = fopen($this->fileName, 'w'); + fwrite($fo, $value); + $this->unzipAll(); + } + + + Function getList($stopOnFile = false) + { + if (sizeof($this->compressedList)) { + $this->debugMsg(1, "Returning already loaded file list."); + return $this->compressedList; + } + + // Open file, and set file handler + $fh = fopen($this->fileName, "r"); + $this->fh = &$fh; + if (!$fh) { + $this->debugMsg(2, "Failed to load file."); + return false; + } + + // Loop the file, looking for files and folders + $ddTry = false; + fseek($fh, 0); + for (; ;) { + // Check if the signature is valid... + $signature = fread($fh, 4); + if (feof($fh)) { +# $this->debugMsg(1, "Reached end of file"); + break; + } + + // If signature is a 'Packed to Removable Disk', just ignore it and move to the next. + if ($signature == 'PK00') { + $this->debugMsg(1, "Found PK00: Packed to Removable Disk"); + continue; + } + + // If signature of a 'Local File Header' + if ($signature == $this->zipSignature) { + # $this->debugMsg(1, "Zip Signature!"); + + // Get information about the zipped file + $file['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract + $file['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag + $file['compression_method'] = unpack("v", fread($fh, 2)); // compression method + $file['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time + $file['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date + $file['crc-32'] = fread($fh, 4); // crc-32 + $file['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size + $file['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size + $fileNameLength = unpack("v", fread($fh, 2)); // filename length + $extraFieldLength = unpack("v", fread($fh, 2)); // extra field length + $file['file_name'] = fread($fh, $fileNameLength[1]); // filename + $file['extra_field'] = $extraFieldLength[1] ? fread($fh, $extraFieldLength[1]) : ''; // extra field + $file['contents-startOffset'] = ftell($fh); + + // Bypass the whole compressed contents, and look for the next file + fseek($fh, $file['compressed_size'][1], SEEK_CUR); + + // Convert the date and time, from MS-DOS format to UNIX Timestamp + $BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT); + $BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT); + $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7)) + 1980; + $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4)); + $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5)); + $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5)); + $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6)); + $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5)); + + // Mount file table + $this->compressedList[$file['file_name']] = Array( + 'file_name' => $file['file_name'], + 'compression_method' => $file['compression_method'][1], + 'version_needed' => $file['version_needed'][1], + 'lastmod_datetime' => mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY), + 'crc-32' => str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT) . + str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT) . + str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT) . + str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT), + 'compressed_size' => $file['compressed_size'][1], + 'uncompressed_size' => $file['uncompressed_size'][1], + 'extra_field' => $file['extra_field'], + 'general_bit_flag' => str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT), + 'contents-startOffset' => $file['contents-startOffset'] + ); + + if ($stopOnFile) if ($file['file_name'] == $stopOnFile) { + $this->debugMsg(1, "Stopping on file..."); + break; + } + } // If signature of a 'Central Directory Structure' + elseif ($signature == $this->dirSignature) { + # $this->debugMsg(1, "Dir Signature!"); + + $dir['version_madeby'] = unpack("v", fread($fh, 2)); // version made by + $dir['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract + $dir['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag + $dir['compression_method'] = unpack("v", fread($fh, 2)); // compression method + $dir['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time + $dir['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date + $dir['crc-32'] = fread($fh, 4); // crc-32 + $dir['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size + $dir['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size + $fileNameLength = unpack("v", fread($fh, 2)); // filename length + $extraFieldLength = unpack("v", fread($fh, 2)); // extra field length + $fileCommentLength = unpack("v", fread($fh, 2)); // file comment length + $dir['disk_number_start'] = unpack("v", fread($fh, 2)); // disk number start + $dir['internal_attributes'] = unpack("v", fread($fh, 2)); // internal file attributes-byte1 + $dir['external_attributes1'] = unpack("v", fread($fh, 2)); // external file attributes-byte2 + $dir['external_attributes2'] = unpack("v", fread($fh, 2)); // external file attributes + $dir['relative_offset'] = unpack("V", fread($fh, 4)); // relative offset of local header + $dir['file_name'] = fread($fh, $fileNameLength[1]); // filename + $dir['extra_field'] = $extraFieldLength[1] ? fread($fh, $extraFieldLength[1]) : ''; // extra field + $dir['file_comment'] = $fileCommentLength[1] ? fread($fh, $fileCommentLength[1]) : ''; // file comment + + // Convert the date and time, from MS-DOS format to UNIX Timestamp + $BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT); + $BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT); + $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7)) + 1980; + $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4)); + $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5)); + $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5)); + $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6)); + $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5)); + + $this->centralDirList[$dir['file_name']] = Array( + 'version_madeby' => $dir['version_madeby'][1], + 'version_needed' => $dir['version_needed'][1], + 'general_bit_flag' => str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT), + 'compression_method' => $dir['compression_method'][1], + 'lastmod_datetime' => mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY), + 'crc-32' => str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT) . + str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT) . + str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT) . + str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT), + 'compressed_size' => $dir['compressed_size'][1], + 'uncompressed_size' => $dir['uncompressed_size'][1], + 'disk_number_start' => $dir['disk_number_start'][1], + 'internal_attributes' => $dir['internal_attributes'][1], + 'external_attributes1' => $dir['external_attributes1'][1], + 'external_attributes2' => $dir['external_attributes2'][1], + 'relative_offset' => $dir['relative_offset'][1], + 'file_name' => $dir['file_name'], + 'extra_field' => $dir['extra_field'], + 'file_comment' => $dir['file_comment'], + ); + } elseif ($signature == $this->dirSignatureE) { + # $this->debugMsg(1, "EOF Dir Signature!"); + + $eodir['disk_number_this'] = unpack("v", fread($fh, 2)); // number of this disk + $eodir['disk_number'] = unpack("v", fread($fh, 2)); // number of the disk with the start of the central directory + $eodir['total_entries_this'] = unpack("v", fread($fh, 2)); // total number of entries in the central dir on this disk + $eodir['total_entries'] = unpack("v", fread($fh, 2)); // total number of entries in + $eodir['size_of_cd'] = unpack("V", fread($fh, 4)); // size of the central directory + $eodir['offset_start_cd'] = unpack("V", fread($fh, 4)); // offset of start of central directory with respect to the starting disk number + $zipFileCommentLenght = unpack("v", fread($fh, 2)); // zipfile comment length + $eodir['zipfile_comment'] = $zipFileCommentLenght[1] ? fread($fh, $zipFileCommentLenght[1]) : ''; // zipfile comment + $this->endOfCentral = Array( + 'disk_number_this' => $eodir['disk_number_this'][1], + 'disk_number' => $eodir['disk_number'][1], + 'total_entries_this' => $eodir['total_entries_this'][1], + 'total_entries' => $eodir['total_entries'][1], + 'size_of_cd' => $eodir['size_of_cd'][1], + 'offset_start_cd' => $eodir['offset_start_cd'][1], + 'zipfile_comment' => $eodir['zipfile_comment'], + ); + } else { + if (!$ddTry) { + $this->debugMsg(1, "Unexpected header. Trying to detect wrong placed 'Data Descriptor'...\n"); + $ddTry = true; + fseek($fh, 12 - 4, SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4) + continue; + } + $this->debugMsg(1, "Unexpected header, ending loop at offset " . ftell($fh)); + break; + } + $ddTry = false; + } + + if ($this->debug) { + #------- Debug compressedList + $kkk = 0; + echo "<table border='0' style='font: 11px Verdana; border: 1px solid #000'>"; + foreach ($this->compressedList as $fileName => $item) { + if (!$kkk && $kkk = 1) { + echo "<tr style='background: #ADA'>"; + foreach ($item as $fieldName => $value) + echo "<td>$fieldName</td>"; + echo '</tr>'; + } + echo "<tr style='background: #CFC'>"; + foreach ($item as $fieldName => $value) { + if ($fieldName == 'lastmod_datetime') + echo "<td title='$fieldName' nowrap='nowrap'>" . date("d/m/Y H:i:s", $value) . "</td>"; + else + echo "<td title='$fieldName' nowrap='nowrap'>$value</td>"; + } + echo "</tr>"; + } + echo "</table>"; + + #------- Debug centralDirList + $kkk = 0; + if (sizeof($this->centralDirList)) { + echo "<table border='0' style='font: 11px Verdana; border: 1px solid #000'>"; + foreach ($this->centralDirList as $fileName => $item) { + if (!$kkk && $kkk = 1) { + echo "<tr style='background: #AAD'>"; + foreach ($item as $fieldName => $value) + echo "<td>$fieldName</td>"; + echo '</tr>'; + } + echo "<tr style='background: #CCF'>"; + foreach ($item as $fieldName => $value) { + if ($fieldName == 'lastmod_datetime') + echo "<td title='$fieldName' nowrap='nowrap'>" . date("d/m/Y H:i:s", $value) . "</td>"; + else + echo "<td title='$fieldName' nowrap='nowrap'>$value</td>"; + } + echo "</tr>"; + } + echo "</table>"; + } + + #------- Debug endOfCentral + $kkk = 0; + if (sizeof($this->endOfCentral)) { + echo "<table border='0' style='font: 11px Verdana' style='border: 1px solid #000'>"; + echo "<tr style='background: #DAA'><td colspan='2'>dUnzip - End of file</td></tr>"; + foreach ($this->endOfCentral as $field => $value) { + echo "<tr>"; + echo "<td style='background: #FCC'>$field</td>"; + echo "<td style='background: #FDD'>$value</td>"; + echo "</tr>"; + } + echo "</table>"; + } + } + + return $this->compressedList; + } + + + Function getExtraInfo($compressedFileName) + { + return + isset($this->centralDirList[$compressedFileName]) ? + $this->centralDirList[$compressedFileName] : + false; + } + + + Function getZipInfo($detail = false) + { + return $detail ? + $this->endOfCentral[$detail] : + $this->endOfCentral; + } + + + Function unzip($compressedFileName, $targetFileName = false) + { + $fdetails = &$this->compressedList[$compressedFileName]; + + if (!sizeof($this->compressedList)) { + $this->debugMsg(1, "Trying to unzip before loading file list... Loading it!"); + $this->getList(false, $compressedFileName); + } + if (!isset($this->compressedList[$compressedFileName])) { + $this->debugMsg(2, "File '<b>$compressedFileName</b>' is not compressed in the zip."); + return false; + } + if (substr($compressedFileName, -1) == "/") { + $this->debugMsg(2, "Trying to unzip a folder name '<b>$compressedFileName</b>'."); + return false; + } + if (!$fdetails['uncompressed_size']) { + $this->debugMsg(1, "File '<b>$compressedFileName</b>' is empty."); + return ""; + } + + fseek($this->fh, $fdetails['contents-startOffset']); + return $this->uncompress( + fread($this->fh, $fdetails['compressed_size']), + $fdetails['compression_method'], + $fdetails['uncompressed_size']); + } + + + Function unzipAll($targetDir = false, $baseDir = "", $maintainStructure = true, $chmod = false) + { + if ($targetDir === false) + $targetDir = dirname(__FILE__) . "/"; + + $lista = $this->getList(); + if (sizeof($lista)) foreach ($lista as $fileName => $trash) { + $dirname = dirname($fileName); + $outDN = "$targetDir/$dirname"; + + if (substr($dirname, 0, strlen($baseDir)) != $baseDir) + continue; + + if (!is_dir($outDN) && $maintainStructure) { + $str = ""; + $folders = explode("/", $dirname); + foreach ($folders as $folder) { + $str = $str ? "$str/$folder" : $folder; + if (!is_dir("$targetDir/$str")) { + $this->debugMsg(1, "Creating folder: $targetDir/$str"); + mkdir("$targetDir/$str"); + if ($chmod) + chmod("$targetDir/$str", $chmod); + } + } + } + if (substr($fileName, -1, 1) == "/") + continue; + + $maintainStructure ? + $this->unzip($fileName, "$targetDir/$fileName") : + $this->unzip($fileName, "$targetDir/" . basename($fileName)); + + if ($chmod) + chmod($maintainStructure ? "$targetDir/$fileName" : "$targetDir/" . basename($fileName), $chmod); + } + } + + Function close() + { // Free the file resource + if ($this->fh) + fclose($this->fh); + } + + // Private (you should NOT call these methods): + Function uncompress($content, $mode, $uncompressedSize, $targetFileName = false) + { + switch ($mode) { + case 0: + // Not compressed + return $content; + case 1: + $this->debugMsg(2, "Shrunk mode is not supported... yet?"); + return false; + case 2: + case 3: + case 4: + case 5: + $this->debugMsg(2, "Compression factor " . ($mode - 1) . " is not supported... yet?"); + return false; + case 6: + $this->debugMsg(2, "Implode is not supported... yet?"); + return false; + case 7: + $this->debugMsg(2, "Tokenizing compression algorithm is not supported... yet?"); + return false; + case 8: + // Deflate + return gzinflate($content, $uncompressedSize); + case 9: + $this->debugMsg(2, "Enhanced Deflating is not supported... yet?"); + return false; + case 10: + $this->debugMsg(2, "PKWARE Date Compression Library Impoloding is not supported... yet?"); + return false; + default: + $this->debugMsg(2, "Unknown uncompress method: $mode"); + return false; + } + } + + + Function debugMsg($level, $string) + { + if ($this->debug) + if ($level == 1) + echo "<b style='color: #777'>dUnzip2:</b> $string<br>"; + if ($level == 2) + echo "<b style='color: #F00'>dUnzip2:</b> $string<br>"; + } +} + ?> \ No newline at end of file diff --git a/modules/util/ArchiveZip.class.php b/modules/util/ArchiveZip.class.php @@ -1,89 +1,89 @@ -<?php - - -/** - * This source is taken from http://www.zend.com/zend/spotlight/creating-zip-files1.php - * Thank you! - */ -class ArchiveZip -{ - var $datasec = array(); - var $ctrl_dir = array(); - var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; - var $old_offset = 0; - - - function add_file($data, $name) - { - $name = str_replace("\\", "/", $name); - $unc_len = strlen($data); - $crc = crc32($data); - $zdata = gzcompress($data); - $zdate = substr ($zdata, 2, -4); - $c_len = strlen($zdata); - - - - $fr = "\x50\x4b\x03\x04"; - $fr .= "\x14\x00"; - $fr .= "\x00\x00"; - $fr .= "\x08\x00"; - $fr .= "\x00\x00\x00\x00"; - $fr .= pack("V",$crc); - $fr .= pack("V",$c_len); - $fr .= pack("V",$unc_len); - $fr .= pack("v", strlen($name) ); - $fr .= pack("v", 0 ); - $fr .= $name; - $fr .= $zdata; - $fr .= pack("V",$crc); - $fr .= pack("V",$c_len); - $fr .= pack("V",$unc_len); - - $this -> datasec[] = $fr; - - - - $new_offset = strlen(implode("", $this->datasec)); - - $cdrec = "\x50\x4b\x01\x02"; - $cdrec .="\x00\x00"; - $cdrec .="\x14\x00"; - $cdrec .="\x00\x00"; - $cdrec .="\x08\x00"; - $cdrec .="\x00\x00\x00\x00"; - $cdrec .= pack("V",$crc); - $cdrec .= pack("V",$c_len); - $cdrec .= pack("V",$unc_len); - $cdrec .= pack("v", strlen($name) ); - $cdrec .= pack("v", 0 ); - $cdrec .= pack("v", 0 ); - $cdrec .= pack("v", 0 ); - $cdrec .= pack("v", 0 ); - $cdrec .= pack("V", 32 ); - $cdrec .= pack("V", $this -> old_offset ); - - $this -> old_offset = $new_offset; - - $cdrec .= $name; - $this -> ctrl_dir[] = $cdrec; - } - - - function file() { - $data = implode("", $this -> datasec); - $ctrldir = implode("", $this -> ctrl_dir); - - return - $data. - $ctrldir. - $this -> eof_ctrl_dir. - pack("v", sizeof($this -> ctrl_dir)). - pack("v", sizeof($this -> ctrl_dir)). - pack("V", strlen($ctrldir)). - pack("V", strlen($data)). - "\x00\x00"; - } -} - +<?php + + +namespace util; +/** + * This source is taken from http://www.zend.com/zend/spotlight/creating-zip-files1.php + * Thank you! + */ +class ArchiveZip +{ + var $datasec = array(); + var $ctrl_dir = array(); + var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; + var $old_offset = 0; + + + function add_file($data, $name) + { + $name = str_replace("\\", "/", $name); + $unc_len = strlen($data); + $crc = crc32($data); + $zdata = gzcompress($data); + $zdate = substr($zdata, 2, -4); + $c_len = strlen($zdata); + + + $fr = "\x50\x4b\x03\x04"; + $fr .= "\x14\x00"; + $fr .= "\x00\x00"; + $fr .= "\x08\x00"; + $fr .= "\x00\x00\x00\x00"; + $fr .= pack("V", $crc); + $fr .= pack("V", $c_len); + $fr .= pack("V", $unc_len); + $fr .= pack("v", strlen($name)); + $fr .= pack("v", 0); + $fr .= $name; + $fr .= $zdata; + $fr .= pack("V", $crc); + $fr .= pack("V", $c_len); + $fr .= pack("V", $unc_len); + + $this->datasec[] = $fr; + + + $new_offset = strlen(implode("", $this->datasec)); + + $cdrec = "\x50\x4b\x01\x02"; + $cdrec .= "\x00\x00"; + $cdrec .= "\x14\x00"; + $cdrec .= "\x00\x00"; + $cdrec .= "\x08\x00"; + $cdrec .= "\x00\x00\x00\x00"; + $cdrec .= pack("V", $crc); + $cdrec .= pack("V", $c_len); + $cdrec .= pack("V", $unc_len); + $cdrec .= pack("v", strlen($name)); + $cdrec .= pack("v", 0); + $cdrec .= pack("v", 0); + $cdrec .= pack("v", 0); + $cdrec .= pack("v", 0); + $cdrec .= pack("V", 32); + $cdrec .= pack("V", $this->old_offset); + + $this->old_offset = $new_offset; + + $cdrec .= $name; + $this->ctrl_dir[] = $cdrec; + } + + + function file() + { + $data = implode("", $this->datasec); + $ctrldir = implode("", $this->ctrl_dir); + + return + $data . + $ctrldir . + $this->eof_ctrl_dir . + pack("v", sizeof($this->ctrl_dir)) . + pack("v", sizeof($this->ctrl_dir)) . + pack("V", strlen($ctrldir)) . + pack("V", strlen($data)) . + "\x00\x00"; + } +} + ?> \ No newline at end of file diff --git a/modules/util/ArrayUtils.class.php b/modules/util/ArrayUtils.class.php @@ -1,66 +1,61 @@ <?php + +namespace util; /** * Created by PhpStorm. * User: dankert * Date: 22.12.18 * Time: 21:36 */ - class ArrayUtils { - public static function getSubArray( $array, $keys ) { - - $a = $array; - foreach( $keys as $k ) - { - if ( ! isset($a[$k]) ) - return array(); - - if ( ! is_array($a[$k]) ) - return array(); - - $a = $a[$k]; - } + public static function getSubArray($array, $keys) + { - return $a; - } + $a = $array; + foreach ($keys as $k) { + if (!isset($a[$k])) + return array(); + if (!is_array($a[$k])) + return array(); + $a = $a[$k]; + } + return $a; + } - public static function getSubValue( $array, $keys ) { - $a = $array; - foreach( $keys as $k ) - { - if ( ! isset($a[$k]) ) - return null; + public static function getSubValue($array, $keys) + { - $a = $a[$k]; - } + $a = $array; + foreach ($keys as $k) { + if (!isset($a[$k])) + return null; - return $a; - } + $a = $a[$k]; + } + return $a; + } - public static function flattenArray( $prefix, $arr, $split= '.' ) - { - $new = array(); - foreach( $arr as $key=>$val) - { - if ( is_array($val) ) - { - $new[$prefix.$key] = ''; + public static function flattenArray($prefix, $arr, $split = '.') + { + $new = array(); + foreach ($arr as $key => $val) { + if (is_array($val)) { + $new[$prefix . $key] = ''; - $new += self::flattenArray($prefix.$key.$split, $val, $split ); - } - else - $new[$prefix.$key] = $val; - } - return $new; - } + $new += self::flattenArray($prefix . $key . $split, $val, $split); + } else + $new[$prefix . $key] = $val; + } + return $new; + } /** @@ -76,16 +71,15 @@ class ArrayUtils foreach ($arr as $key => $val) { if (is_array($val)) { - $new[] = array('depth'=>$depth, 'key'=>$key,'val'=>''); + $new[] = array('depth' => $depth, 'key' => $key, 'val' => ''); $new += self::indentedFlattenArray($val, $padChar, $depth + 1); } else - $new[] = array('depth'=>$depth, 'key'=>$key,'val'=>$val); + $new[] = array('depth' => $depth, 'key' => $key, 'val' => $val); } return $new; } - /** * Make a dry flat array. * @@ -99,10 +93,10 @@ class ArrayUtils $new = array(); foreach ($arr as $key => $val) { if (is_array($val)) { - $new[str_repeat($padChar,$depth).$key] = ''; + $new[str_repeat($padChar, $depth) . $key] = ''; $new += self::dryFlattenArray($val, $padChar, $depth + 1); } else - $new[str_repeat($padChar,$depth).$key] = $val; + $new[str_repeat($padChar, $depth) . $key] = $val; } return $new; } diff --git a/modules/util/Browser.class.php b/modules/util/Browser.class.php @@ -1,65 +1,67 @@ <?php +namespace util; /** * Very simple approach to identify a browsers name and platform. */ -class Browser { +class Browser +{ - public $name; - public $platform; + public $name; + public $platform; /** * Takes the user agent from the HTTP request and analyzes name and platform. */ - public function __construct() - { - $agent = @$_SERVER['HTTP_USER_AGENT']; + public function __construct() + { + $agent = @$_SERVER['HTTP_USER_AGENT']; - if (stripos($agent, 'Opera') || stripos($agent, 'OPR/')) - $this->name = 'Opera'; - elseif (stripos($agent, 'Edge')) - $this->name= 'Microsoft Edge'; - elseif (stripos($agent, 'vivaldi')) - $this->name= 'Vivaldi'; - elseif (stripos($agent, 'netscape')) - $this->name= 'Netscape'; - elseif (stripos($agent, 'Chrome')) - $this->name= 'Google Chrome'; - elseif (stripos($agent, 'Safari')) - $this->name= 'Safari'; - elseif (stripos($agent, 'Firefox')) - $this->name= 'Mozilla Firefox'; - elseif (stripos($agent, 'MSIE') || stripos($agent, 'Trident/7')) - $this->name= 'Internet Explorer'; - else - $this->name= 'Unknown Browser'; + if (stripos($agent, 'Opera') || stripos($agent, 'OPR/')) + $this->name = 'Opera'; + elseif (stripos($agent, 'Edge')) + $this->name = 'Microsoft Edge'; + elseif (stripos($agent, 'vivaldi')) + $this->name = 'Vivaldi'; + elseif (stripos($agent, 'netscape')) + $this->name = 'Netscape'; + elseif (stripos($agent, 'Chrome')) + $this->name = 'Google Chrome'; + elseif (stripos($agent, 'Safari')) + $this->name = 'Safari'; + elseif (stripos($agent, 'Firefox')) + $this->name = 'Mozilla Firefox'; + elseif (stripos($agent, 'MSIE') || stripos($agent, 'Trident/7')) + $this->name = 'Internet Explorer'; + else + $this->name = 'Unknown Browser'; - if (stripos($agent, 'Linux') || stripos($agent, 'linux')) - $this->platform = 'Linux'; - elseif (stripos($agent, 'Windows') || stripos($agent, 'win32')) - $this->platform = 'Windows'; - elseif (stripos($agent, 'android') ) - $this->platform = 'Android'; - elseif (stripos($agent, 'mac os') || stripos($agent, 'cpu os') || stripos($agent, 'iPhone') || stripos($agent, 'OS X')) - $this->platform = 'Android'; - elseif (stripos($agent, 'cros') ) - $this->platform = 'Chrome OS'; - elseif (stripos($agent, 'SymbOS') ) - $this->platform = 'Symbian OS'; - elseif (stripos($agent, 'windows phone') ) - $this->platform = 'Microsoft Windows Phone '; - elseif (stripos($agent, 'nokia') ) - $this->platform = 'Nokia'; - elseif (stripos($agent, 'blackberry') ) - $this->platform = 'Blackberry'; - elseif (stripos($agent, 'openbsd') ) - $this->platform = 'OpenBSD'; - elseif (stripos($agent, 'freebsd') ) - $this->platform = 'FreeBSD'; - else - $this->name= 'Unknown OS'; + if (stripos($agent, 'Linux') || stripos($agent, 'linux')) + $this->platform = 'Linux'; + elseif (stripos($agent, 'Windows') || stripos($agent, 'win32')) + $this->platform = 'Windows'; + elseif (stripos($agent, 'android')) + $this->platform = 'Android'; + elseif (stripos($agent, 'mac os') || stripos($agent, 'cpu os') || stripos($agent, 'iPhone') || stripos($agent, 'OS X')) + $this->platform = 'Android'; + elseif (stripos($agent, 'cros')) + $this->platform = 'Chrome OS'; + elseif (stripos($agent, 'SymbOS')) + $this->platform = 'Symbian OS'; + elseif (stripos($agent, 'windows phone')) + $this->platform = 'Microsoft Windows Phone '; + elseif (stripos($agent, 'nokia')) + $this->platform = 'Nokia'; + elseif (stripos($agent, 'blackberry')) + $this->platform = 'Blackberry'; + elseif (stripos($agent, 'openbsd')) + $this->platform = 'OpenBSD'; + elseif (stripos($agent, 'freebsd')) + $this->platform = 'FreeBSD'; + else + $this->name = 'Unknown OS'; - } + } } diff --git a/modules/util/ClassUtils.class.php b/modules/util/ClassUtils.class.php @@ -1,18 +1,20 @@ <?php +namespace util; /** * Class ClassUtils * @author Jan Dankert */ -class ClassUtils { +class ClassUtils +{ - public static function getSimpleClassName($object) - { - if ( ! is_object($object)) - return 'NotAnObject'; + public static function getSimpleClassName($object) + { + if (!is_object($object)) + return 'NotAnObject'; - $classname = get_class($object); - if ($pos = strrpos($classname, '\\')) return substr($classname, $pos + 1); - return $pos; - } + $classname = get_class($object); + if ($pos = strrpos($classname, '\\')) return substr($classname, $pos + 1); + return $pos; + } } \ No newline at end of file diff --git a/modules/util/Code.class.php b/modules/util/Code.class.php @@ -16,6 +16,11 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +namespace util; +use util\FileUtils; +use Logger; +use util\Macro; + /** * @author $Author$ * @version $Revision$ @@ -24,22 +29,22 @@ class Code extends Macro { public $code; - + function execute() { - if ( substr($this->code,0,2) != '<?' ) - $this->code = "<?php\n".$this->code."\n?>"; + if (substr($this->code, 0, 2) != '<?') + $this->code = "<?php\n" . $this->code . "\n?>"; - Logger::trace('code: Executing PHP Code: '."\n".$this->code); - $tmp = FileUtils::getTempDir().'/openratMacro'; + Logger::trace('code: Executing PHP Code: ' . "\n" . $this->code); + $tmp = FileUtils::getTempDir() . '/openratMacro'; $tmp .= '.code.php.tmp'; - - $f = fopen( $tmp,'w' ); - fwrite( $f,$this->code ); - fclose( $f ); - - require( $tmp ); // Ausfuehren des temporaeren PHP-Codes - unlink( $tmp ); - } + $f = fopen($tmp, 'w'); + fwrite($f, $this->code); + fclose($f); + + require($tmp); // Ausfuehren des temporaeren PHP-Codes + + unlink($tmp); + } } \ No newline at end of file diff --git a/modules/util/Dynamic.class.php b/modules/util/Dynamic.class.php @@ -17,12 +17,15 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +namespace util; +use util\Macro; + /** * Oberklasse für dynamische Klassen ("Makros"). - * + * * Diese Klasse dient nur der Abwärtskompabilität. Neue dynamische Klassen * (ab jetzt "Makros") sollten von der Klasse Macro erben. - * + * * @author Jan Dankert * @package openrat.services */ diff --git a/modules/util/FileUtils.class.php b/modules/util/FileUtils.class.php @@ -1,5 +1,9 @@ <?php +namespace util; +use Pfad; +use RuntimeException; + /** * Werkzeugklasse f�r Datei-Operationen. * @@ -12,15 +16,14 @@ class FileUtils * @param String $pfad * @return Pfad mit angeh�ngtem Slash. */ - public static function slashify($pfad) + public static function slashify($pfad) { - if ( substr($pfad,-1,1) == '/') + if (substr($pfad, -1, 1) == '/') return $pfad; else - return $pfad.'/'; + return $pfad . '/'; } - - + /** * Liefert einen Verzeichnisnamen fuer temporaere Dateien. @@ -29,20 +32,16 @@ class FileUtils { global $conf; $tmpdir = @$conf['cache']['tmp_dir']; - $tmpfile = @tempnam( $tmpdir,'openrat_tmp' ); + $tmpfile = @tempnam($tmpdir, 'openrat_tmp'); // 2. Versuch: Temp-Dir aus "upload_tmp_dir". - if ( $tmpfile === FALSE ) - { + if ($tmpfile === FALSE) { $tmpdir = ini_get('upload_tmp_dir'); - $tmpfile = @tempnam( $tmpdir,'openrat_tmp' ); - } - - elseif ( $tmpfile === FALSE ) - { - $tmpfile = @tempnam( '','openrat_tmp' ); + $tmpfile = @tempnam($tmpdir, 'openrat_tmp'); + } elseif ($tmpfile === FALSE) { + $tmpfile = @tempnam('', 'openrat_tmp'); } - + return $tmpfile; } @@ -52,35 +51,34 @@ class FileUtils */ public static function getTempDir() { - $tmpfile = FileUtils::createTempFile(); - - $tmpdir = dirname($tmpfile); - @unlink($tmpfile); - - return FileUtils::slashify( $tmpdir ); - } + $tmpfile = FileUtils::createTempFile(); + $tmpdir = dirname($tmpfile); + @unlink($tmpfile); - /** - * @param array $attr - * @return string - * @deprecated use \Cache - */ - public static function getTempFileName( $attr = array() ) - { - $filename = FileUtils::getTempDir() . '/openrat'; - foreach ($attr as $a => $w) - $filename .= '_' . $a . $w; + return FileUtils::slashify($tmpdir); + } - $filename .= '.tmp'; - return $filename; - } + /** + * @param array $attr + * @return string + * @deprecated use \Cache + */ + public static function getTempFileName($attr = array()) + { + $filename = FileUtils::getTempDir() . '/openrat'; + foreach ($attr as $a => $w) + $filename .= '_' . $a . $w; + + $filename .= '.tmp'; + return $filename; + } - /** + /** * Liest die Dateien aus dem angegebenen Ordner in ein Array. - * + * * @param $dir string Verzeichnis, welches gelesen werden soll * @return array Liste der Dateien im Ordner */ @@ -88,45 +86,46 @@ class FileUtils { $dir = FileUtils::slashify($dir); $dateien = array(); - - if ( !is_dir($dir) ) - { - throw new RuntimeException('not a directory: '.$dir); + + if (!is_dir($dir)) { + throw new RuntimeException('not a directory: ' . $dir); } - - if ( $dh = opendir($dir) ) - { - while( ($verzEintrag = readdir($dh)) !== false ) - { - if ( substr($verzEintrag,0,1) != '.' ) - { + + if ($dh = opendir($dir)) { + while (($verzEintrag = readdir($dh)) !== false) { + if (substr($verzEintrag, 0, 1) != '.') { $dateien[] = $verzEintrag; } - } - closedir($dh); - - return $dateien; - } - else - { - throw new RuntimeException('unable to open directory: '.$dir); - } - + } + closedir($dh); + + return $dateien; + } else { + throw new RuntimeException('unable to open directory: ' . $dir); + } + } - public static function isAbsolutePath( $path ) { + public static function isAbsolutePath($path) + { return @$path[0] == '/'; } - public static function toAbsolutePath( $pathElements ) { - $pathElements = array_map( function($path) { return trim($path,'/'); },$pathElements ); - return array_reduce( $pathElements, function($path,$item){return $path.($item?'/'.$item:'');},'' ); + public static function toAbsolutePath($pathElements) + { + $pathElements = array_map(function ($path) { + return trim($path, '/'); + }, $pathElements); + return array_reduce($pathElements, function ($path, $item) { + return $path . ($item ? '/' . $item : ''); + }, ''); } - public static function toRelativePath( $pathElements ) { - return '.'.self::toAbsolutePath($pathElements); + public static function toRelativePath($pathElements) + { + return '.' . self::toAbsolutePath($pathElements); } } diff --git a/modules/util/GlobalFunctions.class.php b/modules/util/GlobalFunctions.class.php @@ -1,5 +1,6 @@ <?php +namespace util; /** * Bereitstellen von globalen Funktionen * @author $Author$ @@ -11,28 +12,24 @@ class GlobalFunctions public static function getIsoCodes() { global $conf_php; - - $iso = parse_ini_file( './language/lang.ini.'.$conf_php ); - asort( $iso ); + + $iso = parse_ini_file('./language/lang.ini.' . $conf_php); + asort($iso); return $iso; } - public static function lang( $text ) + public static function lang($text) { - global $SESS; + global $SESS; $text = strtoupper($text); - - if ( isset( $SESS['lang'][$text] ) ) - { - return $SESS['lang'][$text]; - } - else - { - return( '?'.$text.'?' ); - } - } + if (isset($SESS['lang'][$text])) { + return $SESS['lang'][$text]; + } else { + return ('?' . $text . '?'); + } + } } diff --git a/modules/util/Html.class.php b/modules/util/Html.class.php @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +namespace util; /** * Bereitstellen von Methoden fuer die Darstellung von HTML-Elementen * @@ -27,7 +28,7 @@ class Html { - + /** * Erzeugt eine relative Url innerhalb von Openrat * @@ -35,98 +36,90 @@ class Html * @param string Unteraktion, die innerhalb der Aktion aufgerufen werden soll * @param int Id fuer diesen Aufruf * @param array Weitere beliebige Parameter - * @deprecated Das ist Dialog-Logik. Besser im Frontend erzeugen. + * @deprecated Das ist Dialog-Logik. Besser im Frontend erzeugen. */ - public static function url( $action,$subaction='',$id='',$params=array() ) + public static function url($action, $subaction = '', $id = '', $params = array()) { - if ( intval($id)==0 ) - $id='-'; + if (intval($id) == 0) + $id = '-'; global $conf; - - if ( is_array($action) ) - { + + if (is_array($action)) { $params = $action; - if ( isset($params['callAction']) ) - { - $params['subaction'] = $params['callAction']; - unset( $params['callAction'] ); - unset( $params['callSubaction'] ); + if (isset($params['callAction'])) { + $params['subaction'] = $params['callAction']; + unset($params['callAction']); + unset($params['callSubaction']); } - - if ( !isset($params['action' ])) $params['action' ] = ''; - if ( !isset($params['subaction'])) $params['subaction'] = ''; - if ( !isset($params['id' ])) $params['id' ] = ''; - $action = $params['action' ]; + + if (!isset($params['action'])) $params['action'] = ''; + if (!isset($params['subaction'])) $params['subaction'] = ''; + if (!isset($params['id'])) $params['id'] = ''; + $action = $params['action']; $subaction = $params['subaction']; - $id = $params['id' ]; - unset( $params['action' ] ); - unset( $params['subaction'] ); - unset( $params['id' ] ); - $params['old']='true'; + $id = $params['id']; + unset($params['action']); + unset($params['subaction']); + unset($params['id']); + $params['old'] = 'true'; } // Session-Id ergaenzen - if ( $conf['interface']['url']['add_sessionid'] ) - $params[ session_name() ] = session_id(); - - if ( config('security','use_post_token') ) - $params[ 'token'] = token(); + if ($conf['interface']['url']['add_sessionid']) + $params[session_name()] = session_id(); - $fake_urls = $conf['interface']['url']['fake_url' ]; + if (config('security', 'use_post_token')) + $params['token'] = token(); + + $fake_urls = $conf['interface']['url']['fake_url']; $url_format = $conf['interface']['url']['url_format']; - - if ( isset($params['objectid']) && !isset($params['id']) ) - $params['id'] = $params['objectid']; - if ( $fake_urls ) - { + if (isset($params['objectid']) && !isset($params['id'])) + $params['id'] = $params['objectid']; + + if ($fake_urls) { // if ( $id != '' ) // $id = '.'.$id; - } - else - { + } else { global $view; - $params[REQ_PARAM_ACTION ] = $action; + $params[REQ_PARAM_ACTION] = $action; $params[REQ_PARAM_SUBACTION] = $subaction; - $params[REQ_PARAM_ID ] = $id; + $params[REQ_PARAM_ID] = $id; } - if ( count($params) > 0 ) - { + if (count($params) > 0) { $urlParameterList = array(); - foreach( $params as $var=>$value ) - { - $urlParameterList[] = urlencode($var).'='.urlencode($value); + foreach ($params as $var => $value) { + $urlParameterList[] = urlencode($var) . '=' . urlencode($value); } - $urlParameterList['_'] = @$urlParameterList[REQ_PARAM_ACTION].'-'.@$urlParameterList[REQ_PARAM_ID]; - unset( $urlParameterList[REQ_PARAM_ACTION], $urlParameterList[REQ_PARAM_ID]); + $urlParameterList['_'] = @$urlParameterList[REQ_PARAM_ACTION] . '-' . @$urlParameterList[REQ_PARAM_ID]; + unset($urlParameterList[REQ_PARAM_ACTION], $urlParameterList[REQ_PARAM_ID]); // We do not escape '&' as '&amp;' here, as it would brake things like Ajax-Urls. - // Maybe the escaping should be controled by a parameter. - $urlParameter = '?'.implode('&',$urlParameterList); - } - else - { + // Maybe the escaping should be controled by a parameter. + $urlParameter = '?' . implode('&', $urlParameterList); + } else { $urlParameter = ''; } - if ( @$conf['interface']['url']['index'] ) + if (@$conf['interface']['url']['index']) $controller_file_name = ''; else $controller_file_name = ''; $prefix = './'; - - if ( $fake_urls ) - $src = sprintf( $url_format,$action,$subaction,$id,session_id() ).$urlParameter; + + if ($fake_urls) + $src = sprintf($url_format, $action, $subaction, $id, session_id()) . $urlParameter; else - $src = $prefix.$controller_file_name.$urlParameter; + $src = $prefix . $controller_file_name . $urlParameter; return $src; } } + ?> \ No newline at end of file diff --git a/modules/util/Http.class.php b/modules/util/Http.class.php @@ -17,6 +17,10 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +namespace util; +use Logger; +use withPraefixQuestionMark; + /** * Kapselung einer HTTP-Anfrage.<br> * Unter Beruecksichtigung von RFC 1945.<br> @@ -26,12 +30,12 @@ */ class Http { - public $header = array(); - - public $url = array(); - public $responseHeader = array(); - public $requestParameter = array(); - public $urlParameter = array(); + public $header = array(); + + public $url = array(); + public $responseHeader = array(); + public $requestParameter = array(); + public $urlParameter = array(); /** * HTTP-Request-Typ.<br> @@ -40,13 +44,12 @@ class Http * * @var String Request-Typ */ - public $method = 'GET'; - public $error = ''; - public $status = ''; - public $body = ''; - - public $httpCmd = ''; + public $method = 'GET'; + public $error = ''; + public $status = ''; + public $body = ''; + public $httpCmd = ''; /** @@ -55,49 +58,44 @@ class Http * @param String URL * @return Http */ - public function __construct( $url = '' ) + public function __construct($url = '') { - $this->setURL( $url ); + $this->setURL($url); $this->header['User-Agent'] = 'Mozilla/5.0 (OpenRat CMS)'; $this->header['Connection'] = 'close'; } - /** * Setzt die URL. * * @param String URL */ - function setURL( $url ) + function setURL($url) { $this->url = parse_url($url); - if ( empty($this->url['host']) && !empty($this->url['path']) ) - { + if (empty($this->url['host']) && !empty($this->url['path'])) { $this->url['host'] = basename($this->url['path']); $this->url['path'] = '/'; } - if ( empty($this->url['path']) ) + if (empty($this->url['path'])) $this->url['path'] = '/'; - if ( !isset($this->url['port']) ) - if ( !isset($this->url['scheme']) ) - { + if (!isset($this->url['port'])) + if (!isset($this->url['scheme'])) { $this->url['scheme'] = 'http'; // Standard-Port. - $this->url['port'] = 80; // Standard-Port. - } - elseif ( $this->url['scheme'] == 'https' ) + $this->url['port'] = 80; // Standard-Port. + } elseif ($this->url['scheme'] == 'https') $this->url['port'] = 443; // SSL-Port. else $this->url['port'] = 80; // Standard-Port. - - if ( !empty($this->url['query']) ) - parse_str( $this->url['query'],$this->urlParameter ); - } + if (!empty($this->url['query'])) + parse_str($this->url['query'], $this->urlParameter); + } /** @@ -106,61 +104,58 @@ class Http * @param String Benutzername * @param String Kennwort */ - public function setBasicAuthentication( $user, $password ) + public function setBasicAuthentication($user, $password) { - $this->header['Authorization'] = 'Basic '.base64_encode($user.':'.$password); + $this->header['Authorization'] = 'Basic ' . base64_encode($user . ':' . $password); } - /** * Erzeugt eine HTTP-Parameterstring mit allen Parametern. - * + * * @param withPraefixQuestionMark Praefix mit Fragezeichen (fuer GET-Anfragen) * @return String URL-Parameter */ - public function getParameterString( $withPraefixQuestionMark=false ) + public function getParameterString($withPraefixQuestionMark = false) { $parameterString = ''; $parameter = $this->urlParameter + $this->requestParameter; - - if ( ! empty($parameter) ) - { - foreach( $this->requestParameter as $paramName => $paramValue ) - { - if ( strlen($parameterString) > 0) + + if (!empty($parameter)) { + foreach ($this->requestParameter as $paramName => $paramValue) { + if (strlen($parameterString) > 0) $parameterString .= '&'; - elseif ( $withPraefixQuestionMark ) + elseif ($withPraefixQuestionMark) $parameterString .= '?'; - - $parameterString .= urlencode($paramName) . '=' .urlencode($paramValue); + + $parameterString .= urlencode($paramName) . '=' . urlencode($paramValue); } } - + return $parameterString; } - + /** * Liefert die URL des Requests. - * + * * @return String URL */ public function getUrl() { $location = $this->url['scheme']; - $location .= '://'; + $location .= '://'; $location .= $this->url['host']; - if ( $this->url['scheme'] == 'http' && $this->url['port'] != 80 || - $this->url['scheme'] == 'https' && $this->url['port'] != 443 ) - $location .= ':'.$this->url['port']; + if ($this->url['scheme'] == 'http' && $this->url['port'] != 80 || + $this->url['scheme'] == 'https' && $this->url['port'] != 443) + $location .= ':' . $this->url['port']; $location .= $this->url['path']; - + $location .= $this->getParameterString(true); - if ( isset($this->url['fragment']) ) - $location .= '#'.$this->url['fragment']; - + if (isset($this->url['fragment'])) + $location .= '#' . $this->url['fragment']; + return $location; } @@ -171,8 +166,8 @@ class Http public function sendRedirect() { $location = $this->getUrl(); - - header('Location: '.$location); + + header('Location: ' . $location); exit; } @@ -184,86 +179,78 @@ class Http */ public function request() { - $this->error = ''; + $this->error = ''; $this->status = ''; - $errno = 0; + $errno = 0; $errstr = ''; - if ( empty($this->url['host']) ) - { + if (empty($this->url['host'])) { $this->error = "No hostname specified"; return false; } - - foreach( $this->header as $header_key=>$header_value ) - { - if ( is_numeric( $header_key ) ) - { - $dp = strpos($header_value,':'); - if ( $dp!==FALSE) - $this->header[substr($header_value,0,$dp)] = substr($header_value,$dp+1); + + foreach ($this->header as $header_key => $header_value) { + if (is_numeric($header_key)) { + $dp = strpos($header_value, ':'); + if ($dp !== FALSE) + $this->header[substr($header_value, 0, $dp)] = substr($header_value, $dp + 1); unset($this->header[$header_key]); } } - + $parameterString = $this->getParameterString(); - - if ( $this->method == 'POST' ) - { - $this->header['Content-Type' ] = 'application/x-www-form-urlencoded'; + + if ($this->method == 'POST') { + $this->header['Content-Type'] = 'application/x-www-form-urlencoded'; $this->header['Content-Length'] = strlen($parameterString); } - + // Accept-Header setzen, falls noch nicht vorhanden. - if ( !array_key_exists('Accept',$this->header) ) + if (!array_key_exists('Accept', $this->header)) $this->header['Accept'] = '*/*'; - + $this->responseHeader = array(); // RFC 1945 (Section 9.3) says: // A user agent should never automatically redirect a request // more than 5 times, since such redirections usually indicate an infinite loop. - for( $r=1; $r<=5; $r++ ) - { + for ($r = 1; $r <= 5; $r++) { $this->header['Host'] = $this->url['host']; - + // Die Funktion fsockopen() erwartet eine Protokollangabe (bei TCP optional, bei SSL notwendig). - if ( $this->url['scheme'] == 'https' || $this->url['port'] == '443' ) + if ($this->url['scheme'] == 'https' || $this->url['port'] == '443') $prx_proto = 'ssl://'; // SSL else $prx_proto = 'tcp://'; // Default - - $fp = @fsockopen ($prx_proto.$this->url['host'],$this->url['port'], $errno, $errstr, 30); - - if ( !$fp || !is_resource($fp) ) - { + + $fp = @fsockopen($prx_proto . $this->url['host'], $this->url['port'], $errno, $errstr, 30); + + if (!$fp || !is_resource($fp)) { // Keine Verbindung zum Host moeglich. - $this->error = "Connection refused: '".$prx_proto.$this->url['host'].':'.$this->url['port']." - $errstr ($errno)"; + $this->error = "Connection refused: '" . $prx_proto . $this->url['host'] . ':' . $this->url['port'] . " - $errstr ($errno)"; return false; - } - else - { - + } else { + $lb = "\r\n"; $http_get = $this->url['path']; - $request_header = array( $this->method.' '.$http_get.' HTTP/1.0'); - - foreach($this->header as $header_key=>$header_value) - $request_header[] = $header_key.': '.$header_value; - - $http_request = implode($lb,$request_header).$lb.$lb; - - if ( $this->method == 'GET') - if ( !empty($parameterString) ) - $http_get .= '?'.$parameterString; - - if ( $this->method == 'POST' ) + $request_header = array($this->method . ' ' . $http_get . ' HTTP/1.0'); + + foreach ($this->header as $header_key => $header_value) + $request_header[] = $header_key . ': ' . $header_value; + + $http_request = implode($lb, $request_header) . $lb . $lb; + + if ($this->method == 'GET') + if (!empty($parameterString)) + $http_get .= '?' . $parameterString; + + if ($this->method == 'POST') $http_request .= $parameterString; if (!is_resource($fp)) { - $this->error = 'Connection lost after connect: '.$prx_proto.$this->url['host'].':'.$this->url['port']; + $this->error = 'Connection lost after connect: ' . $prx_proto . $this->url['host'] . ':' . $this->url['port']; return false; } fputs($fp, $http_request); // Die HTTP-Anfrage zum Server senden. @@ -274,33 +261,26 @@ class Http // RFC 1945 (Section 6.1) schreibt als Statuszeile folgendes Format vor // "HTTP/" 1*DIGIT "." 1*DIGIT SP 3DIGIT SP if (!is_resource($fp)) { - $this->error = 'Connection lost during transfer: '.$this->url['host'].':'.$this->url['port']; + $this->error = 'Connection lost during transfer: ' . $this->url['host'] . ':' . $this->url['port']; return false; - } - elseif (!feof($fp)) { - $line = fgets($fp,1028); - $this->status = substr($line,9,3); - } - else - { + } elseif (!feof($fp)) { + $line = fgets($fp, 1028); + $this->status = substr($line, 9, 3); + } else { $this->error = 'Unexpected EOF while reading HTTP-Response'; return false; } - + $this->body = ''; while (!feof($fp)) { - $line = fgets($fp,1028); - if ( $isHeader && trim($line)=='' ) // Leerzeile nach Header. + $line = fgets($fp, 1028); + if ($isHeader && trim($line) == '') // Leerzeile nach Header. { $isHeader = false; - } - elseif( $isHeader ) - { - list($headerName,$headerValue) = explode(': ',$line) + array(1=>''); + } elseif ($isHeader) { + list($headerName, $headerValue) = explode(': ', $line) + array(1 => ''); $this->responseHeader[$headerName] = trim($headerValue); - } - else - { + } else { $this->body .= $line; } } @@ -314,46 +294,37 @@ class Http // 301 Moved Permanently // 302 Moved Temporarily - if ( $this->status == '301' || - $this->status == '302' ) - { + if ($this->status == '301' || + $this->status == '302') { $location = @$this->responseHeader['Location']; - if ( empty($location) ) - { + if (empty($location)) { $this->error = '301/302 Response without Location-header'; return false; } - + //Html::debug($this->url,"alte URL"); //Html::debug($location,"NEUES REDIRECT AUF"); $this->setURL($location); continue; // Naechster Versuch mit umgeleiteter Adresse. } - + // RFC 1945 (Section 6.1.1) schreibt // "2xx: Success - The action was successfully received, understood, and accepted." - elseif ( substr($this->status,0,1) == '2' ) - { + elseif (substr($this->status, 0, 1) == '2') { return true; - } - elseif ( substr($this->status,0,1) == '4' ) - { - $this->error = 'Client Error: '.$this->status; + } elseif (substr($this->status, 0, 1) == '4') { + $this->error = 'Client Error: ' . $this->status; return false; - } - elseif ( substr($this->status,0,1) == '5' ) - { - $this->error = 'Server Error: '.$this->status; + } elseif (substr($this->status, 0, 1) == '5') { + $this->error = 'Server Error: ' . $this->status; return false; - } - else - { - $this->error = 'Unexpected HTTP-Status: '.$this->status. '; this is mostly a client error, sorry.'; + } else { + $this->error = 'Unexpected HTTP-Status: ' . $this->status . '; this is mostly a client error, sorry.'; return false; } } - $this->error = 'Too much redirects, infinite loop assumed. Exiting. Last URL: '.$http_get; + $this->error = 'Too much redirects, infinite loop assumed. Exiting. Last URL: ' . $http_get; return false; } @@ -365,7 +336,7 @@ class Http * Aus dem HTTP-Header werden die vom Browser angeforderten Sprachen * gelesen.<br> * Es wird eine Liste von Sprachen erzeugt.<br> - * + * * Beispiel: * 'de_DE','de','en_GB','en' ... usw.<br> * Wenn der Browser 'de_DE' anfordert, wird hier zusätzlich @@ -380,19 +351,18 @@ class Http $languages = array(); $http_languages = @$HTTP_SERVER_VARS['HTTP_ACCEPT_LANGUAGE']; - foreach( explode(',',$http_languages) as $l ) - { - list($part) = explode(';',$l); // Priorit�ten ignorieren. + foreach (explode(',', $http_languages) as $l) { + list($part) = explode(';', $l); // Priorit�ten ignorieren. $languages[] = trim($part); // Aus "de_DE" das "de" extrahieren. - $languages[] = current(explode('_',str_replace('-','_',trim($part)))); + $languages[] = current(explode('_', str_replace('-', '_', trim($part)))); } - return array_unique( $languages ); + return array_unique($languages); } - - + + /** * Ermittelt die aktuelle HTTP-Adresse des Requests (inkl. Pfad, jedoch ohne Datei). * @@ -401,83 +371,75 @@ class Http public static function getServer() { $https = getenv('HTTPS'); - - if ( $https ) + + if ($https) $server = 'https://'; else $server = 'http://'; - - $server .= getenv('SERVER_NAME').dirname(getenv('REQUEST_URI')); - + + $server .= getenv('SERVER_NAME') . dirname(getenv('REQUEST_URI')); + return $server; } - - + /** * Server-Fehlermeldung anzeigen.<br> - * + * * Erzeugt einen "HTTP 501 Internal Server Error". Zusaetzlich * wird ein 'rollback' auf der Datenbank ausgefaehrt. * * @param String $message Eigener Hinweistext */ - public static function serverError($message,$reason='') + public static function serverError($message, $reason = '') { - if ( class_exists('Session')) - { + if (class_exists('util\Session')) { $db = db(); - if ( is_object( $db ) ) + if (is_object($db)) $db->rollback(); } - if ( class_exists('Logger')) - Logger::warn($message."\n".$reason); - - Http::sendStatus(501,'Internal Server Error',$message,$reason); + if (class_exists('Logger')) + Logger::warn($message . "\n" . $reason); + + Http::sendStatus(501, 'Internal Server Error', $message, $reason); } - - - + + /** * Der Benutzer ist nicht autorisiert, eine Aktion auszufuehren. - * + * * Diese Funktion erzeugt einen "HTTP 403 Not Authorized" und das * Skript wird beendet. * * @param String $text Text * @param String $message Eigener Hinweistext */ - public static function notAuthorized($message='') + public static function notAuthorized($message = '') { - Logger::warn("Security warning: $message"); - Http::sendStatus(403,'Not authorized',$message); + Logger::warn("Security warning: $message"); + Http::sendStatus(403, 'Not authorized', $message); } - - - - - - + + /** * Nichts gefunden. - * + * * Diese Funktion erzeugt einen "HTTP 404 Not found" und das * Skript wird beendet. * * @param String $text Text * @param String $message Eigener Hinweistext */ - public static function notFound($text,$message) + public static function notFound($text, $message) { - Http::sendStatus(404,'Not found',$message); + Http::sendStatus(404, 'Not found', $message); } - - + /** * Kein Inhalt. - * + * * Die HTTP-Antwort stellt gegenüber dem Client klar, dass es keinen Inhalt gibt. */ public static function noContent() @@ -485,9 +447,8 @@ class Http header('HTTP/1.0 204 No Content'); exit; } - - - + + /** * Schickt einen HTTP-Status zum Client und beendet das Skript. * @@ -496,23 +457,22 @@ class Http * @param String $message Eigener Hinweistext (Default: leer) * @param String $reason Technischer Grund (Default: leer) */ - private static function sendStatus( $status=501,$text='Internal Server Error',$message='',$reason='' ) + private static function sendStatus($status = 501, $text = 'Internal Server Error', $message = '', $reason = '') { - if ( headers_sent() ) - { + if (headers_sent()) { echo "$status $text\n$message"; exit; } - - header('HTTP/1.0 '.intval($status).' '.$text); - - + + header('HTTP/1.0 ' . intval($status) . ' ' . $text); + + $types = Http::getAccept(); - - header('Content-Type: text/html'); - $message = htmlentities($message); - $reason = htmlentities($reason ); - echo <<<HTML + + header('Content-Type: text/html'); + $message = htmlentities($message); + $reason = htmlentities($reason); + echo <<<HTML <h1>$text</h1> <p>$message</p> <pre><?php echo $reason; ?></pre> @@ -521,8 +481,8 @@ class Http HTML; exit; } - - + + /** * Liefert den Mime-Type, den der Browser (oder besser: HTTP-Client) wünscht. * @@ -531,54 +491,46 @@ HTML; public static function getAccept() { $httpAccept = getenv('HTTP_ACCEPT'); - return $types = explode(',',$httpAccept); + return $types = explode(',', $httpAccept); } - - + /** * Liefert die IPv4-Adresse des Clients. Falls der Request durch einen Proxy kam, wird * versucht, die echte IP-Adresse aus dem Anfrageheader zu ermitteln. - * + * * @return Client-IPv4-Adresse */ public static function getClientIP() { $ip = ''; - - if ( isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ) - { + + if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) { $ip = $_SERVER["HTTP_X_FORWARDED_FOR"]; - } - elseif ( isset($_SERVER["HTTP_CLIENT_IP"]) ) - { + } elseif (isset($_SERVER["HTTP_CLIENT_IP"])) { $ip = $_SERVER["HTTP_CLIENT_IP"]; - } - elseif ( isset($_SERVER["REMOTE_ADDR"]) ) - { + } elseif (isset($_SERVER["REMOTE_ADDR"])) { $ip = $_SERVER["REMOTE_ADDR"]; } - + return $ip; } - - + /** * Ermittelt den TCP/IP-Port des Clients. * Achtung, bei Proxy-Zugriffen kann dies der Port des Proxys sein. - * + * * @return string TCP/IP-Port */ public static function getClientPort() { $ip = ''; - - if ( isset($_SERVER["REMOTE_PORT"]) ) - { + + if (isset($_SERVER["REMOTE_PORT"])) { $ip = $_SERVER["REMOTE_PORT"]; } - + return $ip; } } diff --git a/modules/util/JSqueeze.class.php b/modules/util/JSqueeze.class.php @@ -58,1007 +58,1032 @@ * - Munge primitives: var WINDOW=window, etc. */ +namespace util; class JSqueeze { - const - - SPECIAL_VAR_PACKER = '(\$+[a-zA-Z_]|_[a-zA-Z0-9$])[a-zA-Z0-9_$]*'; - - public - - $charFreq; - - protected - - $strings, - $closures, - $str0, - $str1, - $argFreq, - $specialVarRx, - $keepImportantComments, - - $varRx = '(?:[a-zA-Z_$])[a-zA-Z0-9_$]*', - $reserved = array( - // Literals - 'true','false','null', - // ES6 - 'break','case','class','catch','const','continue','debugger','default','delete','do','else','export','extends','finally','for','function','if','import','in','instanceof','new','return','super','switch','this','throw','try','typeof','var','void','while','with','yield', - // Future - 'enum', - // Strict mode - 'implements','package','protected','static','let','interface','private','public', - // Module - 'await', - // Older standards - 'abstract','boolean','byte','char','double','final','float','goto','int','long','native','short','synchronized','throws','transient','volatile', - ); - - public function __construct() - { - $this->reserved = array_flip($this->reserved); - $this->charFreq = array_fill(0, 256, 0); - } - - /** - * Squeezes a JavaScript source code. - * - * Set $singleLine to false if you want optional - * semi-colons to be replaced by line feeds. - * - * Set $keepImportantComments to false if you want /*! comments to be removed. - * - * $specialVarRx defines the regular expression of special variables names - * for global vars, methods, properties and in string substitution. - * Set it to false if you don't want any. - * - * If the analysed javascript source contains a single line comment like - * this one, then the directive will overwrite $specialVarRx: - * - * // jsqueeze.specialVarRx = your_special_var_regexp_here - * - * Only the first directive is parsed, others are ignored. It is not possible - * to redefine $specialVarRx in the middle of the javascript source. - * - * Example: - * $parser = new JSqueeze; - * $squeezed_js = $parser->squeeze($fat_js); - */ - public function squeeze($code, $singleLine = true, $keepImportantComments = true, $specialVarRx = false) - { - $code = trim($code); - if ('' === $code) { - return ''; - } - - $this->argFreq = array(-1 => 0); - $this->specialVarRx = $specialVarRx; - $this->keepImportantComments = !!$keepImportantComments; - - if (preg_match("#//[ \t]*jsqueeze\.specialVarRx[ \t]*=[ \t]*([\"']?)(.*)\\1#i", $code, $key)) { - if (!$key[1]) { - $key[2] = trim($key[2]); - $key[1] = strtolower($key[2]); - $key[1] = $key[1] && $key[1] != 'false' && $key[1] != 'none' && $key[1] != 'off'; - } - - $this->specialVarRx = $key[1] ? $key[2] : false; - } - - // Remove capturing parentheses - $this->specialVarRx && $this->specialVarRx = preg_replace('/(?<!\\\\)((?:\\\\\\\\)*)\((?!\?)/', '(?:', $this->specialVarRx); - - false !== strpos($code, "\r") && $code = strtr(str_replace("\r\n", "\n", $code), "\r", "\n"); - false !== strpos($code, "\xC2\x85") && $code = str_replace("\xC2\x85", "\n", $code); // Next Line - false !== strpos($code, "\xE2\x80\xA8") && $code = str_replace("\xE2\x80\xA8", "\n", $code); // Line Separator - false !== strpos($code, "\xE2\x80\xA9") && $code = str_replace("\xE2\x80\xA9", "\n", $code); // Paragraph Separator - - list($code, $this->strings) = $this->extractStrings($code); - list($code, $this->closures) = $this->extractClosures($code); - - $key = "//''\"\"#0'"; // This crap has a wonderful property: it can not happen in any valid javascript, even in strings - $this->closures[$key] = &$code; - - $tree = array($key => array('parent' => false)); - $this->makeVars($code, $tree[$key], $key); - $this->renameVars($tree[$key], true); - - $code = substr($tree[$key]['code'], 1); - $code = preg_replace("'\breturn !'", 'return!', $code); - $code = preg_replace("'\}(?=(else|while)[^\$.a-zA-Z0-9_])'", "}\r", $code); - $code = str_replace(array_keys($this->strings), array_values($this->strings), $code); - - if ($singleLine) { - $code = strtr($code, "\n", ';'); - } else { - $code = str_replace("\n", ";\n", $code); - } - false !== strpos($code, "\r") && $code = strtr(trim($code), "\r", "\n"); - - // Cleanup memory - $this->charFreq = array_fill(0, 256, 0); - $this->strings = $this->closures = $this->argFreq = array(); - $this->str0 = $this->str1 = ''; - - return $code; - } - - protected function extractStrings($f) - { - if ($cc_on = false !== strpos($f, '@cc_on')) { - // Protect conditional comments from being removed - $f = str_replace('#', '##', $f); - $f = str_replace('/*@', '1#@', $f); - $f = preg_replace("'//@([^\n]+)'", '2#@$1@#3', $f); - $f = str_replace('@*/', '@#1', $f); - } - - $len = strlen($f); - $code = str_repeat(' ', $len); - $j = 0; - - $strings = array(); - $K = 0; - - $instr = false; - - $q = array( - "'", '"', - "'" => 0, - '"' => 0, - ); - - // Extract strings, removes comments - for ($i = 0; $i < $len; ++$i) { - if ($instr) { - if ('//' == $instr) { - if ("\n" == $f[$i]) { - $f[$i--] = ' '; - $instr = false; - } - } elseif ($f[$i] == $instr || ('/' == $f[$i] && "/'" == $instr)) { - if ('!' == $instr) { - } elseif ('*' == $instr) { - if ('/' == $f[$i + 1]) { - ++$i; - $instr = false; - } - } else { - if ("/'" == $instr) { - while (isset($f[$i + 1]) && false !== strpos('gmi', $f[$i + 1])) { - $s[] = $f[$i++]; - } - $s[] = $f[$i]; - } - - $instr = false; - } - } elseif ('*' == $instr) { - } elseif ('!' == $instr) { - if ('*' == $f[$i] && '/' == $f[$i + 1]) { - $s[] = "*/\r"; - ++$i; - $instr = false; - } elseif ("\n" == $f[$i]) { - $s[] = "\r"; - } else { - $s[] = $f[$i]; - } - } elseif ('\\' == $f[$i]) { - ++$i; - - if ("\n" != $f[$i]) { - isset($q[$f[$i]]) && ++$q[$f[$i]]; - $s[] = '\\'.$f[$i]; - } - } elseif ('[' == $f[$i] && "/'" == $instr) { - $instr = '/['; - $s[] = '['; - } elseif (']' == $f[$i] && '/[' == $instr) { - $instr = "/'"; - $s[] = ']'; - } elseif ("'" == $f[$i] || '"' == $f[$i]) { - ++$q[$f[$i]]; - $s[] = '\\'.$f[$i]; - } else { - $s[] = $f[$i]; - } - } else { - switch ($f[$i]) { - case ';': - // Remove triple semi-colon - if ($i > 0 && ';' == $f[$i - 1] && $i + 1 < $len && ';' == $f[$i + 1]) { - $f[$i] = $f[$i + 1] = '/'; - } else { - $code[++$j] = ';'; - break; - } - - case '/': - if ('*' == $f[$i + 1]) { - ++$i; - $instr = '*'; - - if ($this->keepImportantComments && '!' == $f[$i + 1]) { - ++$i; - // no break here - } else { - break; - } - } elseif ('/' == $f[$i + 1]) { - ++$i; - $instr = '//'; - break; - } else { - $a = $j && (' ' == $code[$j] || "\x7F" == $code[$j]) ? $code[$j - 1] : $code[$j]; - if (false !== strpos('-!%&;<=>~:^+|,()*?[{} ', $a) - || (false !== strpos('oenfd', $a) - && preg_match( - "'(?<![\$.a-zA-Z0-9_])(do|else|return|typeof|yield[ \x7F]?\*?)[ \x7F]?$'", - substr($code, $j - 7, 8) - )) - ) { - if (')' === $a && $j > 1) { - $a = 1; - $k = $j - (' ' == $code[$j] || "\x7F" == $code[$j]) - 1; - while ($k >= 0 && $a) { - if ('(' === $code[$k]) { - --$a; - } elseif (')' === $code[$k]) { - ++$a; - } - --$k; - } - if (!preg_match("'(?<![\$.a-zA-Z0-9_])(if|for|while)[ \x7F]?$'", substr($code, 0, $k + 1))) { - $code[++$j] = '/'; - break; - } - } - - $key = "//''\"\"".$K++.$instr = "/'"; - $a = $j; - $code .= $key; - while (isset($key[++$j - $a - 1])) { - $code[$j] = $key[$j - $a - 1]; - } - --$j; - isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s); - $strings[$key] = array('/'); - $s = &$strings[$key]; - } else { - $code[++$j] = '/'; - } - - break; - } - - case "'": - case '"': - $instr = $f[$i]; - $key = "//''\"\"".$K++.('!' == $instr ? ']' : "'"); - $a = $j; - $code .= $key; - while (isset($key[++$j - $a - 1])) { - $code[$j] = $key[$j - $a - 1]; - } - --$j; - isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s); - $strings[$key] = array(); - $s = &$strings[$key]; - '!' == $instr && $s[] = "\r/*!"; - - break; - - case "\n": - if ($j > 3) { - if (' ' == $code[$j] || "\x7F" == $code[$j]) { - --$j; - } - - $code[++$j] = - false !== strpos('kend+-', $code[$j - 1]) - && preg_match( - "'(?:\+\+|--|(?<![\$.a-zA-Z0-9_])(break|continue|return|yield[ \x7F]?\*?))[ \x7F]?$'", - substr($code, $j - 8, 9) - ) - ? ';' : "\x7F"; - - break; - } - - case "\t": $f[$i] = ' '; - case ' ': - if (!$j || ' ' == $code[$j] || "\x7F" == $code[$j]) { - break; - } - - default: - $code[++$j] = $f[$i]; - } - } - } - - isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s); - unset($s); - - $code = substr($code, 0, $j + 1); - $cc_on && $this->restoreCc($code, false); - - // Protect wanted spaces and remove unwanted ones - $code = strtr($code, "\x7F", ' '); - $code = str_replace('- -', "-\x7F-", $code); - $code = str_replace('+ +', "+\x7F+", $code); - $code = preg_replace("'(\d)\s+\.\s*([a-zA-Z\$_[(])'", "$1\x7F.$2", $code); - $code = preg_replace("# ([-!%&;<=>~:.^+|,()*?[\]{}/']+)#", '$1', $code); - $code = preg_replace("#([-!%&;<=>~:.^+|,()*?[\]{}/]+) #", '$1', $code); - $cc_on && $code = preg_replace_callback("'//[^\'].*?@#3'", function ($m) { return strtr($m[0], ' ', "\x7F"); }, $code); - - // Replace new Array/Object by []/{} - false !== strpos($code, 'new Array') && $code = preg_replace("'new Array(?:\(\)|([;\])},:]))'", '[]$1', $code); - false !== strpos($code, 'new Object') && $code = preg_replace("'new Object(?:\(\)|([;\])},:]))'", '{}$1', $code); - - // Add missing semi-colons after curly braces - // This adds more semi-colons than strictly needed, - // but it seems that later gzipping is favorable to the repetition of "};" - $code = preg_replace("'\}(?![:,;.()\[\]}\|&]|(else|catch|finally|while)[^\$.a-zA-Z0-9_])'", '};', $code); - - // Tag possible empty instruction for easy detection - $code = preg_replace("'(?<![\$.a-zA-Z0-9_])if\('", '1#(', $code); - $code = preg_replace("'(?<![\$.a-zA-Z0-9_])for\('", '2#(', $code); - $code = preg_replace("'(?<![\$.a-zA-Z0-9_])while\('", '3#(', $code); - - $forPool = array(); - $instrPool = array(); - $s = 0; - - $f = array(); - $j = -1; - - // Remove as much semi-colon as possible - $len = strlen($code); - for ($i = 0; $i < $len; ++$i) { - switch ($code[$i]) { - case '(': - if ($j >= 0 && "\n" == $f[$j]) { - $f[$j] = ';'; - } - - ++$s; - - if ($i && '#' == $code[$i - 1]) { - $instrPool[$s - 1] = 1; - if ('2' == $code[$i - 2]) { - $forPool[$s] = 1; - } - } - - $f[++$j] = '('; - break; - - case ']': - case ')': - if ($i + 1 < $len && !isset($forPool[$s]) && !isset($instrPool[$s - 1]) && preg_match("'[a-zA-Z0-9_\$]'", $code[$i + 1])) { - $f[$j] .= $code[$i]; - $f[++$j] = "\n"; - } else { - $f[++$j] = $code[$i]; - } - - if (')' == $code[$i]) { - unset($forPool[$s]); - --$s; - } - - continue 2; - - case '}': - if ("\n" == $f[$j]) { - $f[$j] = '}'; - } else { - $f[++$j] = '}'; - } - break; - - case ';': - if (isset($forPool[$s]) || isset($instrPool[$s])) { - $f[++$j] = ';'; - } elseif ($j >= 0 && "\n" != $f[$j] && ';' != $f[$j]) { - $f[++$j] = "\n"; - } - - break; - - case '#': - switch ($f[$j]) { - case '1': $f[$j] = 'if'; break 2; - case '2': $f[$j] = 'for'; break 2; - case '3': $f[$j] = 'while'; break 2; - } - - case '['; - if ($j >= 0 && "\n" == $f[$j]) { - $f[$j] = ';'; - } - - default: $f[++$j] = $code[$i]; - } - - unset($instrPool[$s]); - } - - $f = implode('', $f); - $cc_on && $f = str_replace('@#3', "\r", $f); - - // Fix "else ;" empty instructions - $f = preg_replace("'(?<![\$.a-zA-Z0-9_])else\n'", "\n", $f); - - $r1 = array( // keywords with a direct object - 'case','delete','do','else','function','in','instanceof','of','break', - 'new','return','throw','typeof','var','void','yield','let','if', - 'const','get','set', - ); - - $r2 = array( // keywords with a subject - 'in','instanceof','of', - ); - - // Fix missing semi-colons - $f = preg_replace("'(?<!(?<![a-zA-Z0-9_\$])".implode(')(?<!(?<![a-zA-Z0-9_\$])', $r1).') (?!('.implode('|', $r2).")(?![a-zA-Z0-9_\$]))'", "\n", $f); - $f = preg_replace("'(?<!(?<![a-zA-Z0-9_\$])do)(?<!(?<![a-zA-Z0-9_\$])else) if\('", "\nif(", $f); - $f = preg_replace("'(?<=--|\+\+)(?<![a-zA-Z0-9_\$])(".implode('|', $r1).")(?![a-zA-Z0-9_\$])'", "\n$1", $f); - $f = preg_replace("'(?<![a-zA-Z0-9_\$])for\neach\('", 'for each(', $f); - $f = preg_replace("'(?<![a-zA-Z0-9_\$])\n(".implode('|', $r2).")(?![a-zA-Z0-9_\$])'", '$1', $f); - - // Merge strings - if ($q["'"] > $q['"']) { - $q = array($q[1], $q[0]); - } - $f = preg_replace("#//''\"\"[0-9]+'#", $q[0].'$0'.$q[0], $f); - strpos($f, $q[0].'+'.$q[0]) && $f = str_replace($q[0].'+'.$q[0], '', $f); - $len = count($strings); - foreach ($strings as $r1 => &$r2) { - $r2 = "/'" == substr($r1, -2) - ? str_replace(array("\\'", '\\"'), array("'", '"'), $r2) - : str_replace('\\'.$q[1], $q[1], $r2); - } - - // Restore wanted spaces - $f = strtr($f, "\x7F", ' '); - - return array($f, $strings); - } - - protected function extractClosures($code) - { - $code = ';'.$code; - - $this->argFreq[-1] += substr_count($code, '}catch('); - - if ($this->argFreq[-1]) { - // Special catch scope handling - - // FIXME: this implementation doesn't work with nested catch scopes who need - // access to their parent's caught variable (but who needs that?). - - $f = preg_split("@}catch\(({$this->varRx})@", $code, -1, PREG_SPLIT_DELIM_CAPTURE); - - $code = 'catch$scope$var'.mt_rand(); - $this->specialVarRx = $this->specialVarRx ? '(?:'.$this->specialVarRx.'|'.preg_quote($code).')' : preg_quote($code); - $i = count($f) - 1; - - while ($i) { - $c = 1; - $j = 0; - $l = strlen($f[$i]); - - while ($c && $j < $l) { - $s = $f[$i][$j++]; - $c += '(' == $s ? 1 : (')' == $s ? -1 : 0); - } - - if (!$c) { - do { - $s = $f[$i][$j++]; - $c += '{' == $s ? 1 : ('}' == $s ? -1 : 0); - } while ($c && $j < $l); - } - - $c = preg_quote($f[$i - 1], '#'); - $f[$i - 2] .= '}catch('.preg_replace("#([.,{]?)(?<![a-zA-Z0-9_\$@]){$c}\\b#", '$1'.$code, $f[$i - 1].substr($f[$i], 0, $j)).substr($f[$i], $j); - - unset($f[$i--], $f[$i--]); - } - - $code = $f[0]; - } - - $f = preg_split("'(?<![a-zA-Z0-9_\$])((?:function[ (]|get |set ).*?\{)'", $code, -1, PREG_SPLIT_DELIM_CAPTURE); - $i = count($f) - 1; - $closures = array(); - - while ($i) { - $c = 1; - $j = 0; - $l = strlen($f[$i]); - - while ($c && $j < $l) { - $s = $f[$i][$j++]; - $c += '{' == $s ? 1 : ('}' == $s ? -1 : 0); - } - - switch (substr($f[$i - 2], -1)) { - default: - if (false !== $c = strpos($f[$i - 1], ' ', 8)) { - break; - } - case false: case "\n": case ';': case '{': case '}': case ')': case ']': - $c = strpos($f[$i - 1], '(', 4); - } - - $l = "//''\"\"#$i'"; - $code = substr($f[$i - 1], $c); - $closures[$l] = $code.substr($f[$i], 0, $j); - $f[$i - 2] .= substr($f[$i - 1], 0, $c).$l.substr($f[$i], $j); - - if ('(){' !== $code) { - $j = substr_count($code, ','); - do { - isset($this->argFreq[$j]) ? ++$this->argFreq[$j] : $this->argFreq[$j] = 1; - } while ($j--); - } - - $i -= 2; - } - - return array($f[0], $closures); - } - - protected function makeVars($closure, &$tree, $key) - { - $tree['code'] = &$closure; - $tree['nfe'] = false; - $tree['used'] = array(); - $tree['local'] = array(); - - // Replace multiple "var" declarations by a single one - $closure = preg_replace_callback("'(?<=[\n\{\}])var [^\n\{\};]+(?:\nvar [^\n\{\};]+)+'", array($this, 'mergeVarDeclarations'), $closure); - - // Get all local vars (functions, arguments and "var" prefixed) - - $vars = &$tree['local']; - - if (preg_match("'^( [^(]*)?\((.*?)\)\{'", $closure, $v)) { - if ($v[1]) { - $vars[$tree['nfe'] = substr($v[1], 1)] = -1; - $tree['parent']['local'][';'.$key] = &$vars[$tree['nfe']]; - } - - if ($v[2]) { - $i = 0; - $v = explode(',', $v[2]); - foreach ($v as $w) { - $vars[$w] = $this->argFreq[$i++] - 1; // Give a bonus to argument variables - } - } - } - - $v = preg_split("'(?<![\$.a-zA-Z0-9_])var '", $closure); - if ($i = count($v) - 1) { - $w = array(); - - while ($i) { - $j = $c = 0; - $l = strlen($v[$i]); - - while ($j < $l) { - switch ($v[$i][$j]) { - case '(': case '[': case '{': - ++$c; - break; - - case ')': case ']': case '}': - if ($c-- <= 0) { - break 2; - } - break; - - case ';': case "\n": - if (!$c) { - break 2; - } - - default: - $c || $w[] = $v[$i][$j]; - } - - ++$j; - } - - $w[] = ','; - --$i; - } - - $v = explode(',', implode('', $w)); - foreach ($v as $w) { - if (preg_match("'^{$this->varRx}'", $w, $v)) { - isset($vars[$v[0]]) || $vars[$v[0]] = 0; - } - } - } - - if (preg_match_all("@function ({$this->varRx})//''\"\"#@", $closure, $v)) { - foreach ($v[1] as $w) { - isset($vars[$w]) || $vars[$w] = 0; - } - } - - if ($this->argFreq[-1] && preg_match_all("@}catch\(({$this->varRx})@", $closure, $v)) { - $v[0] = array(); - foreach ($v[1] as $w) { - isset($v[0][$w]) ? ++$v[0][$w] : $v[0][$w] = 1; - } - foreach ($v[0] as $w => $v) { - $vars[$w] = $this->argFreq[-1] - $v; - } - } - - // Get all used vars, local and non-local - - $vars = &$tree['used']; - - if (preg_match_all("#([.,{]?(?:[gs]et )?)(?<![a-zA-Z0-9_\$])({$this->varRx})(:?)#", $closure, $w, PREG_SET_ORDER)) { - foreach ($w as $k) { - if (isset($k[1][0]) && (',' === $k[1][0] || '{' === $k[1][0])) { - if (':' === $k[3]) { - $k = '.'.$k[2]; - } elseif ('get ' === substr($k[1], 1, 4) || 'set ' === substr($k[1], 1, 4)) { - ++$this->charFreq[ord($k[1][1])]; // "g" or "s" - ++$this->charFreq[101]; // "e" - ++$this->charFreq[116]; // "t" - $k = '.'.$k[2]; - } else { - $k = $k[2]; - } - } else { - $k = $k[1].$k[2]; - } - - isset($vars[$k]) ? ++$vars[$k] : $vars[$k] = 1; - } - } - - if (preg_match_all("#//''\"\"[0-9]+(?:['!]|/')#", $closure, $w)) { - foreach ($w[0] as $a) { - $v = "'" === substr($a, -1) && "/'" !== substr($a, -2) && $this->specialVarRx - ? preg_split("#([.,{]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->specialVarRx}:?)#", $this->strings[$a], -1, PREG_SPLIT_DELIM_CAPTURE) - : array($this->strings[$a]); - $a = count($v); - - for ($i = 0; $i < $a; ++$i) { - $k = $v[$i]; - - if (1 === $i % 2) { - if (',' === $k[0] || '{' === $k[0]) { - if (':' === substr($k, -1)) { - $k = '.'.substr($k, 1, -1); - } elseif ('get ' === substr($k, 1, 4) || 'set ' === substr($k, 1, 4)) { - ++$this->charFreq[ord($k[1])]; // "g" or "s" - ++$this->charFreq[101]; // "e" - ++$this->charFreq[116]; // "t" - $k = '.'.substr($k, 5); - } else { - $k = substr($k, 1); - } - } elseif (':' === substr($k, -1)) { - $k = substr($k, 0, -1); - } - - $w = &$tree; - - while (isset($w['parent']) && !(isset($w['used'][$k]) || isset($w['local'][$k]))) { - $w = &$w['parent']; - } - - (isset($w['used'][$k]) || isset($w['local'][$k])) && (isset($vars[$k]) ? ++$vars[$k] : $vars[$k] = 1); - - unset($w); - } - - if (0 === $i % 2 || !isset($vars[$k])) { - foreach (count_chars($v[$i], 1) as $k => $w) { - $this->charFreq[$k] += $w; - } - } - } - } - } - - // Propagate the usage number to parents - - foreach ($vars as $w => $a) { - $k = &$tree; - $chain = array(); - do { - $vars = &$k['local']; - $chain[] = &$k; - if (isset($vars[$w])) { - unset($k['used'][$w]); - if (isset($vars[$w])) { - $vars[$w] += $a; - } else { - $vars[$w] = $a; - } - $a = false; - break; - } - } while ($k['parent'] && $k = &$k['parent']); - - if ($a && !$k['parent']) { - if (isset($vars[$w])) { - $vars[$w] += $a; - } else { - $vars[$w] = $a; - } - } - - if (isset($tree['used'][$w]) && isset($vars[$w])) { - foreach ($chain as &$b) { - isset($b['local'][$w]) || $b['used'][$w] = &$vars[$w]; - } - } - } - - // Analyse childs - - $tree['childs'] = array(); - $vars = &$tree['childs']; - - if (preg_match_all("@//''\"\"#[0-9]+'@", $closure, $w)) { - foreach ($w[0] as $a) { - $vars[$a] = array('parent' => &$tree); - $this->makeVars($this->closures[$a], $vars[$a], $a); - } - } - } - - protected function mergeVarDeclarations($m) - { - return str_replace("\nvar ", ',', $m[0]); - } - - protected function renameVars(&$tree, $root) - { - if ($root) { - $tree['local'] += $tree['used']; - $tree['used'] = array(); - - foreach ($tree['local'] as $k => $v) { - if ('.' == $k[0]) { - $k = substr($k, 1); - } - - if ('true' === $k) { - $this->charFreq[48] += $v; - } elseif ('false' === $k) { - $this->charFreq[49] += $v; - } elseif (!$this->specialVarRx || !preg_match("#^{$this->specialVarRx}$#", $k)) { - foreach (count_chars($k, 1) as $k => $w) { - $this->charFreq[$k] += $w * $v; - } - } elseif (2 == strlen($k)) { - $tree['used'][] = $k[1]; - } - } - - $this->charFreq = $this->rsort($this->charFreq); - - $this->str0 = ''; - $this->str1 = ''; - - foreach ($this->charFreq as $k => $v) { - if (!$v) { - break; - } - - $v = chr($k); - - if ((64 < $k && $k < 91) || (96 < $k && $k < 123)) { // A-Z a-z - $this->str0 .= $v; - $this->str1 .= $v; - } elseif (47 < $k && $k < 58) { // 0-9 - $this->str1 .= $v; - } - } - - if ('' === $this->str0) { - $this->str0 = 'claspemitdbfrugnjvhowkxqyzCLASPEMITDBFRUGNJVHOWKXQYZ'; - $this->str1 = $this->str0.'0123456789'; - } - - foreach ($tree['local'] as $var => $root) { - if ('.' != substr($var, 0, 1) && isset($tree['local'][".{$var}"])) { - $tree['local'][$var] += $tree['local'][".{$var}"]; - } - } - - foreach ($tree['local'] as $var => $root) { - if ('.' == substr($var, 0, 1) && isset($tree['local'][substr($var, 1)])) { - $tree['local'][$var] = $tree['local'][substr($var, 1)]; - } - } - - $tree['local'] = $this->rsort($tree['local']); - - foreach ($tree['local'] as $var => $root) { - switch (substr($var, 0, 1)) { - case '.': - if (!isset($tree['local'][substr($var, 1)])) { - $tree['local'][$var] = '#'.($this->specialVarRx && 3 < strlen($var) && preg_match("'^\.{$this->specialVarRx}$'", $var) ? $this->getNextName($tree).'$' : substr($var, 1)); - } - break; - - case ';': $tree['local'][$var] = 0 === $root ? '' : $this->getNextName($tree); - case '#': break; - - default: - $root = $this->specialVarRx && 2 < strlen($var) && preg_match("'^{$this->specialVarRx}$'", $var) ? $this->getNextName($tree).'$' : $var; - $tree['local'][$var] = $root; - if (isset($tree['local'][".{$var}"])) { - $tree['local'][".{$var}"] = '#'.$root; - } - } - } - - foreach ($tree['local'] as $var => $root) { - $tree['local'][$var] = preg_replace("'^#'", '.', $tree['local'][$var]); - } - } else { - $tree['local'] = $this->rsort($tree['local']); - if (false !== $tree['nfe']) { - $tree['used'][] = $tree['local'][$tree['nfe']]; - } - - foreach ($tree['local'] as $var => $root) { - if ($tree['nfe'] !== $var) { - $tree['local'][$var] = 0 === $root ? '' : $this->getNextName($tree); - } - } - } - - $this->local_tree = &$tree['local']; - $this->used_tree = &$tree['used']; - - $tree['code'] = preg_replace_callback("#[.,{ ]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->varRx}:?#", array($this, 'getNewName'), $tree['code']); - - if ($this->specialVarRx && preg_match_all("#//''\"\"[0-9]+'#", $tree['code'], $b)) { - foreach ($b[0] as $a) { - $this->strings[$a] = preg_replace_callback( - "#[.,{]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->specialVarRx}:?#", - array($this, 'getNewName'), - $this->strings[$a] - ); - } - } - - foreach ($tree['childs'] as $a => &$b) { - $this->renameVars($b, false); - $tree['code'] = str_replace($a, $b['code'], $tree['code']); - unset($tree['childs'][$a]); - } - } - - protected function getNewName($m) - { - $m = $m[0]; - - $pre = '.' === $m[0] ? '.' : ''; - $post = ''; - - if (',' === $m[0] || '{' === $m[0] || ' ' === $m[0]) { - $pre = $m[0]; - - if (':' === substr($m, -1)) { - $post = ':'; - $m = (' ' !== $m[0] ? '.' : '').substr($m, 1, -1); - } elseif ('get ' === substr($m, 1, 4) || 'set ' === substr($m, 1, 4)) { - $pre .= substr($m, 1, 4); - $m = '.'.substr($m, 5); - } else { - $m = substr($m, 1); - } - } elseif (':' === substr($m, -1)) { - $post = ':'; - $m = substr($m, 0, -1); - } - - $post = (isset($this->reserved[$m]) - ? ('true' === $m ? '!0' : ('false' === $m ? '!1' : $m)) - : ( - isset($this->local_tree[$m]) - ? $this->local_tree[$m] - : ( - isset($this->used_tree[$m]) - ? $this->used_tree[$m] - : $m - ) - ) - ).$post; - - return '' === $post ? '' : ($pre.('.' === $post[0] ? substr($post, 1) : $post)); - } - - protected function getNextName(&$tree = array(), &$counter = false) - { - if (false === $counter) { - $counter = &$tree['counter']; - isset($counter) || $counter = -1; - $exclude = array_flip($tree['used']); - } else { - $exclude = $tree; - } - - ++$counter; - - $len0 = strlen($this->str0); - $len1 = strlen($this->str0); - - $name = $this->str0[$counter % $len0]; - - $i = intval($counter / $len0) - 1; - while ($i >= 0) { - $name .= $this->str1[ $i % $len1 ]; - $i = intval($i / $len1) - 1; - } - - return !(isset($this->reserved[$name]) || isset($exclude[$name])) ? $name : $this->getNextName($exclude, $counter); - } - - protected function restoreCc(&$s, $lf = true) - { - $lf && $s = str_replace('@#3', '', $s); - - $s = str_replace('@#1', '@*/', $s); - $s = str_replace('2#@', '//@', $s); - $s = str_replace('1#@', '/*@', $s); - $s = str_replace('##', '#', $s); - } - - private function rsort($array) - { - if (!$array) { - return $array; - } - - $i = 0; - $tuples = array(); - foreach ($array as $k => &$v) { - $tuples[] = array(++$i, $k, &$v); - } - - usort($tuples, function ($a, $b) { - if ($b[2] > $a[2]) { - return 1; - } - if ($b[2] < $a[2]) { - return -1; - } - if ($b[0] > $a[0]) { - return -1; - } - if ($b[0] < $a[0]) { - return 1; - } - - return 0; - }); - - $array = array(); - - foreach ($tuples as $t) { - $array[$t[1]] = &$t[2]; - } - - return $array; - } + const + + SPECIAL_VAR_PACKER = '(\$+[a-zA-Z_]|_[a-zA-Z0-9$])[a-zA-Z0-9_$]*'; + + public + + $charFreq; + + protected + + $strings, + $closures, + $str0, + $str1, + $argFreq, + $specialVarRx, + $keepImportantComments, + + $varRx = '(?:[a-zA-Z_$])[a-zA-Z0-9_$]*', + $reserved = array( + // Literals + 'true', 'false', 'null', + // ES6 + 'break', 'case', 'class', 'catch', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'export', 'extends', 'finally', 'for', 'function', 'if', 'import', 'in', 'instanceof', 'new', 'return', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield', + // Future + 'enum', + // Strict mode + 'implements', 'package', 'protected', 'static', 'let', 'interface', 'private', 'public', + // Module + 'await', + // Older standards + 'abstract', 'boolean', 'byte', 'char', 'double', 'final', 'float', 'goto', 'int', 'long', 'native', 'short', 'synchronized', 'throws', 'transient', 'volatile', + ); + + public function __construct() + { + $this->reserved = array_flip($this->reserved); + $this->charFreq = array_fill(0, 256, 0); + } + + /** + * Squeezes a JavaScript source code. + * + * Set $singleLine to false if you want optional + * semi-colons to be replaced by line feeds. + * + * Set $keepImportantComments to false if you want /*! comments to be removed. + * + * $specialVarRx defines the regular expression of special variables names + * for global vars, methods, properties and in string substitution. + * Set it to false if you don't want any. + * + * If the analysed javascript source contains a single line comment like + * this one, then the directive will overwrite $specialVarRx: + * + * // jsqueeze.specialVarRx = your_special_var_regexp_here + * + * Only the first directive is parsed, others are ignored. It is not possible + * to redefine $specialVarRx in the middle of the javascript source. + * + * Example: + * $parser = new JSqueeze; + * $squeezed_js = $parser->squeeze($fat_js); + */ + public function squeeze($code, $singleLine = true, $keepImportantComments = true, $specialVarRx = false) + { + $code = trim($code); + if ('' === $code) { + return ''; + } + + $this->argFreq = array(-1 => 0); + $this->specialVarRx = $specialVarRx; + $this->keepImportantComments = !!$keepImportantComments; + + if (preg_match("#//[ \t]*jsqueeze\.specialVarRx[ \t]*=[ \t]*([\"']?)(.*)\\1#i", $code, $key)) { + if (!$key[1]) { + $key[2] = trim($key[2]); + $key[1] = strtolower($key[2]); + $key[1] = $key[1] && $key[1] != 'false' && $key[1] != 'none' && $key[1] != 'off'; + } + + $this->specialVarRx = $key[1] ? $key[2] : false; + } + + // Remove capturing parentheses + $this->specialVarRx && $this->specialVarRx = preg_replace('/(?<!\\\\)((?:\\\\\\\\)*)\((?!\?)/', '(?:', $this->specialVarRx); + + false !== strpos($code, "\r") && $code = strtr(str_replace("\r\n", "\n", $code), "\r", "\n"); + false !== strpos($code, "\xC2\x85") && $code = str_replace("\xC2\x85", "\n", $code); // Next Line + false !== strpos($code, "\xE2\x80\xA8") && $code = str_replace("\xE2\x80\xA8", "\n", $code); // Line Separator + false !== strpos($code, "\xE2\x80\xA9") && $code = str_replace("\xE2\x80\xA9", "\n", $code); // Paragraph Separator + + list($code, $this->strings) = $this->extractStrings($code); + list($code, $this->closures) = $this->extractClosures($code); + + $key = "//''\"\"#0'"; // This crap has a wonderful property: it can not happen in any valid javascript, even in strings + $this->closures[$key] = &$code; + + $tree = array($key => array('parent' => false)); + $this->makeVars($code, $tree[$key], $key); + $this->renameVars($tree[$key], true); + + $code = substr($tree[$key]['code'], 1); + $code = preg_replace("'\breturn !'", 'return!', $code); + $code = preg_replace("'\}(?=(else|while)[^\$.a-zA-Z0-9_])'", "}\r", $code); + $code = str_replace(array_keys($this->strings), array_values($this->strings), $code); + + if ($singleLine) { + $code = strtr($code, "\n", ';'); + } else { + $code = str_replace("\n", ";\n", $code); + } + false !== strpos($code, "\r") && $code = strtr(trim($code), "\r", "\n"); + + // Cleanup memory + $this->charFreq = array_fill(0, 256, 0); + $this->strings = $this->closures = $this->argFreq = array(); + $this->str0 = $this->str1 = ''; + + return $code; + } + + protected function extractStrings($f) + { + if ($cc_on = false !== strpos($f, '@cc_on')) { + // Protect conditional comments from being removed + $f = str_replace('#', '##', $f); + $f = str_replace('/*@', '1#@', $f); + $f = preg_replace("'//@([^\n]+)'", '2#@$1@#3', $f); + $f = str_replace('@*/', '@#1', $f); + } + + $len = strlen($f); + $code = str_repeat(' ', $len); + $j = 0; + + $strings = array(); + $K = 0; + + $instr = false; + + $q = array( + "'", '"', + "'" => 0, + '"' => 0, + ); + + // Extract strings, removes comments + for ($i = 0; $i < $len; ++$i) { + if ($instr) { + if ('//' == $instr) { + if ("\n" == $f[$i]) { + $f[$i--] = ' '; + $instr = false; + } + } elseif ($f[$i] == $instr || ('/' == $f[$i] && "/'" == $instr)) { + if ('!' == $instr) { + } elseif ('*' == $instr) { + if ('/' == $f[$i + 1]) { + ++$i; + $instr = false; + } + } else { + if ("/'" == $instr) { + while (isset($f[$i + 1]) && false !== strpos('gmi', $f[$i + 1])) { + $s[] = $f[$i++]; + } + $s[] = $f[$i]; + } + + $instr = false; + } + } elseif ('*' == $instr) { + } elseif ('!' == $instr) { + if ('*' == $f[$i] && '/' == $f[$i + 1]) { + $s[] = "*/\r"; + ++$i; + $instr = false; + } elseif ("\n" == $f[$i]) { + $s[] = "\r"; + } else { + $s[] = $f[$i]; + } + } elseif ('\\' == $f[$i]) { + ++$i; + + if ("\n" != $f[$i]) { + isset($q[$f[$i]]) && ++$q[$f[$i]]; + $s[] = '\\' . $f[$i]; + } + } elseif ('[' == $f[$i] && "/'" == $instr) { + $instr = '/['; + $s[] = '['; + } elseif (']' == $f[$i] && '/[' == $instr) { + $instr = "/'"; + $s[] = ']'; + } elseif ("'" == $f[$i] || '"' == $f[$i]) { + ++$q[$f[$i]]; + $s[] = '\\' . $f[$i]; + } else { + $s[] = $f[$i]; + } + } else { + switch ($f[$i]) { + case ';': + // Remove triple semi-colon + if ($i > 0 && ';' == $f[$i - 1] && $i + 1 < $len && ';' == $f[$i + 1]) { + $f[$i] = $f[$i + 1] = '/'; + } else { + $code[++$j] = ';'; + break; + } + + case '/': + if ('*' == $f[$i + 1]) { + ++$i; + $instr = '*'; + + if ($this->keepImportantComments && '!' == $f[$i + 1]) { + ++$i; + // no break here + } else { + break; + } + } elseif ('/' == $f[$i + 1]) { + ++$i; + $instr = '//'; + break; + } else { + $a = $j && (' ' == $code[$j] || "\x7F" == $code[$j]) ? $code[$j - 1] : $code[$j]; + if (false !== strpos('-!%&;<=>~:^+|,()*?[{} ', $a) + || (false !== strpos('oenfd', $a) + && preg_match( + "'(?<![\$.a-zA-Z0-9_])(do|else|return|typeof|yield[ \x7F]?\*?)[ \x7F]?$'", + substr($code, $j - 7, 8) + )) + ) { + if (')' === $a && $j > 1) { + $a = 1; + $k = $j - (' ' == $code[$j] || "\x7F" == $code[$j]) - 1; + while ($k >= 0 && $a) { + if ('(' === $code[$k]) { + --$a; + } elseif (')' === $code[$k]) { + ++$a; + } + --$k; + } + if (!preg_match("'(?<![\$.a-zA-Z0-9_])(if|for|while)[ \x7F]?$'", substr($code, 0, $k + 1))) { + $code[++$j] = '/'; + break; + } + } + + $key = "//''\"\"" . $K++ . $instr = "/'"; + $a = $j; + $code .= $key; + while (isset($key[++$j - $a - 1])) { + $code[$j] = $key[$j - $a - 1]; + } + --$j; + isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s); + $strings[$key] = array('/'); + $s = &$strings[$key]; + } else { + $code[++$j] = '/'; + } + + break; + } + + case "'": + case '"': + $instr = $f[$i]; + $key = "//''\"\"" . $K++ . ('!' == $instr ? ']' : "'"); + $a = $j; + $code .= $key; + while (isset($key[++$j - $a - 1])) { + $code[$j] = $key[$j - $a - 1]; + } + --$j; + isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s); + $strings[$key] = array(); + $s = &$strings[$key]; + '!' == $instr && $s[] = "\r/*!"; + + break; + + case "\n": + if ($j > 3) { + if (' ' == $code[$j] || "\x7F" == $code[$j]) { + --$j; + } + + $code[++$j] = + false !== strpos('kend+-', $code[$j - 1]) + && preg_match( + "'(?:\+\+|--|(?<![\$.a-zA-Z0-9_])(break|continue|return|yield[ \x7F]?\*?))[ \x7F]?$'", + substr($code, $j - 8, 9) + ) + ? ';' : "\x7F"; + + break; + } + + case "\t": + $f[$i] = ' '; + case ' ': + if (!$j || ' ' == $code[$j] || "\x7F" == $code[$j]) { + break; + } + + default: + $code[++$j] = $f[$i]; + } + } + } + + isset($s) && ($s = implode('', $s)) && $cc_on && $this->restoreCc($s); + unset($s); + + $code = substr($code, 0, $j + 1); + $cc_on && $this->restoreCc($code, false); + + // Protect wanted spaces and remove unwanted ones + $code = strtr($code, "\x7F", ' '); + $code = str_replace('- -', "-\x7F-", $code); + $code = str_replace('+ +', "+\x7F+", $code); + $code = preg_replace("'(\d)\s+\.\s*([a-zA-Z\$_[(])'", "$1\x7F.$2", $code); + $code = preg_replace("# ([-!%&;<=>~:.^+|,()*?[\]{}/']+)#", '$1', $code); + $code = preg_replace("#([-!%&;<=>~:.^+|,()*?[\]{}/]+) #", '$1', $code); + $cc_on && $code = preg_replace_callback("'//[^\'].*?@#3'", function ($m) { + return strtr($m[0], ' ', "\x7F"); + }, $code); + + // Replace new Array/Object by []/{} + false !== strpos($code, 'new Array') && $code = preg_replace("'new Array(?:\(\)|([;\])},:]))'", '[]$1', $code); + false !== strpos($code, 'new Object') && $code = preg_replace("'new Object(?:\(\)|([;\])},:]))'", '{}$1', $code); + + // Add missing semi-colons after curly braces + // This adds more semi-colons than strictly needed, + // but it seems that later gzipping is favorable to the repetition of "};" + $code = preg_replace("'\}(?![:,;.()\[\]}\|&]|(else|catch|finally|while)[^\$.a-zA-Z0-9_])'", '};', $code); + + // Tag possible empty instruction for easy detection + $code = preg_replace("'(?<![\$.a-zA-Z0-9_])if\('", '1#(', $code); + $code = preg_replace("'(?<![\$.a-zA-Z0-9_])for\('", '2#(', $code); + $code = preg_replace("'(?<![\$.a-zA-Z0-9_])while\('", '3#(', $code); + + $forPool = array(); + $instrPool = array(); + $s = 0; + + $f = array(); + $j = -1; + + // Remove as much semi-colon as possible + $len = strlen($code); + for ($i = 0; $i < $len; ++$i) { + switch ($code[$i]) { + case '(': + if ($j >= 0 && "\n" == $f[$j]) { + $f[$j] = ';'; + } + + ++$s; + + if ($i && '#' == $code[$i - 1]) { + $instrPool[$s - 1] = 1; + if ('2' == $code[$i - 2]) { + $forPool[$s] = 1; + } + } + + $f[++$j] = '('; + break; + + case ']': + case ')': + if ($i + 1 < $len && !isset($forPool[$s]) && !isset($instrPool[$s - 1]) && preg_match("'[a-zA-Z0-9_\$]'", $code[$i + 1])) { + $f[$j] .= $code[$i]; + $f[++$j] = "\n"; + } else { + $f[++$j] = $code[$i]; + } + + if (')' == $code[$i]) { + unset($forPool[$s]); + --$s; + } + + continue 2; + + case '}': + if ("\n" == $f[$j]) { + $f[$j] = '}'; + } else { + $f[++$j] = '}'; + } + break; + + case ';': + if (isset($forPool[$s]) || isset($instrPool[$s])) { + $f[++$j] = ';'; + } elseif ($j >= 0 && "\n" != $f[$j] && ';' != $f[$j]) { + $f[++$j] = "\n"; + } + + break; + + case '#': + switch ($f[$j]) { + case '1': + $f[$j] = 'if'; + break 2; + case '2': + $f[$j] = 'for'; + break 2; + case '3': + $f[$j] = 'while'; + break 2; + } + + case '['; + if ($j >= 0 && "\n" == $f[$j]) { + $f[$j] = ';'; + } + + default: + $f[++$j] = $code[$i]; + } + + unset($instrPool[$s]); + } + + $f = implode('', $f); + $cc_on && $f = str_replace('@#3', "\r", $f); + + // Fix "else ;" empty instructions + $f = preg_replace("'(?<![\$.a-zA-Z0-9_])else\n'", "\n", $f); + + $r1 = array( // keywords with a direct object + 'case', 'delete', 'do', 'else', 'function', 'in', 'instanceof', 'of', 'break', + 'new', 'return', 'throw', 'typeof', 'var', 'void', 'yield', 'let', 'if', + 'const', 'get', 'set', + ); + + $r2 = array( // keywords with a subject + 'in', 'instanceof', 'of', + ); + + // Fix missing semi-colons + $f = preg_replace("'(?<!(?<![a-zA-Z0-9_\$])" . implode(')(?<!(?<![a-zA-Z0-9_\$])', $r1) . ') (?!(' . implode('|', $r2) . ")(?![a-zA-Z0-9_\$]))'", "\n", $f); + $f = preg_replace("'(?<!(?<![a-zA-Z0-9_\$])do)(?<!(?<![a-zA-Z0-9_\$])else) if\('", "\nif(", $f); + $f = preg_replace("'(?<=--|\+\+)(?<![a-zA-Z0-9_\$])(" . implode('|', $r1) . ")(?![a-zA-Z0-9_\$])'", "\n$1", $f); + $f = preg_replace("'(?<![a-zA-Z0-9_\$])for\neach\('", 'for each(', $f); + $f = preg_replace("'(?<![a-zA-Z0-9_\$])\n(" . implode('|', $r2) . ")(?![a-zA-Z0-9_\$])'", '$1', $f); + + // Merge strings + if ($q["'"] > $q['"']) { + $q = array($q[1], $q[0]); + } + $f = preg_replace("#//''\"\"[0-9]+'#", $q[0] . '$0' . $q[0], $f); + strpos($f, $q[0] . '+' . $q[0]) && $f = str_replace($q[0] . '+' . $q[0], '', $f); + $len = count($strings); + foreach ($strings as $r1 => &$r2) { + $r2 = "/'" == substr($r1, -2) + ? str_replace(array("\\'", '\\"'), array("'", '"'), $r2) + : str_replace('\\' . $q[1], $q[1], $r2); + } + + // Restore wanted spaces + $f = strtr($f, "\x7F", ' '); + + return array($f, $strings); + } + + protected function extractClosures($code) + { + $code = ';' . $code; + + $this->argFreq[-1] += substr_count($code, '}catch('); + + if ($this->argFreq[-1]) { + // Special catch scope handling + + // FIXME: this implementation doesn't work with nested catch scopes who need + // access to their parent's caught variable (but who needs that?). + + $f = preg_split("@}catch\(({$this->varRx})@", $code, -1, PREG_SPLIT_DELIM_CAPTURE); + + $code = 'catch$scope$var' . mt_rand(); + $this->specialVarRx = $this->specialVarRx ? '(?:' . $this->specialVarRx . '|' . preg_quote($code) . ')' : preg_quote($code); + $i = count($f) - 1; + + while ($i) { + $c = 1; + $j = 0; + $l = strlen($f[$i]); + + while ($c && $j < $l) { + $s = $f[$i][$j++]; + $c += '(' == $s ? 1 : (')' == $s ? -1 : 0); + } + + if (!$c) { + do { + $s = $f[$i][$j++]; + $c += '{' == $s ? 1 : ('}' == $s ? -1 : 0); + } while ($c && $j < $l); + } + + $c = preg_quote($f[$i - 1], '#'); + $f[$i - 2] .= '}catch(' . preg_replace("#([.,{]?)(?<![a-zA-Z0-9_\$@]){$c}\\b#", '$1' . $code, $f[$i - 1] . substr($f[$i], 0, $j)) . substr($f[$i], $j); + + unset($f[$i--], $f[$i--]); + } + + $code = $f[0]; + } + + $f = preg_split("'(?<![a-zA-Z0-9_\$])((?:function[ (]|get |set ).*?\{)'", $code, -1, PREG_SPLIT_DELIM_CAPTURE); + $i = count($f) - 1; + $closures = array(); + + while ($i) { + $c = 1; + $j = 0; + $l = strlen($f[$i]); + + while ($c && $j < $l) { + $s = $f[$i][$j++]; + $c += '{' == $s ? 1 : ('}' == $s ? -1 : 0); + } + + switch (substr($f[$i - 2], -1)) { + default: + if (false !== $c = strpos($f[$i - 1], ' ', 8)) { + break; + } + case false: + case "\n": + case ';': + case '{': + case '}': + case ')': + case ']': + $c = strpos($f[$i - 1], '(', 4); + } + + $l = "//''\"\"#$i'"; + $code = substr($f[$i - 1], $c); + $closures[$l] = $code . substr($f[$i], 0, $j); + $f[$i - 2] .= substr($f[$i - 1], 0, $c) . $l . substr($f[$i], $j); + + if ('(){' !== $code) { + $j = substr_count($code, ','); + do { + isset($this->argFreq[$j]) ? ++$this->argFreq[$j] : $this->argFreq[$j] = 1; + } while ($j--); + } + + $i -= 2; + } + + return array($f[0], $closures); + } + + protected function makeVars($closure, &$tree, $key) + { + $tree['code'] = &$closure; + $tree['nfe'] = false; + $tree['used'] = array(); + $tree['local'] = array(); + + // Replace multiple "var" declarations by a single one + $closure = preg_replace_callback("'(?<=[\n\{\}])var [^\n\{\};]+(?:\nvar [^\n\{\};]+)+'", array($this, 'mergeVarDeclarations'), $closure); + + // Get all local vars (functions, arguments and "var" prefixed) + + $vars = &$tree['local']; + + if (preg_match("'^( [^(]*)?\((.*?)\)\{'", $closure, $v)) { + if ($v[1]) { + $vars[$tree['nfe'] = substr($v[1], 1)] = -1; + $tree['parent']['local'][';' . $key] = &$vars[$tree['nfe']]; + } + + if ($v[2]) { + $i = 0; + $v = explode(',', $v[2]); + foreach ($v as $w) { + $vars[$w] = $this->argFreq[$i++] - 1; // Give a bonus to argument variables + } + } + } + + $v = preg_split("'(?<![\$.a-zA-Z0-9_])var '", $closure); + if ($i = count($v) - 1) { + $w = array(); + + while ($i) { + $j = $c = 0; + $l = strlen($v[$i]); + + while ($j < $l) { + switch ($v[$i][$j]) { + case '(': + case '[': + case '{': + ++$c; + break; + + case ')': + case ']': + case '}': + if ($c-- <= 0) { + break 2; + } + break; + + case ';': + case "\n": + if (!$c) { + break 2; + } + + default: + $c || $w[] = $v[$i][$j]; + } + + ++$j; + } + + $w[] = ','; + --$i; + } + + $v = explode(',', implode('', $w)); + foreach ($v as $w) { + if (preg_match("'^{$this->varRx}'", $w, $v)) { + isset($vars[$v[0]]) || $vars[$v[0]] = 0; + } + } + } + + if (preg_match_all("@function ({$this->varRx})//''\"\"#@", $closure, $v)) { + foreach ($v[1] as $w) { + isset($vars[$w]) || $vars[$w] = 0; + } + } + + if ($this->argFreq[-1] && preg_match_all("@}catch\(({$this->varRx})@", $closure, $v)) { + $v[0] = array(); + foreach ($v[1] as $w) { + isset($v[0][$w]) ? ++$v[0][$w] : $v[0][$w] = 1; + } + foreach ($v[0] as $w => $v) { + $vars[$w] = $this->argFreq[-1] - $v; + } + } + + // Get all used vars, local and non-local + + $vars = &$tree['used']; + + if (preg_match_all("#([.,{]?(?:[gs]et )?)(?<![a-zA-Z0-9_\$])({$this->varRx})(:?)#", $closure, $w, PREG_SET_ORDER)) { + foreach ($w as $k) { + if (isset($k[1][0]) && (',' === $k[1][0] || '{' === $k[1][0])) { + if (':' === $k[3]) { + $k = '.' . $k[2]; + } elseif ('get ' === substr($k[1], 1, 4) || 'set ' === substr($k[1], 1, 4)) { + ++$this->charFreq[ord($k[1][1])]; // "g" or "s" + ++$this->charFreq[101]; // "e" + ++$this->charFreq[116]; // "t" + $k = '.' . $k[2]; + } else { + $k = $k[2]; + } + } else { + $k = $k[1] . $k[2]; + } + + isset($vars[$k]) ? ++$vars[$k] : $vars[$k] = 1; + } + } + + if (preg_match_all("#//''\"\"[0-9]+(?:['!]|/')#", $closure, $w)) { + foreach ($w[0] as $a) { + $v = "'" === substr($a, -1) && "/'" !== substr($a, -2) && $this->specialVarRx + ? preg_split("#([.,{]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->specialVarRx}:?)#", $this->strings[$a], -1, PREG_SPLIT_DELIM_CAPTURE) + : array($this->strings[$a]); + $a = count($v); + + for ($i = 0; $i < $a; ++$i) { + $k = $v[$i]; + + if (1 === $i % 2) { + if (',' === $k[0] || '{' === $k[0]) { + if (':' === substr($k, -1)) { + $k = '.' . substr($k, 1, -1); + } elseif ('get ' === substr($k, 1, 4) || 'set ' === substr($k, 1, 4)) { + ++$this->charFreq[ord($k[1])]; // "g" or "s" + ++$this->charFreq[101]; // "e" + ++$this->charFreq[116]; // "t" + $k = '.' . substr($k, 5); + } else { + $k = substr($k, 1); + } + } elseif (':' === substr($k, -1)) { + $k = substr($k, 0, -1); + } + + $w = &$tree; + + while (isset($w['parent']) && !(isset($w['used'][$k]) || isset($w['local'][$k]))) { + $w = &$w['parent']; + } + + (isset($w['used'][$k]) || isset($w['local'][$k])) && (isset($vars[$k]) ? ++$vars[$k] : $vars[$k] = 1); + + unset($w); + } + + if (0 === $i % 2 || !isset($vars[$k])) { + foreach (count_chars($v[$i], 1) as $k => $w) { + $this->charFreq[$k] += $w; + } + } + } + } + } + + // Propagate the usage number to parents + + foreach ($vars as $w => $a) { + $k = &$tree; + $chain = array(); + do { + $vars = &$k['local']; + $chain[] = &$k; + if (isset($vars[$w])) { + unset($k['used'][$w]); + if (isset($vars[$w])) { + $vars[$w] += $a; + } else { + $vars[$w] = $a; + } + $a = false; + break; + } + } while ($k['parent'] && $k = &$k['parent']); + + if ($a && !$k['parent']) { + if (isset($vars[$w])) { + $vars[$w] += $a; + } else { + $vars[$w] = $a; + } + } + + if (isset($tree['used'][$w]) && isset($vars[$w])) { + foreach ($chain as &$b) { + isset($b['local'][$w]) || $b['used'][$w] = &$vars[$w]; + } + } + } + + // Analyse childs + + $tree['childs'] = array(); + $vars = &$tree['childs']; + + if (preg_match_all("@//''\"\"#[0-9]+'@", $closure, $w)) { + foreach ($w[0] as $a) { + $vars[$a] = array('parent' => &$tree); + $this->makeVars($this->closures[$a], $vars[$a], $a); + } + } + } + + protected function mergeVarDeclarations($m) + { + return str_replace("\nvar ", ',', $m[0]); + } + + protected function renameVars(&$tree, $root) + { + if ($root) { + $tree['local'] += $tree['used']; + $tree['used'] = array(); + + foreach ($tree['local'] as $k => $v) { + if ('.' == $k[0]) { + $k = substr($k, 1); + } + + if ('true' === $k) { + $this->charFreq[48] += $v; + } elseif ('false' === $k) { + $this->charFreq[49] += $v; + } elseif (!$this->specialVarRx || !preg_match("#^{$this->specialVarRx}$#", $k)) { + foreach (count_chars($k, 1) as $k => $w) { + $this->charFreq[$k] += $w * $v; + } + } elseif (2 == strlen($k)) { + $tree['used'][] = $k[1]; + } + } + + $this->charFreq = $this->rsort($this->charFreq); + + $this->str0 = ''; + $this->str1 = ''; + + foreach ($this->charFreq as $k => $v) { + if (!$v) { + break; + } + + $v = chr($k); + + if ((64 < $k && $k < 91) || (96 < $k && $k < 123)) { // A-Z a-z + $this->str0 .= $v; + $this->str1 .= $v; + } elseif (47 < $k && $k < 58) { // 0-9 + $this->str1 .= $v; + } + } + + if ('' === $this->str0) { + $this->str0 = 'claspemitdbfrugnjvhowkxqyzCLASPEMITDBFRUGNJVHOWKXQYZ'; + $this->str1 = $this->str0 . '0123456789'; + } + + foreach ($tree['local'] as $var => $root) { + if ('.' != substr($var, 0, 1) && isset($tree['local'][".{$var}"])) { + $tree['local'][$var] += $tree['local'][".{$var}"]; + } + } + + foreach ($tree['local'] as $var => $root) { + if ('.' == substr($var, 0, 1) && isset($tree['local'][substr($var, 1)])) { + $tree['local'][$var] = $tree['local'][substr($var, 1)]; + } + } + + $tree['local'] = $this->rsort($tree['local']); + + foreach ($tree['local'] as $var => $root) { + switch (substr($var, 0, 1)) { + case '.': + if (!isset($tree['local'][substr($var, 1)])) { + $tree['local'][$var] = '#' . ($this->specialVarRx && 3 < strlen($var) && preg_match("'^\.{$this->specialVarRx}$'", $var) ? $this->getNextName($tree) . '$' : substr($var, 1)); + } + break; + + case ';': + $tree['local'][$var] = 0 === $root ? '' : $this->getNextName($tree); + case '#': + break; + + default: + $root = $this->specialVarRx && 2 < strlen($var) && preg_match("'^{$this->specialVarRx}$'", $var) ? $this->getNextName($tree) . '$' : $var; + $tree['local'][$var] = $root; + if (isset($tree['local'][".{$var}"])) { + $tree['local'][".{$var}"] = '#' . $root; + } + } + } + + foreach ($tree['local'] as $var => $root) { + $tree['local'][$var] = preg_replace("'^#'", '.', $tree['local'][$var]); + } + } else { + $tree['local'] = $this->rsort($tree['local']); + if (false !== $tree['nfe']) { + $tree['used'][] = $tree['local'][$tree['nfe']]; + } + + foreach ($tree['local'] as $var => $root) { + if ($tree['nfe'] !== $var) { + $tree['local'][$var] = 0 === $root ? '' : $this->getNextName($tree); + } + } + } + + $this->local_tree = &$tree['local']; + $this->used_tree = &$tree['used']; + + $tree['code'] = preg_replace_callback("#[.,{ ]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->varRx}:?#", array($this, 'getNewName'), $tree['code']); + + if ($this->specialVarRx && preg_match_all("#//''\"\"[0-9]+'#", $tree['code'], $b)) { + foreach ($b[0] as $a) { + $this->strings[$a] = preg_replace_callback( + "#[.,{]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->specialVarRx}:?#", + array($this, 'getNewName'), + $this->strings[$a] + ); + } + } + + foreach ($tree['childs'] as $a => &$b) { + $this->renameVars($b, false); + $tree['code'] = str_replace($a, $b['code'], $tree['code']); + unset($tree['childs'][$a]); + } + } + + protected function getNewName($m) + { + $m = $m[0]; + + $pre = '.' === $m[0] ? '.' : ''; + $post = ''; + + if (',' === $m[0] || '{' === $m[0] || ' ' === $m[0]) { + $pre = $m[0]; + + if (':' === substr($m, -1)) { + $post = ':'; + $m = (' ' !== $m[0] ? '.' : '') . substr($m, 1, -1); + } elseif ('get ' === substr($m, 1, 4) || 'set ' === substr($m, 1, 4)) { + $pre .= substr($m, 1, 4); + $m = '.' . substr($m, 5); + } else { + $m = substr($m, 1); + } + } elseif (':' === substr($m, -1)) { + $post = ':'; + $m = substr($m, 0, -1); + } + + $post = (isset($this->reserved[$m]) + ? ('true' === $m ? '!0' : ('false' === $m ? '!1' : $m)) + : ( + isset($this->local_tree[$m]) + ? $this->local_tree[$m] + : ( + isset($this->used_tree[$m]) + ? $this->used_tree[$m] + : $m + ) + ) + ) . $post; + + return '' === $post ? '' : ($pre . ('.' === $post[0] ? substr($post, 1) : $post)); + } + + protected function getNextName(&$tree = array(), &$counter = false) + { + if (false === $counter) { + $counter = &$tree['counter']; + isset($counter) || $counter = -1; + $exclude = array_flip($tree['used']); + } else { + $exclude = $tree; + } + + ++$counter; + + $len0 = strlen($this->str0); + $len1 = strlen($this->str0); + + $name = $this->str0[$counter % $len0]; + + $i = intval($counter / $len0) - 1; + while ($i >= 0) { + $name .= $this->str1[$i % $len1]; + $i = intval($i / $len1) - 1; + } + + return !(isset($this->reserved[$name]) || isset($exclude[$name])) ? $name : $this->getNextName($exclude, $counter); + } + + protected function restoreCc(&$s, $lf = true) + { + $lf && $s = str_replace('@#3', '', $s); + + $s = str_replace('@#1', '@*/', $s); + $s = str_replace('2#@', '//@', $s); + $s = str_replace('1#@', '/*@', $s); + $s = str_replace('##', '#', $s); + } + + private function rsort($array) + { + if (!$array) { + return $array; + } + + $i = 0; + $tuples = array(); + foreach ($array as $k => &$v) { + $tuples[] = array(++$i, $k, &$v); + } + + usort($tuples, function ($a, $b) { + if ($b[2] > $a[2]) { + return 1; + } + if ($b[2] < $a[2]) { + return -1; + } + if ($b[0] > $a[0]) { + return -1; + } + if ($b[0] < $a[0]) { + return 1; + } + + return 0; + }); + + $array = array(); + + foreach ($tuples as $t) { + $array[$t[1]] = &$t[2]; + } + + return $array; + } } + ?> \ No newline at end of file diff --git a/modules/util/Ldap.class.php b/modules/util/Ldap.class.php @@ -1,182 +1,179 @@ -<?php -// OpenRat Content Management System -// Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -/** - * Bereitstellen von LDAP-Funktionen. - * @author $Author$ - * @version $Revision$ - * @package openrat.services - */ -class Ldap -{ - var $connection; - var $timeout; - var $aliases; - - - /** - * - */ - function Ldap() - { - global $conf; - - $this->timeout = intval($conf['ldap']['search']['timeout']); - - if ( $conf['ldap']['search']['aliases'] ) - $this->aliases = LDAP_DEREF_ALWAYS; - else - $this->aliases = LDAP_DEREF_NEVER; - } - - - - /** - * Verbindung �ffnen. - */ - function connect() - { - global $conf; - - $ldapHost = $conf['ldap']['host']; - $ldapPort = $conf['ldap']['port']; - - // Verbindung zum LDAP-Server herstellen - $this->connection = @ldap_connect( $ldapHost,$ldapPort ); - - // siehe http://bugs.php.net/bug.php?id=15637 - // Unter bestimmten Bedingungen wird trotz nicht erreichbarem LDAP-Server eine PHP-Resource - // zurueck gegeben. Dann erscheint zwar keine Fehlermeldung, aber zumindestens misslingt - // der nachfolgende Bind-Befehl. - if ( !is_resource($this->connection) || $this->connection === false ) - { - Logger::error( "connect to ldap server '$ldapHost:$ldapPort' failed" ); - // Abbruch, wenn LDAP-Server nicht erreichbar - throw new RuntimeException( "Connection failed to $ldapHost:$ldapPort (".ldap_errno().'/'.ldap_error().'). Please contact your administrator.' ); - } - - // Protokollversion setzen. - $j = ldap_set_option( $this->connection, LDAP_OPT_PROTOCOL_VERSION,intval($conf['ldap']['protocol']) ); - if ( ! $j ) - throw new LogicException( 'LDAP error while setting protocol version'.ldap_errno().'/'.ldap_error().')' ); - - } - - - - /** - * Ein Binding auf den LDAP-Server durchf�hren. - */ - function bind( $user,$pw ) - { - return @ldap_bind( $this->connection,$user,$pw); - } - - - - /** - * Ein Binding auf den LDAP-Server durchf�hren. - */ - function bindAnonymous() - { - return @ldap_bind( $this->connection ); - } - - - - /** - * Das Bindung wird entfernt. - */ - function unbind() - { - ldap_unbind( $this->connection ); - } - - - - /** - * Eine Suche auf den LDAP-Server durchf�hren. - */ - function searchUser( $username ) - { - global $conf; - - $techUser = $conf['ldap']['search']['user']; - $techPass = $conf['ldap']['search']['password']; - - if ( $conf['ldap']['search']['anonymous'] ) - $this->bindAnonymous(); - else - $this->bind( $techUser, $techPass ); - - $dn = $conf['ldap']['search']['basedn']; - $filter = $conf['ldap']['search']['filter']; - $filter = str_replace('{user}', $username, $filter); - - $s = @ldap_search( $this->connection,$dn,$filter,array(),0,1,$this->timeout,$this->aliases ); - - if ( ! is_resource($s) ) - return null; - - $dn = @ldap_get_dn($this->connection, ldap_first_entry($this->connection,$s) ); - - return $dn; - } - - - - /** - * Ein Binding auf den LDAP-Server durchf�hren. - */ - function searchAttribute( $filter,$attr ) - { - global $conf; - - $timeout = intval($conf['ldap']['search']['timeout']); - - if ( $conf['ldap']['search']['aliases'] ) - $aliases = LDAP_DEREF_ALWAYS; - else - $aliases = LDAP_DEREF_NEVER; - - - $base_dn = $conf['ldap']['search']['basedn']; - $s = ldap_search( $this->connection,$base_dn,$filter,array(),0,0,$this->timeout,$this->aliases ); - $ergebnisse = ldap_get_entries($this->connection,$s); - - $liste = array(); -// Html::debug($ergebnisse); - for( $i=0; $i<=$ergebnisse['count']-1; $i++ ) - $liste[] = $ergebnisse[$i][$attr][0]; - - return $liste; - } - - - - /** - * Verbindung schlie�en. - */ - function close() - { - // Verbindung zum LDAP-Server brav beenden - ldap_close( $this->connection ); - } -} - +<?php +// OpenRat Content Management System +// Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +namespace util; +use Logger; +use LogicException; +use RuntimeException; + +/** + * Bereitstellen von LDAP-Funktionen. + * @author $Author$ + * @version $Revision$ + * @package openrat.services + */ +class Ldap +{ + var $connection; + var $timeout; + var $aliases; + + + /** + * + */ + function Ldap() + { + global $conf; + + $this->timeout = intval($conf['ldap']['search']['timeout']); + + if ($conf['ldap']['search']['aliases']) + $this->aliases = LDAP_DEREF_ALWAYS; + else + $this->aliases = LDAP_DEREF_NEVER; + } + + + /** + * Verbindung �ffnen. + */ + function connect() + { + global $conf; + + $ldapHost = $conf['ldap']['host']; + $ldapPort = $conf['ldap']['port']; + + // Verbindung zum LDAP-Server herstellen + $this->connection = @ldap_connect($ldapHost, $ldapPort); + + // siehe http://bugs.php.net/bug.php?id=15637 + // Unter bestimmten Bedingungen wird trotz nicht erreichbarem LDAP-Server eine PHP-Resource + // zurueck gegeben. Dann erscheint zwar keine Fehlermeldung, aber zumindestens misslingt + // der nachfolgende Bind-Befehl. + if (!is_resource($this->connection) || $this->connection === false) { + Logger::error("connect to ldap server '$ldapHost:$ldapPort' failed"); + // Abbruch, wenn LDAP-Server nicht erreichbar + throw new RuntimeException("Connection failed to $ldapHost:$ldapPort (" . ldap_errno() . '/' . ldap_error() . '). Please contact your administrator.'); + } + + // Protokollversion setzen. + $j = ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, intval($conf['ldap']['protocol'])); + if (!$j) + throw new LogicException('LDAP error while setting protocol version' . ldap_errno() . '/' . ldap_error() . ')'); + + } + + + /** + * Ein Binding auf den LDAP-Server durchf�hren. + */ + function bind($user, $pw) + { + return @ldap_bind($this->connection, $user, $pw); + } + + + /** + * Ein Binding auf den LDAP-Server durchf�hren. + */ + function bindAnonymous() + { + return @ldap_bind($this->connection); + } + + + /** + * Das Bindung wird entfernt. + */ + function unbind() + { + ldap_unbind($this->connection); + } + + + /** + * Eine Suche auf den LDAP-Server durchf�hren. + */ + function searchUser($username) + { + global $conf; + + $techUser = $conf['ldap']['search']['user']; + $techPass = $conf['ldap']['search']['password']; + + if ($conf['ldap']['search']['anonymous']) + $this->bindAnonymous(); + else + $this->bind($techUser, $techPass); + + $dn = $conf['ldap']['search']['basedn']; + $filter = $conf['ldap']['search']['filter']; + $filter = str_replace('{user}', $username, $filter); + + $s = @ldap_search($this->connection, $dn, $filter, array(), 0, 1, $this->timeout, $this->aliases); + + if (!is_resource($s)) + return null; + + $dn = @ldap_get_dn($this->connection, ldap_first_entry($this->connection, $s)); + + return $dn; + } + + + /** + * Ein Binding auf den LDAP-Server durchf�hren. + */ + function searchAttribute($filter, $attr) + { + global $conf; + + $timeout = intval($conf['ldap']['search']['timeout']); + + if ($conf['ldap']['search']['aliases']) + $aliases = LDAP_DEREF_ALWAYS; + else + $aliases = LDAP_DEREF_NEVER; + + + $base_dn = $conf['ldap']['search']['basedn']; + $s = ldap_search($this->connection, $base_dn, $filter, array(), 0, 0, $this->timeout, $this->aliases); + $ergebnisse = ldap_get_entries($this->connection, $s); + + $liste = array(); +// Html::debug($ergebnisse); + for ($i = 0; $i <= $ergebnisse['count'] - 1; $i++) + $liste[] = $ergebnisse[$i][$attr][0]; + + return $liste; + } + + + /** + * Verbindung schlie�en. + */ + function close() + { + // Verbindung zum LDAP-Server brav beenden + ldap_close($this->connection); + } +} + ?> \ No newline at end of file diff --git a/modules/util/Line.class.php b/modules/util/Line.class.php @@ -1,152 +0,0 @@ -<?php - -/** - * Darstellung einer Zeile in einem Freitext.<br> - * <br> - * Im Konstruktor wird die Zeile analysiert und es wird festgestellt, was - * die Zeile f�r einen Inhalt hat (z.B. ein Listenelement, eine �berschrift, usw.)<br> - * - * @author Jan Dankert - * @version $Revision$ - * @package openrat.services - */ -class Line -{ - var $source; // Der urspr�ngliche Inhalt - var $value; // Der textuelle Inhalt (sofern vorhanden) - - var $isDefinition = false; // Definitionseintrag - var $isList = false; // nicht-numerierte Liste - var $isNumberedList = false; // numerierte Liste - var $indent = 0; // Einschubtiefe der Liste - - var $isHeadline = false; // �berschrift - var $isHeadlineUnderline = false; // unterstrichene �berschrift - var $headlineLevel = 0; // Grad der �berschrift (1,2,3...) - - - var $isTableOfContent = false; // Inhaltsverzeichnis - var $isTable = false; // Tabelle - var $isCode = false; // Code - var $isQuote = false; // Zitat - var $isQuotePraefix = false; // Zitatbeginn/-ende - - var $isUnparsed = false; - - var $isEmpty = false; // Zeile ist leer - var $isNormal = false; // Zeile ist ohne besonderen Inhalt, d.h. keine Tabelle, kein Zitat, usw. - - - - /** - * Erzeugt einen Zeilenobjekt, der Text im Parameter wird dabei geparst. - */ - function __construct( $s ) - { - global $conf; - $text_markup = $conf['editor']['text-markup']; -// Html::debug($text_markup); - - $list_numbered = $text_markup['list-numbered' ]; - $list_unnumbered = $text_markup['list-unnumbered']; - $headline = $text_markup['headline' ]; - - $this->source = $s; - $this->value = $s; - - $this->isList = $this->isAnErsterStelle(ltrim($s),$list_unnumbered); - $this->isNumberedList = $this->isAnErsterStelle(ltrim($s),$list_numbered ); - $this->indent = strlen($s) - strlen(ltrim($s)) + 1; - - if ( $this->isList || $this->isNumberedList ) - $this->value = ltrim(substr($s,$this->indent)); - - $this->level = strspn( $s,$headline ); - $this->isHeadline = $this->level >= 1; - - if ( $this->isHeadline ) - $this->value = ltrim(substr($s,$this->level)); - - - $hl = array( 1 => $text_markup['headline_level1_underline'], - 2 => $text_markup['headline_level2_underline'], - 3 => $text_markup['headline_level3_underline'] ); - - foreach($hl as $lev=>$char ) - { - if ( substr($s,0,3*strlen($char))==str_repeat($char,3*strlen($char)) ) - { - $this->isHeadlineUnderline = true; - $this->isNormal = true; - $this->level = intval($lev); - } - } - - if ( $this->isAnErsterStelle($s,$text_markup['table-of-content']) ) - { - $this->isTableOfContent = true; - $this->isNumberedList = false; - $this->isList = false; - $this->value = ''; - } - elseif - ( $this->isHeadline || - $this->isHeadlineUnderline || - $this->isList || - $this->isNumberedList ) - { - ; - } - elseif ( $this->isAnErsterStelle($s,$text_markup['table-cell-sep']) ) - { - $this->isTable = true; - $this->value = ''; - } - elseif ( $this->isAnErsterStelle($s,$text_markup['pre-begin']) && !$this->isHeadlineUnderline ) - { - $this->isCode = true; - $this->value = substr($s,strlen($text_markup['pre-begin'])); - } - elseif ( strpos($s, $text_markup['definition-sep'])!== false ) - { - $this->isDefinition = true; - } - elseif ( trim($s)==$text_markup['quote-line-begin'] ) - { - $this->isQuote = true; - } - elseif ( $this->isAnErsterStelle($s,$text_markup['quote']) && strlen(trim($s))>1 ) - { - $this->isQuotePraefix = true; - $this->value = ltrim(substr($s,strlen($text_markup['quote']))); - $this->level = strspn( str_replace(' ','',$s),$text_markup['quote'] ); - } - elseif ( $this->isAnErsterStelle($s,'`') ) - { - $this->isUnparsed = true; - $this->value = substr($this->value,1); - } - elseif ( $s == '' ) - { - $this->isEmpty = true; - } - else - { - $this->isNormal = true; - } - } - - - /** - * Stellt fest, ob $wort am Anfang von $text steht. - */ - function isAnErsterStelle( $text,$wort ) - { -// Html::debug($text,"Text"); -// Html::debug($wort,"Wort"); -// Html::debug(substr($text,0,strlen($wort))==$wort,'Ergebnis'); - return substr($text,0,strlen($wort))==$wort; - } -} - -?>- \ No newline at end of file diff --git a/modules/util/Macro.class.php b/modules/util/Macro.class.php @@ -15,8 +15,11 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +namespace util; + use cms\model\Page; use cms\model\Project; +use util\Session; /** @@ -28,15 +31,16 @@ use cms\model\Project; */ class Macro { - /** - * @var Page - */ + /** + * @var Page + */ protected $page; - public function setContextPage( &$page ) { + public function setContextPage(&$page) + { $this->page = $page; } - + /** * Ausführen des Makros. Diese Methode sollte durch die Unterklasse überschrieben werden. */ @@ -44,8 +48,8 @@ class Macro { // overwrite this in subclasses } - - + + /** * Holt die aktuellen Datenbankverbindung. */ @@ -54,7 +58,7 @@ class Macro return db(); } - + /** * Holt die aktuelle Objekt-Id. * @return number @@ -64,7 +68,7 @@ class Macro return $this->page->objectid; } - + /** * Holt die aktuelle Seite. * @return \cms\model\Page @@ -73,8 +77,8 @@ class Macro { return $this->page; } - - + + /** * Holt das aktuelle Objekt. * @return Object @@ -84,78 +88,77 @@ class Macro return $this->page; } - /** - * Ermittelt die Id des Wurzelordners im aktuellen Projekt. + * Ermittelt die Id des Wurzelordners im aktuellen Projekt. */ protected function getRootObjectId() { - $project = new Project( $this->page->projectid); + $project = new Project($this->page->projectid); return $project->getRootObjectId(); } - + /** * Löscht die bisher erzeugte Ausgabe. - * @deprecated useless + * @deprecated useless */ public function delOutput() { } - + /** * Ergänzt die Standardausgabe um den gewünschten Wert. * @deprecated use echo() */ - public function output( $text ) + public function output($text) { echo $text; } - + /** * Ergänzt die Standardausgabe um den gewünschten Wert. Es wird ein Zeilenendezeichen ergänzt. * @deprecated use echo() */ - public function outputLn( $text ) + public function outputLn($text) { - echo $text."\n"; + echo $text . "\n"; } /** * Setzt eine Sitzungsvariable. - * + * * @param String $var * @param Object $value */ - public function setSessionVar( $var,$value ) + public function setSessionVar($var, $value) { - Session::set( $var,$value ); + Session::set($var, $value); } /** * Ermittelt eine Sitzungsvariable. - * + * * @param String $var * @return string */ - public function getSessionVar( $var ) + public function getSessionVar($var) { - return Session::get( $var ); + return Session::get($var); } - /** - * Ermittelt den Pfad auf ein Objekt. - * @param Object - * @return string - */ - public function pathToObject( $obj ) + /** + * Ermittelt den Pfad auf ein Objekt. + * @param Object + * @return string + */ + public function pathToObject($obj) { - if ( is_object($obj) ) + if (is_object($obj)) return $this->page->path_to_object($obj->objectid); else return $this->page->path_to_object($obj); diff --git a/modules/util/Mail.class.php b/modules/util/Mail.class.php @@ -16,6 +16,13 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +namespace util; + +use Adresse; +use LogicException; +use util\Text; +use unknown_type; + /** * Erzeugen und Versender einer E-Mail gemaess RFC 822.<br> * <br> @@ -30,23 +37,23 @@ * eingesetzt werden. Die Mail kann zwar auch direkt an Mail-Exchanger (MX) des * Empf�ngers geschickt werden, falls dieser aber Greylisting einsetzt ist eine * Zustellung nicht m�glich.<br> - * <br> - * + * <br> + * * @author Jan Dankert * @version $Id$ * @package serviceClasses */ class Mail { - var $from = ''; - var $to = ''; - var $bcc = ''; - var $cc = ''; + var $from = ''; + var $to = ''; + var $bcc = ''; + var $cc = ''; var $subject = ''; - var $text = ''; - var $header = array(); - var $nl = ''; - + var $text = ''; + var $header = array(); + var $nl = ''; + /** * Falls beim Versendern der E-Mail etwas schiefgeht, steht hier drin * die technische Fehlermeldung. @@ -54,7 +61,7 @@ class Mail * @var array Fehler */ var $error = array(); - + /** * Set to true for debugging. * If true, All SMTP-Commands are written to error log. @@ -62,8 +69,8 @@ class Mail * @var bool */ var $debug = true; - - + + /** * Konstruktor. * Es werden folgende Parameter erwartet @@ -72,101 +79,95 @@ class Mail * @param String unbenutzt. * @return Mail */ - function __construct( $to,$text,$xy='' ) + function __construct($to, $text, $xy = '') { global $conf; - + // Zeilenumbruch CR/LF gem. RFC 822. - $this->nl = chr(13).chr(10); - - if ( !empty($conf['mail']['from']) ) + $this->nl = chr(13) . chr(10); + + if (!empty($conf['mail']['from'])) $this->from = $this->header_encode($conf['mail']['from']); // Priorit�t definieren (sofern konfiguriert) - if ( !empty($conf['mail']['priority']) ) - $this->header[] = 'X-Priority: '.$conf['mail']['priority']; - - $this->header[] = 'X-Mailer: '.$this->header_encode(OR_TITLE.' '.OR_VERSION); + if (!empty($conf['mail']['priority'])) + $this->header[] = 'X-Priority: ' . $conf['mail']['priority']; + + $this->header[] = 'X-Mailer: ' . $this->header_encode(OR_TITLE . ' ' . OR_VERSION); $this->header[] = 'Content-Type: text/plain; charset=UTF-8'; - $this->subject = $this->header_encode(lang( 'mail_subject_'.$text )); - $this->to = $this->header_encode($to); - - $this->text = $this->nl.wordwrap(str_replace(';',$this->nl,lang('mail_text_'.$text)),70,$this->nl).$this->nl; + $this->subject = $this->header_encode(lang('mail_subject_' . $text)); + $this->to = $this->header_encode($to); + + $this->text = $this->nl . wordwrap(str_replace(';', $this->nl, lang('mail_text_' . $text)), 70, $this->nl) . $this->nl; // Signatur anhaengen (sofern konfiguriert) $signature = $conf['mail']['signature']; - if ( empty( $signature ) ) + if (empty($signature)) $signature = $conf['application']['name']; - if ( !empty( $signature ) ) - { - $this->text .= $this->nl.'-- '.$this->nl; - $this->text .= str_replace(';',$this->nl,$signature); + if (!empty($signature)) { + $this->text .= $this->nl . '-- ' . $this->nl; + $this->text .= str_replace(';', $this->nl, $signature); $this->text .= $this->nl; } - + // Kopie-Empf�nger - if ( !empty($conf['mail']['cc']) ) + if (!empty($conf['mail']['cc'])) $this->cc = $this->header_encode($conf['mail']['cc']); // Blindkopie-Empf�nger - if ( !empty($conf['mail']['bcc']) ) + if (!empty($conf['mail']['bcc'])) $this->bcc = $this->header_encode($conf['mail']['bcc']); } - /** * Kodiert einen Text in das Format "Quoted-printable".<br> * See RFC 2045. * @param String $text Eingabe * @return Text im quoted-printable-Format */ - private function quoted_printable_encode( $text ) + private function quoted_printable_encode($text) { - $text = str_replace(' ','=20',$text); - - for( $i=128; $i<=255; $i++ ) - { - $text = str_replace( chr($i),'='.dechex($i),$text ); + $text = str_replace(' ', '=20', $text); + + for ($i = 128; $i <= 255; $i++) { + $text = str_replace(chr($i), '=' . dechex($i), $text); } - + return $text; } - - + /** * Setzen einer Variablen in den Mail-Inhalt. */ - public function setVar( $varName,$varInhalt) + public function setVar($varName, $varInhalt) { - $this->text = str_replace( '{'.$varName.'}', $varInhalt, $this->text ); + $this->text = str_replace('{' . $varName . '}', $varInhalt, $this->text); } - + /** * Mail absenden. * Die E-Mail wird versendet. - * + * * @return boolean Erfolg - */ + */ public function send() { global $conf; - if ( strpos( $this->to,'@') === FALSE ) - throw new LogicException("E-Mail-Adress does not contain a domain name: ".$this->to); + if (strpos($this->to, '@') === FALSE) + throw new LogicException("E-Mail-Adress does not contain a domain name: " . $this->to); - $to_domain = explode('@',$this->to)[1]; + $to_domain = explode('@', $this->to)[1]; // Prüfen gegen die Whitelist $white = @$conf['mail']['whitelist']; - - if ( !empty($white) ) - { - if ( ! $this->containsDomain($to_domain,$white) ) - { + + if (!empty($white)) { + if (!$this->containsDomain($to_domain, $white)) { // Wenn Domain nicht in Whitelist gefunden, dann Mail nicht verschicken. $this->error[] = 'Mail-Domain is not whitelisted'; return false; @@ -175,215 +176,186 @@ class Mail // Prüfen gegen die Blacklist $black = @$conf['mail']['blacklist']; - - if ( !empty($black) ) - { - if ( $this->containsDomain($to_domain,$black) ) - { + + if (!empty($black)) { + if ($this->containsDomain($to_domain, $black)) { // Wenn Domain in Blacklist gefunden, dann Mail nicht verschicken. $this->error[] = 'Mail-Domain is blacklisted'; return false; } } - + // Header um Adressangaben erg�nzen. - if ( !empty($this->from ) ) - $this->header[] = 'From: '.$this->from; - - if ( !empty($this->cc ) ) - $this->header[] = 'Cc: '.$this->cc; - - if ( !empty($this->bcc ) ) - $this->header[] = 'Bcc: '.$this->bcc; - + if (!empty($this->from)) + $this->header[] = 'From: ' . $this->from; + + if (!empty($this->cc)) + $this->header[] = 'Cc: ' . $this->cc; + + if (!empty($this->bcc)) + $this->header[] = 'Bcc: ' . $this->bcc; + // Mail versenden - if ( strtolower(@$conf['mail']['client']) == 'php' ) - { + if (strtolower(@$conf['mail']['client']) == 'php') { // PHP-interne Mailfunktion verwenden. - $result = @mail( $this->to, // Empf�nger - $this->subject, // Betreff - $this->text, // Inhalt - // Lt. RFC822 müssen Header mit CRLF enden. - // ABER: Der Parameter "additional headers" verlangt offenbar \n am Zeilenende. - implode("\n",$this->header) ); - if ( !$result ) + $result = @mail($this->to, // Empf�nger + $this->subject, // Betreff + $this->text, // Inhalt + // Lt. RFC822 müssen Header mit CRLF enden. + // ABER: Der Parameter "additional headers" verlangt offenbar \n am Zeilenende. + implode("\n", $this->header)); + if (!$result) // Die E-Mail wurde nicht akzeptiert. // Genauer geht es leider nicht, da mail() nur einen boolean-Wert // zur�ck liefert. $this->error[] = 'Mail was NOT accepted by mail()'; - + return $result; - } - else - { + } else { // eigenen SMTP-Dialog verwenden. $smtpConf = $conf['mail']['smtp']; - - if ( !empty($smtpConf['host'])) - { + + if (!empty($smtpConf['host'])) { // Eigenen Relay-Host verwenden. $mxHost = $smtpConf['host']; $mxPort = intval($smtpConf['port']); - } - else - { + } else { // Mail direkt zustellen. $mxHost = $this->getMxHost($this->to); - - if ( empty($mxHost) ) - { + + if (empty($mxHost)) { $this->error[] = "No MX-Entry found. Mail could not be sent."; return false; } - - if ($smtpConf['ssl']) + + if ($smtpConf['ssl']) $mxPort = 465; else $mxPort = 25; } - - if ( !empty($smtpConf['localhost'])) - { + + if (!empty($smtpConf['localhost'])) { $myHost = $smtpConf['localhost']; - } - else - { + } else { $myHost = gethostbyaddr(getenv('REMOTE_ADDR')); } - - if ( $smtpConf['ssl']) + + if ($smtpConf['ssl']) $proto = 'ssl'; else $proto = 'tcp'; - + //connect to the host and port - $smtpSocket = fsockopen($proto.'://'.$mxHost,$mxPort, $errno, $errstr, intval($smtpConf['timeout'])); - - if ( !is_resource($smtpSocket) ) - { - $this->error[] = 'Connection failed to: '.$proto.'://'.$mxHost.':'.$mxPort.' ('.$errstr.'/'.$errno.')'; + $smtpSocket = fsockopen($proto . '://' . $mxHost, $mxPort, $errno, $errstr, intval($smtpConf['timeout'])); + + if (!is_resource($smtpSocket)) { + $this->error[] = 'Connection failed to: ' . $proto . '://' . $mxHost . ':' . $mxPort . ' (' . $errstr . '/' . $errno . ')'; return false; } - + $smtpResponse = fgets($smtpSocket, 4096); - if ( $this->debug) + if ($this->debug) $this->error[] = trim($smtpResponse); - if ( substr($smtpResponse,0,3) != '220' ) - { - $this->error[] = 'No 220: '.trim($smtpResponse); + if (substr($smtpResponse, 0, 3) != '220') { + $this->error[] = 'No 220: ' . trim($smtpResponse); return false; } - if ( !is_resource($smtpSocket) ) - { - $this->error[] = 'Connection failed to: '.$smtpConf['host'].':'.$smtpConf['port'].' ('.$smtpResponse.')'; + if (!is_resource($smtpSocket)) { + $this->error[] = 'Connection failed to: ' . $smtpConf['host'] . ':' . $smtpConf['port'] . ' (' . $smtpResponse . ')'; return false; } - + //you have to say HELO again after TLS is started - $smtpResponse = $this->sendSmtpCommand($smtpSocket,'HELO '.$myHost); + $smtpResponse = $this->sendSmtpCommand($smtpSocket, 'HELO ' . $myHost); - if ( substr($smtpResponse,0,3) != '250' ) - { - $this->error[] = "No 2xx after HELO, server says: ".$smtpResponse; + if (substr($smtpResponse, 0, 3) != '250') { + $this->error[] = "No 2xx after HELO, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } - if ( $smtpConf['tls'] ) - { - $smtpResponse = $this->sendSmtpCommand($smtpSocket,'STARTTLS'); - if ( substr($smtpResponse,0,3) == '220' ) - { + if ($smtpConf['tls']) { + $smtpResponse = $this->sendSmtpCommand($smtpSocket, 'STARTTLS'); + if (substr($smtpResponse, 0, 3) == '220') { // STARTTLS ist gelungen. //you have to say HELO again after TLS is started - $smtpResponse = $this->sendSmtpCommand($smtpSocket,'HELO '.$myHost); - - if ( substr($smtpResponse,0,3) != '250' ) - { - $this->error[] = "No 2xx after HELO, server says: ".$smtpResponse; + $smtpResponse = $this->sendSmtpCommand($smtpSocket, 'HELO ' . $myHost); + + if (substr($smtpResponse, 0, 3) != '250') { + $this->error[] = "No 2xx after HELO, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } - } - else - { + } else { // STARTTLS ging in die Hose. Einfach weitermachen. } } - + // request for auth login - if ( isset($smtpConf['auth_username']) && !empty($smtpConf['host']) && !empty($smtpConf['auth_username'])) - { - $smtpResponse = $this->sendSmtpCommand($smtpSocket,"AUTH LOGIN"); - if ( substr($smtpResponse,0,3) != '334' ) - { - $this->error[] = "No 334 after AUTH_LOGIN, server says: ".$smtpResponse; + if (isset($smtpConf['auth_username']) && !empty($smtpConf['host']) && !empty($smtpConf['auth_username'])) { + $smtpResponse = $this->sendSmtpCommand($smtpSocket, "AUTH LOGIN"); + if (substr($smtpResponse, 0, 3) != '334') { + $this->error[] = "No 334 after AUTH_LOGIN, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } - - if ( $this->debug) - $this->error[] = 'Login for '.$smtpConf['auth_username']; - + + if ($this->debug) + $this->error[] = 'Login for ' . $smtpConf['auth_username']; + //send the username $smtpResponse = $this->sendSmtpCommand($smtpSocket, base64_encode($smtpConf['auth_username'])); - if ( substr($smtpResponse,0,3) != '334' ) - { - $this->error[] = "No 3xx after setting username, server says: ".$smtpResponse; + if (substr($smtpResponse, 0, 3) != '334') { + $this->error[] = "No 3xx after setting username, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } - + //send the password $smtpResponse = $this->sendSmtpCommand($smtpSocket, base64_encode($smtpConf['auth_password'])); - if ( substr($smtpResponse,0,3) != '235' ) - { - $this->error[] = "No 235 after sending password, server says: ".$smtpResponse; + if (substr($smtpResponse, 0, 3) != '235') { + $this->error[] = "No 235 after sending password, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } } - + //email from - $smtpResponse = $this->sendSmtpCommand($smtpSocket, 'MAIL FROM: <'.$conf['mail']['from'].'>'); - if ( substr($smtpResponse,0,3) != '250' ) - { - $this->error[] = "No 2xx after MAIL_FROM, server says: ".$smtpResponse; + $smtpResponse = $this->sendSmtpCommand($smtpSocket, 'MAIL FROM: <' . $conf['mail']['from'] . '>'); + if (substr($smtpResponse, 0, 3) != '250') { + $this->error[] = "No 2xx after MAIL_FROM, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } - + //email to - $smtpResponse = $this->sendSmtpCommand($smtpSocket, 'RCPT TO: <'.$this->to.'>'); - if ( substr($smtpResponse,0,3) != '250' ) - { - $this->error[] = "No 2xx after RCPT_TO, server says: ".$smtpResponse; + $smtpResponse = $this->sendSmtpCommand($smtpSocket, 'RCPT TO: <' . $this->to . '>'); + if (substr($smtpResponse, 0, 3) != '250') { + $this->error[] = "No 2xx after RCPT_TO, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } - + //the email $smtpResponse = $this->sendSmtpCommand($smtpSocket, "DATA"); - if ( substr($smtpResponse,0,3) != '354' ) - { - $this->error[] = "No 354 after DATA, server says: ".$smtpResponse; + if (substr($smtpResponse, 0, 3) != '354') { + $this->error[] = "No 354 after DATA, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } - - $this->header[] = 'To: '.$this->to; - $this->header[] = 'Subject: '.$this->subject; - $this->header[] = 'Date: '.date('r'); - $this->header[] = 'Message-Id: '.'<'.getenv('REMOTE_ADDR').'.'.time().'.openrat@'.getenv('SERVER_NAME').'.'.getenv('HOSTNAME').'>'; - - //observe the . after the newline, it signals the end of message - $smtpResponse = $this->sendSmtpCommand($smtpSocket, implode($this->nl,$this->header).$this->nl.$this->nl.$this->text.$this->nl.'.'); - if ( substr($smtpResponse,0,3) != '250' ) - { - $this->error[] = "No 2xx after putting DATA, server says: ".$smtpResponse; + + $this->header[] = 'To: ' . $this->to; + $this->header[] = 'Subject: ' . $this->subject; + $this->header[] = 'Date: ' . date('r'); + $this->header[] = 'Message-Id: ' . '<' . getenv('REMOTE_ADDR') . '.' . time() . '.openrat@' . getenv('SERVER_NAME') . '.' . getenv('HOSTNAME') . '>'; + + //observe the . after the newline, it signals the end of message + $smtpResponse = $this->sendSmtpCommand($smtpSocket, implode($this->nl, $this->header) . $this->nl . $this->nl . $this->text . $this->nl . '.'); + if (substr($smtpResponse, 0, 3) != '250') { + $this->error[] = "No 2xx after putting DATA, server says: " . $smtpResponse; $this->sendSmtpQuit($smtpSocket); return false; } @@ -393,22 +365,21 @@ class Mail return true; } } - - + + /** * Sendet ein SMTP-Kommando zum SMTP-Server. - * + * * @access private * @param Resource $socket TCP/IP-Socket zum SMTP-Server * @param unknown_type $cmd SMTP-Kommando * @return Server-Antwort */ - private function sendSmtpCommand( $socket,$cmd ) + private function sendSmtpCommand($socket, $cmd) { - if ( $this->debug ) - $this->error[] = 'CLIENT: >>> '.trim($cmd); - if ( !is_resource($socket) ) - { + if ($this->debug) + $this->error[] = 'CLIENT: >>> ' . trim($cmd); + if (!is_resource($socket)) { // Die Verbindung ist geschlossen. Dies kann bei dieser // Implementierung eigentlich nur dann passieren, wenn // der Server die Verbindung schlie�t. @@ -416,85 +387,82 @@ class Mail $this->error[] = "Connection lost"; return; } - - fputs($socket,$cmd.$this->nl); + + fputs($socket, $cmd . $this->nl); $response = trim(fgets($socket, 4096)); - if ( $this->debug ) - $this->error[] = 'SERVER: <<< '.$response; + if ($this->debug) + $this->error[] = 'SERVER: <<< ' . $response; return $response; } - - - + + /** * Sendet ein QUIT zum SMTP-Server, wartet die Antwort ab und * schlie�t danach die Verbindung. * * @param Resource Socket */ - private function sendSmtpQuit( $socket ) + private function sendSmtpQuit($socket) { - - if ( $this->debug ) + + if ($this->debug) $this->error[] = "CLIENT: >>> QUIT"; - if ( !is_resource($socket) ) + if (!is_resource($socket)) return; - // Wenn die Verbindung nicht mehr da ist, brauchen wir - // auch kein QUIT mehr :) + // Wenn die Verbindung nicht mehr da ist, brauchen wir + // auch kein QUIT mehr :) - - fputs($socket,'QUIT'.$this->nl); + + fputs($socket, 'QUIT' . $this->nl); $response = trim(fgets($socket, 4096)); - if ( $this->debug ) - $this->error[] = 'SERVER: <<< '.$response; - - if ( substr($response,0,3) != '221' ) - $this->error[] = 'QUIT FAILED: '.$response; - + if ($this->debug) + $this->error[] = 'SERVER: <<< ' . $response; + + if (substr($response, 0, 3) != '221') + $this->error[] = 'QUIT FAILED: ' . $response; + fclose($socket); } - - - + + /** * Umwandlung von 8-bit-Zeichen in MIME-Header gemaess RFC 2047.<br> * Header d�rfen nur 7-bit-Zeichen enthalten. 8-bit-Zeichen m�ssen kodiert werden. - * + * * @param String $text * @return String */ - private function header_encode( $text ) + private function header_encode($text) { global $conf; - - if ( empty($conf['mail']['header_encoding']) ) + + if (empty($conf['mail']['header_encoding'])) return $text; - $woerter = explode(' ',$text); + $woerter = explode(' ', $text); $neu = array(); - - foreach( $woerter as $wort ) - { - $type = strtolower(substr($conf['mail']['header_encoding'],0,1)); + + foreach ($woerter as $wort) { + $type = strtolower(substr($conf['mail']['header_encoding'], 0, 1)); $neu_wort = ''; - - if ( $type == 'b' ) + + if ($type == 'b') $neu_wort = base64_encode($wort); - elseif ( $type == 'q' ) + elseif ($type == 'q') $neu_wort = $this->quoted_printable_encode($wort); else - throw new LogicException( 'Mail-Configuration broken: UNKNOWN Header-Encoding type: '.$type); + throw new LogicException('Mail-Configuration broken: UNKNOWN Header-Encoding type: ' . $type); - if ( strlen($wort)==strlen($neu_wort) ) + if (strlen($wort) == strlen($neu_wort)) $neu[] = $wort; else - $neu[] = '=?UTF-8?'.$type.'?'.$neu_wort.'?='; + $neu[] = '=?UTF-8?' . $type . '?' . $neu_wort . '?='; } - - return implode(' ',$neu); + + return implode(' ', $neu); } - + /** * Ermittelt den MX-Eintrag zu einer E-Mail-Adresse.<br> @@ -503,70 +471,64 @@ class Mail * @param String E-Mail-Adresse des Empf�ngers. * @return MX-Eintrag */ - private function getMxHost( $to ) + private function getMxHost($to) { - list($user,$host) = explode('@',$to.'@'); - - if ( empty($host) ) - { + list($user, $host) = explode('@', $to . '@'); + + if (empty($host)) { $this->error[] = 'Illegal mail address - No hostname found.'; return ""; } - - list($host) = explode('>',$host); - + + list($host) = explode('>', $host); + $mxHostsName = array(); $mxHostsPrio = array(); - getmxrr($host,$mxHostsName,$mxHostsPrio); - + getmxrr($host, $mxHostsName, $mxHostsPrio); + $mxList = array(); - foreach( $mxHostsName as $id=>$mxHostName ) - { - $mxList[$mxHostName] = $mxHostsPrio[$id]; + foreach ($mxHostsName as $id => $mxHostName) { + $mxList[$mxHostName] = $mxHostsPrio[$id]; } asort($mxList); return key($mxList); } - - + /** * Stellt fest, ob die E-Mail-Adresse eine gueltige Syntax besitzt. - * + * * Es wird nur die Syntax geprüft. Ob die Adresse wirklich existiert, steht dadurch noch lange * nicht fest. Dazu müsste man die MX-Records auflösen und einen Zustellversuch unternehmen. - * + * * @param $email_address Adresse * @return true, falls Adresse OK, sonst false */ - function checkAddress( $email_address ) + function checkAddress($email_address) { // Source: de.php.net/ereg return ereg("^[-A-Za-z0-9_]+[-A-Za-z0-9_.]*[@]{1}[-A-Za-z0-9_]+[-A-Za-z0-9_.]*[.]{1}[A-Za-z]{2,5}$", $email_address); } - - + /** * Prüft, ob eine Domain in einer List von Domains enthalten ist. - * + * * @param $checkDomain string zu prüfende Domain * @param $domain_list string Liste von Domains als kommaseparierte Liste * @return true, falls vorhanden, sonst false */ private static function containsDomain($checkDomain, $domain_list) { - $domains = explode(',',$domain_list); - - foreach( $domains as $domain ) - { + $domains = explode(',', $domain_list); + + foreach ($domains as $domain) { $domain = trim($domain); - - if (empty($domain)) + + if (empty($domain)) continue; - if ($domain == substr($checkDomain,-strlen($domain))) - { + if ($domain == substr($checkDomain, -strlen($domain))) { return true; } } diff --git a/modules/util/Mustache.class.php b/modules/util/Mustache.class.php @@ -1,7 +1,7 @@ <?php -namespace cms\mustache; +namespace util; /** diff --git a/modules/util/Parsedown.class.php b/modules/util/Parsedown.class.php @@ -13,1982 +13,1809 @@ # # +namespace util; class Parsedown { - # ~ + # ~ - const version = '1.8.0-beta-7'; + const version = '1.8.0-beta-7'; - # ~ + # ~ - function text($text) - { - $Elements = $this->textElements($text); + function text($text) + { + $Elements = $this->textElements($text); - # convert to markup - $markup = $this->elements($Elements); + # convert to markup + $markup = $this->elements($Elements); - # trim line breaks - $markup = trim($markup, "\n"); + # trim line breaks + $markup = trim($markup, "\n"); - return $markup; - } + return $markup; + } - protected function textElements($text) - { - # make sure no definitions are set - $this->DefinitionData = array(); - - # standardize line breaks - $text = str_replace(array("\r\n", "\r"), "\n", $text); - - # remove surrounding line breaks - $text = trim($text, "\n"); - - # split text into lines - $lines = explode("\n", $text); - - # iterate through lines to identify blocks - return $this->linesElements($lines); - } - - # - # Setters - # - - function setBreaksEnabled($breaksEnabled) - { - $this->breaksEnabled = $breaksEnabled; - - return $this; - } - - protected $breaksEnabled; - - function setMarkupEscaped($markupEscaped) - { - $this->markupEscaped = $markupEscaped; - - return $this; - } - - protected $markupEscaped; - - function setUrlsLinked($urlsLinked) - { - $this->urlsLinked = $urlsLinked; - - return $this; - } - - protected $urlsLinked = true; - - function setSafeMode($safeMode) - { - $this->safeMode = (bool) $safeMode; - - return $this; - } - - protected $safeMode; - - function setStrictMode($strictMode) - { - $this->strictMode = (bool) $strictMode; - - return $this; - } - - protected $strictMode; - - protected $safeLinksWhitelist = array( - 'http://', - 'https://', - 'ftp://', - 'ftps://', - 'mailto:', - 'tel:', - 'data:image/png;base64,', - 'data:image/gif;base64,', - 'data:image/jpeg;base64,', - 'irc:', - 'ircs:', - 'git:', - 'ssh:', - 'news:', - 'steam:', - ); - - # - # Lines - # - - protected $BlockTypes = array( - '#' => array('Header'), - '*' => array('Rule', 'List'), - '+' => array('List'), - '-' => array('SetextHeader', 'Table', 'Rule', 'List'), - '0' => array('List'), - '1' => array('List'), - '2' => array('List'), - '3' => array('List'), - '4' => array('List'), - '5' => array('List'), - '6' => array('List'), - '7' => array('List'), - '8' => array('List'), - '9' => array('List'), - ':' => array('Table'), - '<' => array('Comment', 'Markup'), - '=' => array('SetextHeader'), - '>' => array('Quote'), - '[' => array('Reference'), - '_' => array('Rule'), - '`' => array('FencedCode'), - '|' => array('Table'), - '~' => array('FencedCode'), - ); - - # ~ - - protected $unmarkedBlockTypes = array( - 'Code', - ); - - # - # Blocks - # - - protected function lines(array $lines) - { - return $this->elements($this->linesElements($lines)); - } - - protected function linesElements(array $lines) - { - $Elements = array(); - $CurrentBlock = null; - - foreach ($lines as $line) - { - if (chop($line) === '') - { - if (isset($CurrentBlock)) - { - $CurrentBlock['interrupted'] = (isset($CurrentBlock['interrupted']) - ? $CurrentBlock['interrupted'] + 1 : 1 - ); - } - - continue; - } - - while (($beforeTab = strstr($line, "\t", true)) !== false) - { - $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4; - - $line = $beforeTab - . str_repeat(' ', $shortage) - . substr($line, strlen($beforeTab) + 1) - ; - } - - $indent = strspn($line, ' '); - - $text = $indent > 0 ? substr($line, $indent) : $line; - - # ~ - - $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); - - # ~ - - if (isset($CurrentBlock['continuable'])) - { - $methodName = 'block' . $CurrentBlock['type'] . 'Continue'; - $Block = $this->$methodName($Line, $CurrentBlock); - - if (isset($Block)) - { - $CurrentBlock = $Block; - - continue; - } - else - { - if ($this->isBlockCompletable($CurrentBlock['type'])) - { - $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; - $CurrentBlock = $this->$methodName($CurrentBlock); - } - } - } - - # ~ - - $marker = $text[0]; - - # ~ - - $blockTypes = $this->unmarkedBlockTypes; - - if (isset($this->BlockTypes[$marker])) - { - foreach ($this->BlockTypes[$marker] as $blockType) - { - $blockTypes []= $blockType; - } - } - - # - # ~ - - foreach ($blockTypes as $blockType) - { - $Block = $this->{"block$blockType"}($Line, $CurrentBlock); - - if (isset($Block)) - { - $Block['type'] = $blockType; - - if ( ! isset($Block['identified'])) - { - if (isset($CurrentBlock)) - { - $Elements[] = $this->extractElement($CurrentBlock); - } - - $Block['identified'] = true; - } - - if ($this->isBlockContinuable($blockType)) - { - $Block['continuable'] = true; - } - - $CurrentBlock = $Block; - - continue 2; - } - } - - # ~ - - if (isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph') - { - $Block = $this->paragraphContinue($Line, $CurrentBlock); - } - - if (isset($Block)) - { - $CurrentBlock = $Block; - } - else - { - if (isset($CurrentBlock)) - { - $Elements[] = $this->extractElement($CurrentBlock); - } - - $CurrentBlock = $this->paragraph($Line); - - $CurrentBlock['identified'] = true; - } - } - - # ~ - - if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) - { - $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; - $CurrentBlock = $this->$methodName($CurrentBlock); - } - - # ~ - - if (isset($CurrentBlock)) - { - $Elements[] = $this->extractElement($CurrentBlock); - } - - # ~ - - return $Elements; - } - - protected function extractElement(array $Component) - { - if ( ! isset($Component['element'])) - { - if (isset($Component['markup'])) - { - $Component['element'] = array('rawHtml' => $Component['markup']); - } - elseif (isset($Component['hidden'])) - { - $Component['element'] = array(); - } - } - - return $Component['element']; - } - - protected function isBlockContinuable($Type) - { - return method_exists($this, 'block' . $Type . 'Continue'); - } - - protected function isBlockCompletable($Type) - { - return method_exists($this, 'block' . $Type . 'Complete'); - } - - # - # Code - - protected function blockCode($Line, $Block = null) - { - if (isset($Block) and $Block['type'] === 'Paragraph' and ! isset($Block['interrupted'])) - { - return; - } - - if ($Line['indent'] >= 4) - { - $text = substr($Line['body'], 4); - - $Block = array( - 'element' => array( - 'name' => 'pre', - 'element' => array( - 'name' => 'code', - 'text' => $text, - ), - ), - ); - - return $Block; - } - } - - protected function blockCodeContinue($Line, $Block) - { - if ($Line['indent'] >= 4) - { - if (isset($Block['interrupted'])) - { - $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); - - unset($Block['interrupted']); - } - - $Block['element']['element']['text'] .= "\n"; - - $text = substr($Line['body'], 4); - - $Block['element']['element']['text'] .= $text; - - return $Block; - } - } - - protected function blockCodeComplete($Block) - { - return $Block; - } - - # - # Comment - - protected function blockComment($Line) - { - if ($this->markupEscaped or $this->safeMode) - { - return; - } - - if (strpos($Line['text'], '<!--') === 0) - { - $Block = array( - 'element' => array( - 'rawHtml' => $Line['body'], - 'autobreak' => true, - ), - ); - - if (strpos($Line['text'], '-->') !== false) - { - $Block['closed'] = true; - } - - return $Block; - } - } - - protected function blockCommentContinue($Line, array $Block) - { - if (isset($Block['closed'])) - { - return; - } - - $Block['element']['rawHtml'] .= "\n" . $Line['body']; - - if (strpos($Line['text'], '-->') !== false) - { - $Block['closed'] = true; - } - - return $Block; - } - - # - # Fenced Code - - protected function blockFencedCode($Line) - { - $marker = $Line['text'][0]; - - $openerLength = strspn($Line['text'], $marker); - - if ($openerLength < 3) - { - return; - } - - $infostring = trim(substr($Line['text'], $openerLength), "\t "); - - if (strpos($infostring, '`') !== false) - { - return; - } - - $Element = array( - 'name' => 'code', - 'text' => '', - ); - - if ($infostring !== '') - { - /** - * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes - * Every HTML element may have a class attribute specified. - * The attribute, if specified, must have a value that is a set - * of space-separated tokens representing the various classes - * that the element belongs to. - * [...] - * The space characters, for the purposes of this specification, - * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), - * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and - * U+000D CARRIAGE RETURN (CR). - */ - $language = substr($infostring, 0, strcspn($infostring, " \t\n\f\r")); - - $Element['attributes'] = array('class' => "language-$language"); - } - - $Block = array( - 'char' => $marker, - 'openerLength' => $openerLength, - 'element' => array( - 'name' => 'pre', - 'element' => $Element, - ), - ); - - return $Block; - } - - protected function blockFencedCodeContinue($Line, $Block) - { - if (isset($Block['complete'])) - { - return; - } - - if (isset($Block['interrupted'])) - { - $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); - - unset($Block['interrupted']); - } - - if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] - and chop(substr($Line['text'], $len), ' ') === '' - ) { - $Block['element']['element']['text'] = substr($Block['element']['element']['text'], 1); - - $Block['complete'] = true; - - return $Block; - } - - $Block['element']['element']['text'] .= "\n" . $Line['body']; - - return $Block; - } - - protected function blockFencedCodeComplete($Block) - { - return $Block; - } - - # - # Header - - protected function blockHeader($Line) - { - $level = strspn($Line['text'], '#'); - - if ($level > 6) - { - return; - } - - $text = trim($Line['text'], '#'); - - if ($this->strictMode and isset($text[0]) and $text[0] !== ' ') - { - return; - } - - $text = trim($text, ' '); - - $Block = array( - 'element' => array( - 'name' => 'h' . $level, - 'handler' => array( - 'function' => 'lineElements', - 'argument' => $text, - 'destination' => 'elements', - ) - ), - ); - - return $Block; - } - - # - # List - - protected function blockList($Line, array $CurrentBlock = null) - { - list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]{1,9}+[.\)]'); - - if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches)) - { - $contentIndent = strlen($matches[2]); - - if ($contentIndent >= 5) - { - $contentIndent -= 1; - $matches[1] = substr($matches[1], 0, -$contentIndent); - $matches[3] = str_repeat(' ', $contentIndent) . $matches[3]; - } - elseif ($contentIndent === 0) - { - $matches[1] .= ' '; - } - - $markerWithoutWhitespace = strstr($matches[1], ' ', true); - - $Block = array( - 'indent' => $Line['indent'], - 'pattern' => $pattern, - 'data' => array( - 'type' => $name, - 'marker' => $matches[1], - 'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : substr($markerWithoutWhitespace, -1)), - ), - 'element' => array( - 'name' => $name, - 'elements' => array(), - ), - ); - $Block['data']['markerTypeRegex'] = preg_quote($Block['data']['markerType'], '/'); - - if ($name === 'ol') - { - $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; - - if ($listStart !== '1') - { - if ( - isset($CurrentBlock) - and $CurrentBlock['type'] === 'Paragraph' - and ! isset($CurrentBlock['interrupted']) - ) { - return; - } - - $Block['element']['attributes'] = array('start' => $listStart); - } - } - - $Block['li'] = array( - 'name' => 'li', - 'handler' => array( - 'function' => 'li', - 'argument' => !empty($matches[3]) ? array($matches[3]) : array(), - 'destination' => 'elements' - ) - ); - - $Block['element']['elements'] []= & $Block['li']; - - return $Block; - } - } - - protected function blockListContinue($Line, array $Block) - { - if (isset($Block['interrupted']) and empty($Block['li']['handler']['argument'])) - { - return null; - } - - $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker'])); - - if ($Line['indent'] < $requiredIndent - and ( - ( - $Block['data']['type'] === 'ol' - and preg_match('/^[0-9]++'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) - ) or ( - $Block['data']['type'] === 'ul' - and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) - ) - ) - ) { - if (isset($Block['interrupted'])) - { - $Block['li']['handler']['argument'] []= ''; - - $Block['loose'] = true; - - unset($Block['interrupted']); - } - - unset($Block['li']); - - $text = isset($matches[1]) ? $matches[1] : ''; - - $Block['indent'] = $Line['indent']; - - $Block['li'] = array( - 'name' => 'li', - 'handler' => array( - 'function' => 'li', - 'argument' => array($text), - 'destination' => 'elements' - ) - ); - - $Block['element']['elements'] []= & $Block['li']; - - return $Block; - } - elseif ($Line['indent'] < $requiredIndent and $this->blockList($Line)) - { - return null; - } - - if ($Line['text'][0] === '[' and $this->blockReference($Line)) - { - return $Block; - } - - if ($Line['indent'] >= $requiredIndent) - { - if (isset($Block['interrupted'])) - { - $Block['li']['handler']['argument'] []= ''; - - $Block['loose'] = true; - - unset($Block['interrupted']); - } - - $text = substr($Line['body'], $requiredIndent); - - $Block['li']['handler']['argument'] []= $text; - - return $Block; - } - - if ( ! isset($Block['interrupted'])) - { - $text = preg_replace('/^[ ]{0,'.$requiredIndent.'}+/', '', $Line['body']); - - $Block['li']['handler']['argument'] []= $text; - - return $Block; - } - } - - protected function blockListComplete(array $Block) - { - if (isset($Block['loose'])) - { - foreach ($Block['element']['elements'] as &$li) - { - if (end($li['handler']['argument']) !== '') - { - $li['handler']['argument'] []= ''; - } - } - } - - return $Block; - } - - # - # Quote - - protected function blockQuote($Line) - { - if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) - { - $Block = array( - 'element' => array( - 'name' => 'blockquote', - 'handler' => array( - 'function' => 'linesElements', - 'argument' => (array) $matches[1], - 'destination' => 'elements', - ) - ), - ); - - return $Block; - } - } - - protected function blockQuoteContinue($Line, array $Block) - { - if (isset($Block['interrupted'])) - { - return; - } - - if ($Line['text'][0] === '>' and preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) - { - $Block['element']['handler']['argument'] []= $matches[1]; - - return $Block; - } - - if ( ! isset($Block['interrupted'])) - { - $Block['element']['handler']['argument'] []= $Line['text']; - - return $Block; - } - } - - # - # Rule - - protected function blockRule($Line) - { - $marker = $Line['text'][0]; - - if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], " $marker") === '') - { - $Block = array( - 'element' => array( - 'name' => 'hr', - ), - ); - - return $Block; - } - } - - # - # Setext - - protected function blockSetextHeader($Line, array $Block = null) - { - if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted'])) - { - return; - } - - if ($Line['indent'] < 4 and chop(chop($Line['text'], ' '), $Line['text'][0]) === '') - { - $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; - - return $Block; - } - } - - # - # Markup - - protected function blockMarkup($Line) - { - if ($this->markupEscaped or $this->safeMode) - { - return; - } - - if (preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+(\/)?>/', $Line['text'], $matches)) - { - $element = strtolower($matches[1]); - - if (in_array($element, $this->textLevelElements)) - { - return; - } - - $Block = array( - 'name' => $matches[1], - 'element' => array( - 'rawHtml' => $Line['text'], - 'autobreak' => true, - ), - ); - - return $Block; - } - } - - protected function blockMarkupContinue($Line, array $Block) - { - if (isset($Block['closed']) or isset($Block['interrupted'])) - { - return; - } - - $Block['element']['rawHtml'] .= "\n" . $Line['body']; - - return $Block; - } - - # - # Reference - - protected function blockReference($Line) - { - if (strpos($Line['text'], ']') !== false - and preg_match('/^\[(.+?)\]:[ ]*+<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches) - ) { - $id = strtolower($matches[1]); - - $Data = array( - 'url' => $matches[2], - 'title' => isset($matches[3]) ? $matches[3] : null, - ); - - $this->DefinitionData['Reference'][$id] = $Data; - - $Block = array( - 'element' => array(), - ); - - return $Block; - } - } - - # - # Table - - protected function blockTable($Line, array $Block = null) - { - if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted'])) - { - return; - } - - if ( - strpos($Block['element']['handler']['argument'], '|') === false - and strpos($Line['text'], '|') === false - and strpos($Line['text'], ':') === false - or strpos($Block['element']['handler']['argument'], "\n") !== false - ) { - return; - } - - if (chop($Line['text'], ' -:|') !== '') - { - return; - } - - $alignments = array(); - - $divider = $Line['text']; - - $divider = trim($divider); - $divider = trim($divider, '|'); - - $dividerCells = explode('|', $divider); - - foreach ($dividerCells as $dividerCell) - { - $dividerCell = trim($dividerCell); - - if ($dividerCell === '') - { - return; - } - - $alignment = null; - - if ($dividerCell[0] === ':') - { - $alignment = 'left'; - } - - if (substr($dividerCell, - 1) === ':') - { - $alignment = $alignment === 'left' ? 'center' : 'right'; - } - - $alignments []= $alignment; - } - - # ~ + protected function textElements($text) + { + # make sure no definitions are set + $this->DefinitionData = array(); + + # standardize line breaks + $text = str_replace(array("\r\n", "\r"), "\n", $text); + + # remove surrounding line breaks + $text = trim($text, "\n"); + + # split text into lines + $lines = explode("\n", $text); + + # iterate through lines to identify blocks + return $this->linesElements($lines); + } + + # + # Setters + # + + function setBreaksEnabled($breaksEnabled) + { + $this->breaksEnabled = $breaksEnabled; + + return $this; + } + + protected $breaksEnabled; + + function setMarkupEscaped($markupEscaped) + { + $this->markupEscaped = $markupEscaped; + + return $this; + } + + protected $markupEscaped; + + function setUrlsLinked($urlsLinked) + { + $this->urlsLinked = $urlsLinked; + + return $this; + } + + protected $urlsLinked = true; + + function setSafeMode($safeMode) + { + $this->safeMode = (bool)$safeMode; + + return $this; + } + + protected $safeMode; + + function setStrictMode($strictMode) + { + $this->strictMode = (bool)$strictMode; + + return $this; + } + + protected $strictMode; + + protected $safeLinksWhitelist = array( + 'http://', + 'https://', + 'ftp://', + 'ftps://', + 'mailto:', + 'tel:', + 'data:image/png;base64,', + 'data:image/gif;base64,', + 'data:image/jpeg;base64,', + 'irc:', + 'ircs:', + 'git:', + 'ssh:', + 'news:', + 'steam:', + ); + + # + # Lines + # + + protected $BlockTypes = array( + '#' => array('Header'), + '*' => array('Rule', 'List'), + '+' => array('List'), + '-' => array('SetextHeader', 'Table', 'Rule', 'List'), + '0' => array('List'), + '1' => array('List'), + '2' => array('List'), + '3' => array('List'), + '4' => array('List'), + '5' => array('List'), + '6' => array('List'), + '7' => array('List'), + '8' => array('List'), + '9' => array('List'), + ':' => array('Table'), + '<' => array('Comment', 'Markup'), + '=' => array('SetextHeader'), + '>' => array('Quote'), + '[' => array('Reference'), + '_' => array('Rule'), + '`' => array('FencedCode'), + '|' => array('Table'), + '~' => array('FencedCode'), + ); + + # ~ + + protected $unmarkedBlockTypes = array( + 'Code', + ); + + # + # Blocks + # + + protected function lines(array $lines) + { + return $this->elements($this->linesElements($lines)); + } + + protected function linesElements(array $lines) + { + $Elements = array(); + $CurrentBlock = null; + + foreach ($lines as $line) { + if (chop($line) === '') { + if (isset($CurrentBlock)) { + $CurrentBlock['interrupted'] = (isset($CurrentBlock['interrupted']) + ? $CurrentBlock['interrupted'] + 1 : 1 + ); + } + + continue; + } + + while (($beforeTab = strstr($line, "\t", true)) !== false) { + $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4; + + $line = $beforeTab + . str_repeat(' ', $shortage) + . substr($line, strlen($beforeTab) + 1); + } + + $indent = strspn($line, ' '); + + $text = $indent > 0 ? substr($line, $indent) : $line; + + # ~ + + $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); + + # ~ + + if (isset($CurrentBlock['continuable'])) { + $methodName = 'block' . $CurrentBlock['type'] . 'Continue'; + $Block = $this->$methodName($Line, $CurrentBlock); + + if (isset($Block)) { + $CurrentBlock = $Block; + + continue; + } else { + if ($this->isBlockCompletable($CurrentBlock['type'])) { + $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; + $CurrentBlock = $this->$methodName($CurrentBlock); + } + } + } + + # ~ + + $marker = $text[0]; + + # ~ + + $blockTypes = $this->unmarkedBlockTypes; + + if (isset($this->BlockTypes[$marker])) { + foreach ($this->BlockTypes[$marker] as $blockType) { + $blockTypes [] = $blockType; + } + } + + # + # ~ + + foreach ($blockTypes as $blockType) { + $Block = $this->{"block$blockType"}($Line, $CurrentBlock); + + if (isset($Block)) { + $Block['type'] = $blockType; - $HeaderElements = array(); - - $header = $Block['element']['handler']['argument']; - - $header = trim($header); - $header = trim($header, '|'); - - $headerCells = explode('|', $header); - - if (count($headerCells) !== count($alignments)) - { - return; - } - - foreach ($headerCells as $index => $headerCell) - { - $headerCell = trim($headerCell); - - $HeaderElement = array( - 'name' => 'th', - 'handler' => array( - 'function' => 'lineElements', - 'argument' => $headerCell, - 'destination' => 'elements', - ) - ); - - if (isset($alignments[$index])) - { - $alignment = $alignments[$index]; - - $HeaderElement['attributes'] = array( - 'style' => "text-align: $alignment;", - ); - } - - $HeaderElements []= $HeaderElement; - } - - # ~ - - $Block = array( - 'alignments' => $alignments, - 'identified' => true, - 'element' => array( - 'name' => 'table', - 'elements' => array(), - ), - ); - - $Block['element']['elements'] []= array( - 'name' => 'thead', - ); - - $Block['element']['elements'] []= array( - 'name' => 'tbody', - 'elements' => array(), - ); - - $Block['element']['elements'][0]['elements'] []= array( - 'name' => 'tr', - 'elements' => $HeaderElements, - ); - - return $Block; - } - - protected function blockTableContinue($Line, array $Block) - { - if (isset($Block['interrupted'])) - { - return; - } - - if (count($Block['alignments']) === 1 or $Line['text'][0] === '|' or strpos($Line['text'], '|')) - { - $Elements = array(); - - $row = $Line['text']; - - $row = trim($row); - $row = trim($row, '|'); - - preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]++`|`)++/', $row, $matches); - - $cells = array_slice($matches[0], 0, count($Block['alignments'])); - - foreach ($cells as $index => $cell) - { - $cell = trim($cell); - - $Element = array( - 'name' => 'td', - 'handler' => array( - 'function' => 'lineElements', - 'argument' => $cell, - 'destination' => 'elements', - ) - ); - - if (isset($Block['alignments'][$index])) - { - $Element['attributes'] = array( - 'style' => 'text-align: ' . $Block['alignments'][$index] . ';', - ); - } - - $Elements []= $Element; - } - - $Element = array( - 'name' => 'tr', - 'elements' => $Elements, - ); - - $Block['element']['elements'][1]['elements'] []= $Element; - - return $Block; - } - } - - # - # ~ - # - - protected function paragraph($Line) - { - return array( - 'type' => 'Paragraph', - 'element' => array( - 'name' => 'p', - 'handler' => array( - 'function' => 'lineElements', - 'argument' => $Line['text'], - 'destination' => 'elements', - ), - ), - ); - } - - protected function paragraphContinue($Line, array $Block) - { - if (isset($Block['interrupted'])) - { - return; - } - - $Block['element']['handler']['argument'] .= "\n".$Line['text']; - - return $Block; - } - - # - # Inline Elements - # - - protected $InlineTypes = array( - '!' => array('Image'), - '&' => array('SpecialCharacter'), - '*' => array('Emphasis'), - ':' => array('Url'), - '<' => array('UrlTag', 'EmailTag', 'Markup'), - '[' => array('Link'), - '_' => array('Emphasis'), - '`' => array('Code'), - '~' => array('Strikethrough'), - '\\' => array('EscapeSequence'), - ); + if (!isset($Block['identified'])) { + if (isset($CurrentBlock)) { + $Elements[] = $this->extractElement($CurrentBlock); + } - # ~ + $Block['identified'] = true; + } - protected $inlineMarkerList = '!*_&[:<`~\\'; + if ($this->isBlockContinuable($blockType)) { + $Block['continuable'] = true; + } - # - # ~ - # + $CurrentBlock = $Block; - public function line($text, $nonNestables = array()) - { - return $this->elements($this->lineElements($text, $nonNestables)); - } + continue 2; + } + } - protected function lineElements($text, $nonNestables = array()) - { - # standardize line breaks - $text = str_replace(array("\r\n", "\r"), "\n", $text); + # ~ - $Elements = array(); - - $nonNestables = (empty($nonNestables) - ? array() - : array_combine($nonNestables, $nonNestables) - ); - - # $excerpt is based on the first occurrence of a marker - - while ($excerpt = strpbrk($text, $this->inlineMarkerList)) - { - $marker = $excerpt[0]; - - $markerPosition = strlen($text) - strlen($excerpt); - - $Excerpt = array('text' => $excerpt, 'context' => $text); - - foreach ($this->InlineTypes[$marker] as $inlineType) - { - # check to see if the current inline type is nestable in the current context - - if (isset($nonNestables[$inlineType])) - { - continue; - } - - $Inline = $this->{"inline$inlineType"}($Excerpt); + if (isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph') { + $Block = $this->paragraphContinue($Line, $CurrentBlock); + } - if ( ! isset($Inline)) - { - continue; - } - - # makes sure that the inline belongs to "our" marker - - if (isset($Inline['position']) and $Inline['position'] > $markerPosition) - { - continue; - } - - # sets a default inline position - - if ( ! isset($Inline['position'])) - { - $Inline['position'] = $markerPosition; - } - - # cause the new element to 'inherit' our non nestables + if (isset($Block)) { + $CurrentBlock = $Block; + } else { + if (isset($CurrentBlock)) { + $Elements[] = $this->extractElement($CurrentBlock); + } + $CurrentBlock = $this->paragraph($Line); - $Inline['element']['nonNestables'] = isset($Inline['element']['nonNestables']) - ? array_merge($Inline['element']['nonNestables'], $nonNestables) - : $nonNestables - ; + $CurrentBlock['identified'] = true; + } + } - # the text that comes before the inline - $unmarkedText = substr($text, 0, $Inline['position']); + # ~ - # compile the unmarked text - $InlineText = $this->inlineText($unmarkedText); - $Elements[] = $InlineText['element']; - - # compile the inline - $Elements[] = $this->extractElement($Inline); - - # remove the examined text - $text = substr($text, $Inline['position'] + $Inline['extent']); - - continue 2; - } - - # the marker does not belong to an inline - - $unmarkedText = substr($text, 0, $markerPosition + 1); - - $InlineText = $this->inlineText($unmarkedText); - $Elements[] = $InlineText['element']; - - $text = substr($text, $markerPosition + 1); - } - - $InlineText = $this->inlineText($text); - $Elements[] = $InlineText['element']; - - foreach ($Elements as &$Element) - { - if ( ! isset($Element['autobreak'])) - { - $Element['autobreak'] = false; - } - } - - return $Elements; - } - - # - # ~ - # - - protected function inlineText($text) - { - $Inline = array( - 'extent' => strlen($text), - 'element' => array(), - ); - - $Inline['element']['elements'] = self::pregReplaceElements( - $this->breaksEnabled ? '/[ ]*+\n/' : '/(?:[ ]*+\\\\|[ ]{2,}+)\n/', - array( - array('name' => 'br'), - array('text' => "\n"), - ), - $text - ); - - return $Inline; - } - - protected function inlineCode($Excerpt) - { - $marker = $Excerpt['text'][0]; - - if (preg_match('/^(['.$marker.']++)[ ]*+(.+?)[ ]*+(?<!['.$marker.'])\1(?!'.$marker.')/s', $Excerpt['text'], $matches)) - { - $text = $matches[2]; - $text = preg_replace('/[ ]*+\n/', ' ', $text); - - return array( - 'extent' => strlen($matches[0]), - 'element' => array( - 'name' => 'code', - 'text' => $text, - ), - ); - } - } - - protected function inlineEmailTag($Excerpt) - { - $hostnameLabel = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?'; - - $commonMarkEmail = '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]++@' - . $hostnameLabel . '(?:\.' . $hostnameLabel . ')*'; - - if (strpos($Excerpt['text'], '>') !== false - and preg_match("/^<((mailto:)?$commonMarkEmail)>/i", $Excerpt['text'], $matches) - ){ - $url = $matches[1]; - - if ( ! isset($matches[2])) - { - $url = "mailto:$url"; - } - - return array( - 'extent' => strlen($matches[0]), - 'element' => array( - 'name' => 'a', - 'text' => $matches[1], - 'attributes' => array( - 'href' => $url, - ), - ), - ); - } - } - - protected function inlineEmphasis($Excerpt) - { - if ( ! isset($Excerpt['text'][1])) - { - return; - } - - $marker = $Excerpt['text'][0]; - - if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) - { - $emphasis = 'strong'; - } - elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) - { - $emphasis = 'em'; - } - else - { - return; - } - - return array( - 'extent' => strlen($matches[0]), - 'element' => array( - 'name' => $emphasis, - 'handler' => array( - 'function' => 'lineElements', - 'argument' => $matches[1], - 'destination' => 'elements', - ) - ), - ); - } - - protected function inlineEscapeSequence($Excerpt) - { - if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) - { - return array( - 'element' => array('rawHtml' => $Excerpt['text'][1]), - 'extent' => 2, - ); - } - } - - protected function inlineImage($Excerpt) - { - if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') - { - return; - } - - $Excerpt['text']= substr($Excerpt['text'], 1); - - $Link = $this->inlineLink($Excerpt); - - if ($Link === null) - { - return; - } - - $Inline = array( - 'extent' => $Link['extent'] + 1, - 'element' => array( - 'name' => 'img', - 'attributes' => array( - 'src' => $Link['element']['attributes']['href'], - 'alt' => $Link['element']['handler']['argument'], - ), - 'autobreak' => true, - ), - ); - - $Inline['element']['attributes'] += $Link['element']['attributes']; - - unset($Inline['element']['attributes']['href']); - - return $Inline; - } - - protected function inlineLink($Excerpt) - { - $Element = array( - 'name' => 'a', - 'handler' => array( - 'function' => 'lineElements', - 'argument' => null, - 'destination' => 'elements', - ), - 'nonNestables' => array('Url', 'Link'), - 'attributes' => array( - 'href' => null, - 'title' => null, - ), - ); - - $extent = 0; - - $remainder = $Excerpt['text']; - - if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) - { - $Element['handler']['argument'] = $matches[1]; - - $extent += strlen($matches[0]); - - $remainder = substr($remainder, $extent); - } - else - { - return; - } - - if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) - { - $Element['attributes']['href'] = $matches[1]; - - if (isset($matches[2])) - { - $Element['attributes']['title'] = substr($matches[2], 1, - 1); - } - - $extent += strlen($matches[0]); - } - else - { - if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) - { - $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument']; - $definition = strtolower($definition); - - $extent += strlen($matches[0]); - } - else - { - $definition = strtolower($Element['handler']['argument']); - } - - if ( ! isset($this->DefinitionData['Reference'][$definition])) - { - return; - } - - $Definition = $this->DefinitionData['Reference'][$definition]; - - $Element['attributes']['href'] = $Definition['url']; - $Element['attributes']['title'] = $Definition['title']; - } - - return array( - 'extent' => $extent, - 'element' => $Element, - ); - } - - protected function inlineMarkup($Excerpt) - { - if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) - { - return; - } - - if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches)) - { - return array( - 'element' => array('rawHtml' => $matches[0]), - 'extent' => strlen($matches[0]), - ); - } - - if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?+[^-])*-->/s', $Excerpt['text'], $matches)) - { - return array( - 'element' => array('rawHtml' => $matches[0]), - 'extent' => strlen($matches[0]), - ); - } - - if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) - { - return array( - 'element' => array('rawHtml' => $matches[0]), - 'extent' => strlen($matches[0]), - ); - } - } - - protected function inlineSpecialCharacter($Excerpt) - { - if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false - and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches) - ) { - return array( - 'element' => array('rawHtml' => '&' . $matches[1] . ';'), - 'extent' => strlen($matches[0]), - ); - } - - return; - } - - protected function inlineStrikethrough($Excerpt) - { - if ( ! isset($Excerpt['text'][1])) - { - return; - } - - if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) - { - return array( - 'extent' => strlen($matches[0]), - 'element' => array( - 'name' => 'del', - 'handler' => array( - 'function' => 'lineElements', - 'argument' => $matches[1], - 'destination' => 'elements', - ) - ), - ); - } - } - - protected function inlineUrl($Excerpt) - { - if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') - { - return; - } - - if (strpos($Excerpt['context'], 'http') !== false - and preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE) - ) { - $url = $matches[0][0]; - - $Inline = array( - 'extent' => strlen($matches[0][0]), - 'position' => $matches[0][1], - 'element' => array( - 'name' => 'a', - 'text' => $url, - 'attributes' => array( - 'href' => $url, - ), - ), - ); - - return $Inline; - } - } - - protected function inlineUrlTag($Excerpt) - { - if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches)) - { - $url = $matches[1]; - - return array( - 'extent' => strlen($matches[0]), - 'element' => array( - 'name' => 'a', - 'text' => $url, - 'attributes' => array( - 'href' => $url, - ), - ), - ); - } - } - - # ~ - - protected function unmarkedText($text) - { - $Inline = $this->inlineText($text); - return $this->element($Inline['element']); - } - - # - # Handlers - # - - protected function handle(array $Element) - { - if (isset($Element['handler'])) - { - if (!isset($Element['nonNestables'])) - { - $Element['nonNestables'] = array(); - } - - if (is_string($Element['handler'])) - { - $function = $Element['handler']; - $argument = $Element['text']; - unset($Element['text']); - $destination = 'rawHtml'; - } - else - { - $function = $Element['handler']['function']; - $argument = $Element['handler']['argument']; - $destination = $Element['handler']['destination']; - } - - $Element[$destination] = $this->{$function}($argument, $Element['nonNestables']); - - if ($destination === 'handler') - { - $Element = $this->handle($Element); - } - - unset($Element['handler']); - } - - return $Element; - } - - protected function handleElementRecursive(array $Element) - { - return $this->elementApplyRecursive(array($this, 'handle'), $Element); - } - - protected function handleElementsRecursive(array $Elements) - { - return $this->elementsApplyRecursive(array($this, 'handle'), $Elements); - } - - protected function elementApplyRecursive($closure, array $Element) - { - $Element = call_user_func($closure, $Element); - - if (isset($Element['elements'])) - { - $Element['elements'] = $this->elementsApplyRecursive($closure, $Element['elements']); - } - elseif (isset($Element['element'])) - { - $Element['element'] = $this->elementApplyRecursive($closure, $Element['element']); - } - - return $Element; - } - - protected function elementApplyRecursiveDepthFirst($closure, array $Element) - { - if (isset($Element['elements'])) - { - $Element['elements'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['elements']); - } - elseif (isset($Element['element'])) - { - $Element['element'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['element']); - } - - $Element = call_user_func($closure, $Element); - - return $Element; - } - - protected function elementsApplyRecursive($closure, array $Elements) - { - foreach ($Elements as &$Element) - { - $Element = $this->elementApplyRecursive($closure, $Element); - } - - return $Elements; - } - - protected function elementsApplyRecursiveDepthFirst($closure, array $Elements) - { - foreach ($Elements as &$Element) - { - $Element = $this->elementApplyRecursiveDepthFirst($closure, $Element); - } - - return $Elements; - } - - protected function element(array $Element) - { - if ($this->safeMode) - { - $Element = $this->sanitiseElement($Element); - } - - # identity map if element has no handler - $Element = $this->handle($Element); - - $hasName = isset($Element['name']); - - $markup = ''; - - if ($hasName) - { - $markup .= '<' . $Element['name']; - - if (isset($Element['attributes'])) - { - foreach ($Element['attributes'] as $name => $value) - { - if ($value === null) - { - continue; - } - - $markup .= " $name=\"".self::escape($value).'"'; - } - } - } - - $permitRawHtml = false; - - if (isset($Element['text'])) - { - $text = $Element['text']; - } - // very strongly consider an alternative if you're writing an - // extension - elseif (isset($Element['rawHtml'])) - { - $text = $Element['rawHtml']; - - $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode']; - $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode; - } - - $hasContent = isset($text) || isset($Element['element']) || isset($Element['elements']); - - if ($hasContent) - { - $markup .= $hasName ? '>' : ''; - - if (isset($Element['elements'])) - { - $markup .= $this->elements($Element['elements']); - } - elseif (isset($Element['element'])) - { - $markup .= $this->element($Element['element']); - } - else - { - if (!$permitRawHtml) - { - $markup .= self::escape($text, true); - } - else - { - $markup .= $text; - } - } - - $markup .= $hasName ? '</' . $Element['name'] . '>' : ''; - } - elseif ($hasName) - { - $markup .= ' />'; - } - - return $markup; - } - - protected function elements(array $Elements) - { - $markup = ''; - - $autoBreak = true; - - foreach ($Elements as $Element) - { - if (empty($Element)) - { - continue; - } - - $autoBreakNext = (isset($Element['autobreak']) - ? $Element['autobreak'] : isset($Element['name']) - ); - // (autobreak === false) covers both sides of an element - $autoBreak = !$autoBreak ? $autoBreak : $autoBreakNext; - - $markup .= ($autoBreak ? "\n" : '') . $this->element($Element); - $autoBreak = $autoBreakNext; - } - - $markup .= $autoBreak ? "\n" : ''; - - return $markup; - } - - # ~ - - protected function li($lines) - { - $Elements = $this->linesElements($lines); - - if ( ! in_array('', $lines) - and isset($Elements[0]) and isset($Elements[0]['name']) - and $Elements[0]['name'] === 'p' - ) { - unset($Elements[0]['name']); - } - - return $Elements; - } - - # - # AST Convenience - # - - /** - * Replace occurrences $regexp with $Elements in $text. Return an array of - * elements representing the replacement. - */ - protected static function pregReplaceElements($regexp, $Elements, $text) - { - $newElements = array(); - - while (preg_match($regexp, $text, $matches, PREG_OFFSET_CAPTURE)) - { - $offset = $matches[0][1]; - $before = substr($text, 0, $offset); - $after = substr($text, $offset + strlen($matches[0][0])); - - $newElements[] = array('text' => $before); - - foreach ($Elements as $Element) - { - $newElements[] = $Element; - } - - $text = $after; - } - - $newElements[] = array('text' => $text); - - return $newElements; - } - - # - # Deprecated Methods - # - - function parse($text) - { - $markup = $this->text($text); - - return $markup; - } - - protected function sanitiseElement(array $Element) - { - static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; - static $safeUrlNameToAtt = array( - 'a' => 'href', - 'img' => 'src', - ); - - if ( ! isset($Element['name'])) - { - unset($Element['attributes']); - return $Element; - } - - if (isset($safeUrlNameToAtt[$Element['name']])) - { - $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); - } - - if ( ! empty($Element['attributes'])) - { - foreach ($Element['attributes'] as $att => $val) - { - # filter out badly parsed attribute - if ( ! preg_match($goodAttribute, $att)) - { - unset($Element['attributes'][$att]); - } - # dump onevent attribute - elseif (self::striAtStart($att, 'on')) - { - unset($Element['attributes'][$att]); - } - } - } - - return $Element; - } - - protected function filterUnsafeUrlInAttribute(array $Element, $attribute) - { - foreach ($this->safeLinksWhitelist as $scheme) - { - if (self::striAtStart($Element['attributes'][$attribute], $scheme)) - { - return $Element; - } - } - - $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); - - return $Element; - } - - # - # Static Methods - # - - protected static function escape($text, $allowQuotes = false) - { - return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); - } - - protected static function striAtStart($string, $needle) - { - $len = strlen($needle); - - if ($len > strlen($string)) - { - return false; - } - else - { - return strtolower(substr($string, 0, $len)) === strtolower($needle); - } - } - - static function instance($name = 'default') - { - if (isset(self::$instances[$name])) - { - return self::$instances[$name]; - } - - $instance = new static(); - - self::$instances[$name] = $instance; - - return $instance; - } - - private static $instances = array(); - - # - # Fields - # - - protected $DefinitionData; - - # - # Read-Only - - protected $specialCharacters = array( - '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', '~' - ); - - protected $StrongRegex = array( - '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*+[*])+?)[*]{2}(?![*])/s', - '_' => '/^__((?:\\\\_|[^_]|_[^_]*+_)+?)__(?!_)/us', - ); - - protected $EmRegex = array( - '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', - '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', - ); - - protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*+(?:\s*+=\s*+(?:[^"\'=<>`\s]+|"[^"]*+"|\'[^\']*+\'))?+'; - - protected $voidElements = array( - 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', - ); - - protected $textLevelElements = array( - 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', - 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', - 'i', 'rp', 'del', 'code', 'strike', 'marquee', - 'q', 'rt', 'ins', 'font', 'strong', - 's', 'tt', 'kbd', 'mark', - 'u', 'xm', 'sub', 'nobr', - 'sup', 'ruby', - 'var', 'span', - 'wbr', 'time', - ); + if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) { + $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; + $CurrentBlock = $this->$methodName($CurrentBlock); + } + + # ~ + + if (isset($CurrentBlock)) { + $Elements[] = $this->extractElement($CurrentBlock); + } + + # ~ + + return $Elements; + } + + protected function extractElement(array $Component) + { + if (!isset($Component['element'])) { + if (isset($Component['markup'])) { + $Component['element'] = array('rawHtml' => $Component['markup']); + } elseif (isset($Component['hidden'])) { + $Component['element'] = array(); + } + } + + return $Component['element']; + } + + protected function isBlockContinuable($Type) + { + return method_exists($this, 'block' . $Type . 'Continue'); + } + + protected function isBlockCompletable($Type) + { + return method_exists($this, 'block' . $Type . 'Complete'); + } + + # + # Code + + protected function blockCode($Line, $Block = null) + { + if (isset($Block) and $Block['type'] === 'Paragraph' and !isset($Block['interrupted'])) { + return; + } + + if ($Line['indent'] >= 4) { + $text = substr($Line['body'], 4); + + $Block = array( + 'element' => array( + 'name' => 'pre', + 'element' => array( + 'name' => 'code', + 'text' => $text, + ), + ), + ); + + return $Block; + } + } + + protected function blockCodeContinue($Line, $Block) + { + if ($Line['indent'] >= 4) { + if (isset($Block['interrupted'])) { + $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); + + unset($Block['interrupted']); + } + + $Block['element']['element']['text'] .= "\n"; + + $text = substr($Line['body'], 4); + + $Block['element']['element']['text'] .= $text; + + return $Block; + } + } + + protected function blockCodeComplete($Block) + { + return $Block; + } + + # + # Comment + + protected function blockComment($Line) + { + if ($this->markupEscaped or $this->safeMode) { + return; + } + + if (strpos($Line['text'], '<!--') === 0) { + $Block = array( + 'element' => array( + 'rawHtml' => $Line['body'], + 'autobreak' => true, + ), + ); + + if (strpos($Line['text'], '-->') !== false) { + $Block['closed'] = true; + } + + return $Block; + } + } + + protected function blockCommentContinue($Line, array $Block) + { + if (isset($Block['closed'])) { + return; + } + + $Block['element']['rawHtml'] .= "\n" . $Line['body']; + + if (strpos($Line['text'], '-->') !== false) { + $Block['closed'] = true; + } + + return $Block; + } + + # + # Fenced Code + + protected function blockFencedCode($Line) + { + $marker = $Line['text'][0]; + + $openerLength = strspn($Line['text'], $marker); + + if ($openerLength < 3) { + return; + } + + $infostring = trim(substr($Line['text'], $openerLength), "\t "); + + if (strpos($infostring, '`') !== false) { + return; + } + + $Element = array( + 'name' => 'code', + 'text' => '', + ); + + if ($infostring !== '') { + /** + * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes + * Every HTML element may have a class attribute specified. + * The attribute, if specified, must have a value that is a set + * of space-separated tokens representing the various classes + * that the element belongs to. + * [...] + * The space characters, for the purposes of this specification, + * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), + * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and + * U+000D CARRIAGE RETURN (CR). + */ + $language = substr($infostring, 0, strcspn($infostring, " \t\n\f\r")); + + $Element['attributes'] = array('class' => "language-$language"); + } + + $Block = array( + 'char' => $marker, + 'openerLength' => $openerLength, + 'element' => array( + 'name' => 'pre', + 'element' => $Element, + ), + ); + + return $Block; + } + + protected function blockFencedCodeContinue($Line, $Block) + { + if (isset($Block['complete'])) { + return; + } + + if (isset($Block['interrupted'])) { + $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); + + unset($Block['interrupted']); + } + + if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] + and chop(substr($Line['text'], $len), ' ') === '' + ) { + $Block['element']['element']['text'] = substr($Block['element']['element']['text'], 1); + + $Block['complete'] = true; + + return $Block; + } + + $Block['element']['element']['text'] .= "\n" . $Line['body']; + + return $Block; + } + + protected function blockFencedCodeComplete($Block) + { + return $Block; + } + + # + # Header + + protected function blockHeader($Line) + { + $level = strspn($Line['text'], '#'); + + if ($level > 6) { + return; + } + + $text = trim($Line['text'], '#'); + + if ($this->strictMode and isset($text[0]) and $text[0] !== ' ') { + return; + } + + $text = trim($text, ' '); + + $Block = array( + 'element' => array( + 'name' => 'h' . $level, + 'handler' => array( + 'function' => 'lineElements', + 'argument' => $text, + 'destination' => 'elements', + ) + ), + ); + + return $Block; + } + + # + # List + + protected function blockList($Line, array $CurrentBlock = null) + { + list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]{1,9}+[.\)]'); + + if (preg_match('/^(' . $pattern . '([ ]++|$))(.*+)/', $Line['text'], $matches)) { + $contentIndent = strlen($matches[2]); + + if ($contentIndent >= 5) { + $contentIndent -= 1; + $matches[1] = substr($matches[1], 0, -$contentIndent); + $matches[3] = str_repeat(' ', $contentIndent) . $matches[3]; + } elseif ($contentIndent === 0) { + $matches[1] .= ' '; + } + + $markerWithoutWhitespace = strstr($matches[1], ' ', true); + + $Block = array( + 'indent' => $Line['indent'], + 'pattern' => $pattern, + 'data' => array( + 'type' => $name, + 'marker' => $matches[1], + 'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : substr($markerWithoutWhitespace, -1)), + ), + 'element' => array( + 'name' => $name, + 'elements' => array(), + ), + ); + $Block['data']['markerTypeRegex'] = preg_quote($Block['data']['markerType'], '/'); + + if ($name === 'ol') { + $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; + + if ($listStart !== '1') { + if ( + isset($CurrentBlock) + and $CurrentBlock['type'] === 'Paragraph' + and !isset($CurrentBlock['interrupted']) + ) { + return; + } + + $Block['element']['attributes'] = array('start' => $listStart); + } + } + + $Block['li'] = array( + 'name' => 'li', + 'handler' => array( + 'function' => 'li', + 'argument' => !empty($matches[3]) ? array($matches[3]) : array(), + 'destination' => 'elements' + ) + ); + + $Block['element']['elements'] [] = &$Block['li']; + + return $Block; + } + } + + protected function blockListContinue($Line, array $Block) + { + if (isset($Block['interrupted']) and empty($Block['li']['handler']['argument'])) { + return null; + } + + $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker'])); + + if ($Line['indent'] < $requiredIndent + and ( + ( + $Block['data']['type'] === 'ol' + and preg_match('/^[0-9]++' . $Block['data']['markerTypeRegex'] . '(?:[ ]++(.*)|$)/', $Line['text'], $matches) + ) or ( + $Block['data']['type'] === 'ul' + and preg_match('/^' . $Block['data']['markerTypeRegex'] . '(?:[ ]++(.*)|$)/', $Line['text'], $matches) + ) + ) + ) { + if (isset($Block['interrupted'])) { + $Block['li']['handler']['argument'] [] = ''; + + $Block['loose'] = true; + + unset($Block['interrupted']); + } + + unset($Block['li']); + + $text = isset($matches[1]) ? $matches[1] : ''; + + $Block['indent'] = $Line['indent']; + + $Block['li'] = array( + 'name' => 'li', + 'handler' => array( + 'function' => 'li', + 'argument' => array($text), + 'destination' => 'elements' + ) + ); + + $Block['element']['elements'] [] = &$Block['li']; + + return $Block; + } elseif ($Line['indent'] < $requiredIndent and $this->blockList($Line)) { + return null; + } + + if ($Line['text'][0] === '[' and $this->blockReference($Line)) { + return $Block; + } + + if ($Line['indent'] >= $requiredIndent) { + if (isset($Block['interrupted'])) { + $Block['li']['handler']['argument'] [] = ''; + + $Block['loose'] = true; + + unset($Block['interrupted']); + } + + $text = substr($Line['body'], $requiredIndent); + + $Block['li']['handler']['argument'] [] = $text; + + return $Block; + } + + if (!isset($Block['interrupted'])) { + $text = preg_replace('/^[ ]{0,' . $requiredIndent . '}+/', '', $Line['body']); + + $Block['li']['handler']['argument'] [] = $text; + + return $Block; + } + } + + protected function blockListComplete(array $Block) + { + if (isset($Block['loose'])) { + foreach ($Block['element']['elements'] as &$li) { + if (end($li['handler']['argument']) !== '') { + $li['handler']['argument'] [] = ''; + } + } + } + + return $Block; + } + + # + # Quote + + protected function blockQuote($Line) + { + if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) { + $Block = array( + 'element' => array( + 'name' => 'blockquote', + 'handler' => array( + 'function' => 'linesElements', + 'argument' => (array)$matches[1], + 'destination' => 'elements', + ) + ), + ); + + return $Block; + } + } + + protected function blockQuoteContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) { + return; + } + + if ($Line['text'][0] === '>' and preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) { + $Block['element']['handler']['argument'] [] = $matches[1]; + + return $Block; + } + + if (!isset($Block['interrupted'])) { + $Block['element']['handler']['argument'] [] = $Line['text']; + + return $Block; + } + } + + # + # Rule + + protected function blockRule($Line) + { + $marker = $Line['text'][0]; + + if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], " $marker") === '') { + $Block = array( + 'element' => array( + 'name' => 'hr', + ), + ); + + return $Block; + } + } + + # + # Setext + + protected function blockSetextHeader($Line, array $Block = null) + { + if (!isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted'])) { + return; + } + + if ($Line['indent'] < 4 and chop(chop($Line['text'], ' '), $Line['text'][0]) === '') { + $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; + + return $Block; + } + } + + # + # Markup + + protected function blockMarkup($Line) + { + if ($this->markupEscaped or $this->safeMode) { + return; + } + + if (preg_match('/^<[\/]?+(\w*)(?:[ ]*+' . $this->regexHtmlAttribute . ')*+[ ]*+(\/)?>/', $Line['text'], $matches)) { + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) { + return; + } + + $Block = array( + 'name' => $matches[1], + 'element' => array( + 'rawHtml' => $Line['text'], + 'autobreak' => true, + ), + ); + + return $Block; + } + } + + protected function blockMarkupContinue($Line, array $Block) + { + if (isset($Block['closed']) or isset($Block['interrupted'])) { + return; + } + + $Block['element']['rawHtml'] .= "\n" . $Line['body']; + + return $Block; + } + + # + # Reference + + protected function blockReference($Line) + { + if (strpos($Line['text'], ']') !== false + and preg_match('/^\[(.+?)\]:[ ]*+<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches) + ) { + $id = strtolower($matches[1]); + + $Data = array( + 'url' => $matches[2], + 'title' => isset($matches[3]) ? $matches[3] : null, + ); + + $this->DefinitionData['Reference'][$id] = $Data; + + $Block = array( + 'element' => array(), + ); + + return $Block; + } + } + + # + # Table + + protected function blockTable($Line, array $Block = null) + { + if (!isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted'])) { + return; + } + + if ( + strpos($Block['element']['handler']['argument'], '|') === false + and strpos($Line['text'], '|') === false + and strpos($Line['text'], ':') === false + or strpos($Block['element']['handler']['argument'], "\n") !== false + ) { + return; + } + + if (chop($Line['text'], ' -:|') !== '') { + return; + } + + $alignments = array(); + + $divider = $Line['text']; + + $divider = trim($divider); + $divider = trim($divider, '|'); + + $dividerCells = explode('|', $divider); + + foreach ($dividerCells as $dividerCell) { + $dividerCell = trim($dividerCell); + + if ($dividerCell === '') { + return; + } + + $alignment = null; + + if ($dividerCell[0] === ':') { + $alignment = 'left'; + } + + if (substr($dividerCell, -1) === ':') { + $alignment = $alignment === 'left' ? 'center' : 'right'; + } + + $alignments [] = $alignment; + } + + # ~ + + $HeaderElements = array(); + + $header = $Block['element']['handler']['argument']; + + $header = trim($header); + $header = trim($header, '|'); + + $headerCells = explode('|', $header); + + if (count($headerCells) !== count($alignments)) { + return; + } + + foreach ($headerCells as $index => $headerCell) { + $headerCell = trim($headerCell); + + $HeaderElement = array( + 'name' => 'th', + 'handler' => array( + 'function' => 'lineElements', + 'argument' => $headerCell, + 'destination' => 'elements', + ) + ); + + if (isset($alignments[$index])) { + $alignment = $alignments[$index]; + + $HeaderElement['attributes'] = array( + 'style' => "text-align: $alignment;", + ); + } + + $HeaderElements [] = $HeaderElement; + } + + # ~ + + $Block = array( + 'alignments' => $alignments, + 'identified' => true, + 'element' => array( + 'name' => 'table', + 'elements' => array(), + ), + ); + + $Block['element']['elements'] [] = array( + 'name' => 'thead', + ); + + $Block['element']['elements'] [] = array( + 'name' => 'tbody', + 'elements' => array(), + ); + + $Block['element']['elements'][0]['elements'] [] = array( + 'name' => 'tr', + 'elements' => $HeaderElements, + ); + + return $Block; + } + + protected function blockTableContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) { + return; + } + + if (count($Block['alignments']) === 1 or $Line['text'][0] === '|' or strpos($Line['text'], '|')) { + $Elements = array(); + + $row = $Line['text']; + + $row = trim($row); + $row = trim($row, '|'); + + preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]++`|`)++/', $row, $matches); + + $cells = array_slice($matches[0], 0, count($Block['alignments'])); + + foreach ($cells as $index => $cell) { + $cell = trim($cell); + + $Element = array( + 'name' => 'td', + 'handler' => array( + 'function' => 'lineElements', + 'argument' => $cell, + 'destination' => 'elements', + ) + ); + + if (isset($Block['alignments'][$index])) { + $Element['attributes'] = array( + 'style' => 'text-align: ' . $Block['alignments'][$index] . ';', + ); + } + + $Elements [] = $Element; + } + + $Element = array( + 'name' => 'tr', + 'elements' => $Elements, + ); + + $Block['element']['elements'][1]['elements'] [] = $Element; + + return $Block; + } + } + + # + # ~ + # + + protected function paragraph($Line) + { + return array( + 'type' => 'Paragraph', + 'element' => array( + 'name' => 'p', + 'handler' => array( + 'function' => 'lineElements', + 'argument' => $Line['text'], + 'destination' => 'elements', + ), + ), + ); + } + + protected function paragraphContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) { + return; + } + + $Block['element']['handler']['argument'] .= "\n" . $Line['text']; + + return $Block; + } + + # + # Inline Elements + # + + protected $InlineTypes = array( + '!' => array('Image'), + '&' => array('SpecialCharacter'), + '*' => array('Emphasis'), + ':' => array('Url'), + '<' => array('UrlTag', 'EmailTag', 'Markup'), + '[' => array('Link'), + '_' => array('Emphasis'), + '`' => array('Code'), + '~' => array('Strikethrough'), + '\\' => array('EscapeSequence'), + ); + + # ~ + + protected $inlineMarkerList = '!*_&[:<`~\\'; + + # + # ~ + # + + public function line($text, $nonNestables = array()) + { + return $this->elements($this->lineElements($text, $nonNestables)); + } + + protected function lineElements($text, $nonNestables = array()) + { + # standardize line breaks + $text = str_replace(array("\r\n", "\r"), "\n", $text); + + $Elements = array(); + + $nonNestables = (empty($nonNestables) + ? array() + : array_combine($nonNestables, $nonNestables) + ); + + # $excerpt is based on the first occurrence of a marker + + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) { + $marker = $excerpt[0]; + + $markerPosition = strlen($text) - strlen($excerpt); + + $Excerpt = array('text' => $excerpt, 'context' => $text); + + foreach ($this->InlineTypes[$marker] as $inlineType) { + # check to see if the current inline type is nestable in the current context + + if (isset($nonNestables[$inlineType])) { + continue; + } + + $Inline = $this->{"inline$inlineType"}($Excerpt); + + if (!isset($Inline)) { + continue; + } + + # makes sure that the inline belongs to "our" marker + + if (isset($Inline['position']) and $Inline['position'] > $markerPosition) { + continue; + } + + # sets a default inline position + + if (!isset($Inline['position'])) { + $Inline['position'] = $markerPosition; + } + + # cause the new element to 'inherit' our non nestables + + + $Inline['element']['nonNestables'] = isset($Inline['element']['nonNestables']) + ? array_merge($Inline['element']['nonNestables'], $nonNestables) + : $nonNestables; + + # the text that comes before the inline + $unmarkedText = substr($text, 0, $Inline['position']); + + # compile the unmarked text + $InlineText = $this->inlineText($unmarkedText); + $Elements[] = $InlineText['element']; + + # compile the inline + $Elements[] = $this->extractElement($Inline); + + # remove the examined text + $text = substr($text, $Inline['position'] + $Inline['extent']); + + continue 2; + } + + # the marker does not belong to an inline + + $unmarkedText = substr($text, 0, $markerPosition + 1); + + $InlineText = $this->inlineText($unmarkedText); + $Elements[] = $InlineText['element']; + + $text = substr($text, $markerPosition + 1); + } + + $InlineText = $this->inlineText($text); + $Elements[] = $InlineText['element']; + + foreach ($Elements as &$Element) { + if (!isset($Element['autobreak'])) { + $Element['autobreak'] = false; + } + } + + return $Elements; + } + + # + # ~ + # + + protected function inlineText($text) + { + $Inline = array( + 'extent' => strlen($text), + 'element' => array(), + ); + + $Inline['element']['elements'] = self::pregReplaceElements( + $this->breaksEnabled ? '/[ ]*+\n/' : '/(?:[ ]*+\\\\|[ ]{2,}+)\n/', + array( + array('name' => 'br'), + array('text' => "\n"), + ), + $text + ); + + return $Inline; + } + + protected function inlineCode($Excerpt) + { + $marker = $Excerpt['text'][0]; + + if (preg_match('/^([' . $marker . ']++)[ ]*+(.+?)[ ]*+(?<![' . $marker . '])\1(?!' . $marker . ')/s', $Excerpt['text'], $matches)) { + $text = $matches[2]; + $text = preg_replace('/[ ]*+\n/', ' ', $text); + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'code', + 'text' => $text, + ), + ); + } + } + + protected function inlineEmailTag($Excerpt) + { + $hostnameLabel = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?'; + + $commonMarkEmail = '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]++@' + . $hostnameLabel . '(?:\.' . $hostnameLabel . ')*'; + + if (strpos($Excerpt['text'], '>') !== false + and preg_match("/^<((mailto:)?$commonMarkEmail)>/i", $Excerpt['text'], $matches) + ) { + $url = $matches[1]; + + if (!isset($matches[2])) { + $url = "mailto:$url"; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $matches[1], + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + protected function inlineEmphasis($Excerpt) + { + if (!isset($Excerpt['text'][1])) { + return; + } + + $marker = $Excerpt['text'][0]; + + if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) { + $emphasis = 'strong'; + } elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) { + $emphasis = 'em'; + } else { + return; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => $emphasis, + 'handler' => array( + 'function' => 'lineElements', + 'argument' => $matches[1], + 'destination' => 'elements', + ) + ), + ); + } + + protected function inlineEscapeSequence($Excerpt) + { + if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) { + return array( + 'element' => array('rawHtml' => $Excerpt['text'][1]), + 'extent' => 2, + ); + } + } + + protected function inlineImage($Excerpt) + { + if (!isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') { + return; + } + + $Excerpt['text'] = substr($Excerpt['text'], 1); + + $Link = $this->inlineLink($Excerpt); + + if ($Link === null) { + return; + } + + $Inline = array( + 'extent' => $Link['extent'] + 1, + 'element' => array( + 'name' => 'img', + 'attributes' => array( + 'src' => $Link['element']['attributes']['href'], + 'alt' => $Link['element']['handler']['argument'], + ), + 'autobreak' => true, + ), + ); + + $Inline['element']['attributes'] += $Link['element']['attributes']; + + unset($Inline['element']['attributes']['href']); + + return $Inline; + } + + protected function inlineLink($Excerpt) + { + $Element = array( + 'name' => 'a', + 'handler' => array( + 'function' => 'lineElements', + 'argument' => null, + 'destination' => 'elements', + ), + 'nonNestables' => array('Url', 'Link'), + 'attributes' => array( + 'href' => null, + 'title' => null, + ), + ); + + $extent = 0; + + $remainder = $Excerpt['text']; + + if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) { + $Element['handler']['argument'] = $matches[1]; + + $extent += strlen($matches[0]); + + $remainder = substr($remainder, $extent); + } else { + return; + } + + if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) { + $Element['attributes']['href'] = $matches[1]; + + if (isset($matches[2])) { + $Element['attributes']['title'] = substr($matches[2], 1, -1); + } + + $extent += strlen($matches[0]); + } else { + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) { + $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument']; + $definition = strtolower($definition); + + $extent += strlen($matches[0]); + } else { + $definition = strtolower($Element['handler']['argument']); + } + + if (!isset($this->DefinitionData['Reference'][$definition])) { + return; + } + + $Definition = $this->DefinitionData['Reference'][$definition]; + + $Element['attributes']['href'] = $Definition['url']; + $Element['attributes']['title'] = $Definition['title']; + } + + return array( + 'extent' => $extent, + 'element' => $Element, + ); + } + + protected function inlineMarkup($Excerpt) + { + if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) { + return; + } + + if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches)) { + return array( + 'element' => array('rawHtml' => $matches[0]), + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?+[^-])*-->/s', $Excerpt['text'], $matches)) { + return array( + 'element' => array('rawHtml' => $matches[0]), + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+' . $this->regexHtmlAttribute . ')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) { + return array( + 'element' => array('rawHtml' => $matches[0]), + 'extent' => strlen($matches[0]), + ); + } + } + + protected function inlineSpecialCharacter($Excerpt) + { + if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false + and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches) + ) { + return array( + 'element' => array('rawHtml' => '&' . $matches[1] . ';'), + 'extent' => strlen($matches[0]), + ); + } + + return; + } + + protected function inlineStrikethrough($Excerpt) + { + if (!isset($Excerpt['text'][1])) { + return; + } + + if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) { + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'del', + 'handler' => array( + 'function' => 'lineElements', + 'argument' => $matches[1], + 'destination' => 'elements', + ) + ), + ); + } + } + + protected function inlineUrl($Excerpt) + { + if ($this->urlsLinked !== true or !isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') { + return; + } + + if (strpos($Excerpt['context'], 'http') !== false + and preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE) + ) { + $url = $matches[0][0]; + + $Inline = array( + 'extent' => strlen($matches[0][0]), + 'position' => $matches[0][1], + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + + return $Inline; + } + } + + protected function inlineUrlTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches)) { + $url = $matches[1]; + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + # ~ + + protected function unmarkedText($text) + { + $Inline = $this->inlineText($text); + return $this->element($Inline['element']); + } + + # + # Handlers + # + + protected function handle(array $Element) + { + if (isset($Element['handler'])) { + if (!isset($Element['nonNestables'])) { + $Element['nonNestables'] = array(); + } + + if (is_string($Element['handler'])) { + $function = $Element['handler']; + $argument = $Element['text']; + unset($Element['text']); + $destination = 'rawHtml'; + } else { + $function = $Element['handler']['function']; + $argument = $Element['handler']['argument']; + $destination = $Element['handler']['destination']; + } + + $Element[$destination] = $this->{$function}($argument, $Element['nonNestables']); + + if ($destination === 'handler') { + $Element = $this->handle($Element); + } + + unset($Element['handler']); + } + + return $Element; + } + + protected function handleElementRecursive(array $Element) + { + return $this->elementApplyRecursive(array($this, 'handle'), $Element); + } + + protected function handleElementsRecursive(array $Elements) + { + return $this->elementsApplyRecursive(array($this, 'handle'), $Elements); + } + + protected function elementApplyRecursive($closure, array $Element) + { + $Element = call_user_func($closure, $Element); + + if (isset($Element['elements'])) { + $Element['elements'] = $this->elementsApplyRecursive($closure, $Element['elements']); + } elseif (isset($Element['element'])) { + $Element['element'] = $this->elementApplyRecursive($closure, $Element['element']); + } + + return $Element; + } + + protected function elementApplyRecursiveDepthFirst($closure, array $Element) + { + if (isset($Element['elements'])) { + $Element['elements'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['elements']); + } elseif (isset($Element['element'])) { + $Element['element'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['element']); + } + + $Element = call_user_func($closure, $Element); + + return $Element; + } + + protected function elementsApplyRecursive($closure, array $Elements) + { + foreach ($Elements as &$Element) { + $Element = $this->elementApplyRecursive($closure, $Element); + } + + return $Elements; + } + + protected function elementsApplyRecursiveDepthFirst($closure, array $Elements) + { + foreach ($Elements as &$Element) { + $Element = $this->elementApplyRecursiveDepthFirst($closure, $Element); + } + + return $Elements; + } + + protected function element(array $Element) + { + if ($this->safeMode) { + $Element = $this->sanitiseElement($Element); + } + + # identity map if element has no handler + $Element = $this->handle($Element); + + $hasName = isset($Element['name']); + + $markup = ''; + + if ($hasName) { + $markup .= '<' . $Element['name']; + + if (isset($Element['attributes'])) { + foreach ($Element['attributes'] as $name => $value) { + if ($value === null) { + continue; + } + + $markup .= " $name=\"" . self::escape($value) . '"'; + } + } + } + + $permitRawHtml = false; + + if (isset($Element['text'])) { + $text = $Element['text']; + } + // very strongly consider an alternative if you're writing an + // extension + elseif (isset($Element['rawHtml'])) { + $text = $Element['rawHtml']; + + $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode']; + $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode; + } + + $hasContent = isset($text) || isset($Element['element']) || isset($Element['elements']); + + if ($hasContent) { + $markup .= $hasName ? '>' : ''; + + if (isset($Element['elements'])) { + $markup .= $this->elements($Element['elements']); + } elseif (isset($Element['element'])) { + $markup .= $this->element($Element['element']); + } else { + if (!$permitRawHtml) { + $markup .= self::escape($text, true); + } else { + $markup .= $text; + } + } + + $markup .= $hasName ? '</' . $Element['name'] . '>' : ''; + } elseif ($hasName) { + $markup .= ' />'; + } + + return $markup; + } + + protected function elements(array $Elements) + { + $markup = ''; + + $autoBreak = true; + + foreach ($Elements as $Element) { + if (empty($Element)) { + continue; + } + + $autoBreakNext = (isset($Element['autobreak']) + ? $Element['autobreak'] : isset($Element['name']) + ); + // (autobreak === false) covers both sides of an element + $autoBreak = !$autoBreak ? $autoBreak : $autoBreakNext; + + $markup .= ($autoBreak ? "\n" : '') . $this->element($Element); + $autoBreak = $autoBreakNext; + } + + $markup .= $autoBreak ? "\n" : ''; + + return $markup; + } + + # ~ + + protected function li($lines) + { + $Elements = $this->linesElements($lines); + + if (!in_array('', $lines) + and isset($Elements[0]) and isset($Elements[0]['name']) + and $Elements[0]['name'] === 'p' + ) { + unset($Elements[0]['name']); + } + + return $Elements; + } + + # + # AST Convenience + # + + /** + * Replace occurrences $regexp with $Elements in $text. Return an array of + * elements representing the replacement. + */ + protected static function pregReplaceElements($regexp, $Elements, $text) + { + $newElements = array(); + + while (preg_match($regexp, $text, $matches, PREG_OFFSET_CAPTURE)) { + $offset = $matches[0][1]; + $before = substr($text, 0, $offset); + $after = substr($text, $offset + strlen($matches[0][0])); + + $newElements[] = array('text' => $before); + + foreach ($Elements as $Element) { + $newElements[] = $Element; + } + + $text = $after; + } + + $newElements[] = array('text' => $text); + + return $newElements; + } + + # + # Deprecated Methods + # + + function parse($text) + { + $markup = $this->text($text); + + return $markup; + } + + protected function sanitiseElement(array $Element) + { + static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; + static $safeUrlNameToAtt = array( + 'a' => 'href', + 'img' => 'src', + ); + + if (!isset($Element['name'])) { + unset($Element['attributes']); + return $Element; + } + + if (isset($safeUrlNameToAtt[$Element['name']])) { + $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); + } + + if (!empty($Element['attributes'])) { + foreach ($Element['attributes'] as $att => $val) { + # filter out badly parsed attribute + if (!preg_match($goodAttribute, $att)) { + unset($Element['attributes'][$att]); + } # dump onevent attribute + elseif (self::striAtStart($att, 'on')) { + unset($Element['attributes'][$att]); + } + } + } + + return $Element; + } + + protected function filterUnsafeUrlInAttribute(array $Element, $attribute) + { + foreach ($this->safeLinksWhitelist as $scheme) { + if (self::striAtStart($Element['attributes'][$attribute], $scheme)) { + return $Element; + } + } + + $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); + + return $Element; + } + + # + # Static Methods + # + + protected static function escape($text, $allowQuotes = false) + { + return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); + } + + protected static function striAtStart($string, $needle) + { + $len = strlen($needle); + + if ($len > strlen($string)) { + return false; + } else { + return strtolower(substr($string, 0, $len)) === strtolower($needle); + } + } + + static function instance($name = 'default') + { + if (isset(self::$instances[$name])) { + return self::$instances[$name]; + } + + $instance = new static(); + + self::$instances[$name] = $instance; + + return $instance; + } + + private static $instances = array(); + + # + # Fields + # + + protected $DefinitionData; + + # + # Read-Only + + protected $specialCharacters = array( + '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', '~' + ); + + protected $StrongRegex = array( + '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*+[*])+?)[*]{2}(?![*])/s', + '_' => '/^__((?:\\\\_|[^_]|_[^_]*+_)+?)__(?!_)/us', + ); + + protected $EmRegex = array( + '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', + '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', + ); + + protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*+(?:\s*+=\s*+(?:[^"\'=<>`\s]+|"[^"]*+"|\'[^\']*+\'))?+'; + + protected $voidElements = array( + 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', + ); + + protected $textLevelElements = array( + 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', + 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', + 'i', 'rp', 'del', 'code', 'strike', 'marquee', + 'q', 'rt', 'ins', 'font', 'strong', + 's', 'tt', 'kbd', 'mark', + 'u', 'xm', 'sub', 'nobr', + 'sup', 'ruby', + 'var', 'span', + 'wbr', 'time', + ); } diff --git a/modules/util/Session.class.php b/modules/util/Session.class.php @@ -1,9 +1,9 @@ <?php // PHP-Versionsunabhaengiges Array fuer die Session-Variablen ermitteln -use cms\model\User; - +namespace util; +use cms\model\User; /** @@ -18,102 +18,101 @@ use cms\model\User; * @version $Revision$ * @package openrat.service */ - class Session { - const KEY_DBID = 'dbid'; - const KEY_DB = 'database'; - const KEY_USER = 'userObject'; - const KEY_CONFIG = 'config'; - const PRAEFIX = 'ors_'; + const KEY_DBID = 'dbid'; + const KEY_DB = 'database'; + const KEY_USER = 'userObject'; + const KEY_CONFIG = 'config'; + const PRAEFIX = 'ors_'; - public static function get( $var ) + public static function get($var) { - $SESS = &$_SESSION; + $SESS = &$_SESSION; - if ( isset($SESS[self::PRAEFIX.$var]) ) - return $SESS[self::PRAEFIX.$var]; + if (isset($SESS[self::PRAEFIX . $var])) + return $SESS[self::PRAEFIX . $var]; else return ''; } - public static function set( $var,$value ) + public static function set($var, $value) { - $SESS = &$_SESSION; - $SESS[ self::PRAEFIX.$var ] = $value; + $SESS = &$_SESSION; + $SESS[self::PRAEFIX . $var] = $value; } - /** - * @return array - */ - public static function getConfig() + /** + * @return array + */ + public static function getConfig() { return Session::get(self::KEY_CONFIG); } - public static function setConfig( $var ) + public static function setConfig($var) { - Session::set(self::KEY_CONFIG,$var); + Session::set(self::KEY_CONFIG, $var); } - /** - * Liefert den Benutzer aus der Sitzung oder <code>null</code>, wenn kein Benutze angemeldet ist. - * - * @return User - */ - public static function getUser() + /** + * Liefert den Benutzer aus der Sitzung oder <code>null</code>, wenn kein Benutze angemeldet ist. + * + * @return User + */ + public static function getUser() { return Session::get(self::KEY_USER); } - public static function setUser( $var ) + public static function setUser($var) { - Session::set(self::KEY_USER,$var); + Session::set(self::KEY_USER, $var); } - /** - * @return \database\Database - */ - public static function getDatabase() + /** + * @return \database\Database + */ + public static function getDatabase() { return Session::get(self::KEY_DB); } - public static function setDatabase( $var ) + public static function setDatabase($var) { - Session::set(self::KEY_DB,$var); + Session::set(self::KEY_DB, $var); } - /** - * @return String DB-Id - */ - public static function getDatabaseId() + /** + * @return String DB-Id + */ + public static function getDatabaseId() { return Session::get(self::KEY_DBID); } - public static function setDatabaseId( $var ) + public static function setDatabaseId($var) { - Session::set(self::KEY_DBID,$var); + Session::set(self::KEY_DBID, $var); } /** * Schliesst die aktuelle Session - * + * * Diese Funktion sollte so schnell wie moeglich aufgerufen werden, da vorher * keine andere Seite (im Frameset oder parallele AJAX-Requests) geladen werden kann * Nach Aufruf dieser Methode sind keine Session-Zugriffe ueber diese Klasse mehr * moeglich. */ - public static function close() + public static function close() { session_write_close(); - } + } } ?> \ No newline at end of file diff --git a/modules/util/Text.class.php b/modules/util/Text.class.php @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +namespace util; /** * Nuetzliche Funktionen fuer das Bearbeiten von Texten/Zeichenketten * @author $Author$ @@ -26,23 +27,22 @@ class Text { /** - * + * * @param unknown $key * @param unknown $text * @return string|unknown */ - public static function accessKey( $key, $text ) + public static function accessKey($key, $text) { - $pos = strpos(strtolower($text),strtolower($key)); - - if ( $pos !== false ) - return substr($text,0,max($pos,0)).'<span class="accesskey">'.substr($text,$pos,1).'</span>'.substr($text,$pos+1); + $pos = strpos(strtolower($text), strtolower($key)); + + if ($pos !== false) + return substr($text, 0, max($pos, 0)) . '<span class="accesskey">' . substr($text, $pos, 1) . '</span>' . substr($text, $pos + 1); else return $text; } - /** * Einen Text auf eine bestimmte Laenge begrenzen. * @@ -53,14 +53,13 @@ class Text * @param Integer maximale Laenge des Textes (optional) * @param Text, der an gekuerzten Text angehangen wird (optional) */ - public static function maxLength( $text,$laenge=20,$append='...',$where=STR_PAD_RIGHT ) + public static function maxLength($text, $laenge = 20, $append = '...', $where = STR_PAD_RIGHT) { - if ( strlen($text) > $laenge ) - { - if ( $where == STR_PAD_RIGHT ) - $text = substr($text,0,$laenge).$append; - elseif ( $where == STR_PAD_BOTH ) - $text = substr($text,0,$laenge/2).$append.substr($text,strlen($text)-($laenge/2)); + if (strlen($text) > $laenge) { + if ($where == STR_PAD_RIGHT) + $text = substr($text, 0, $laenge) . $append; + elseif ($where == STR_PAD_BOTH) + $text = substr($text, 0, $laenge / 2) . $append . substr($text, strlen($text) - ($laenge / 2)); } return $text; @@ -74,14 +73,14 @@ class Text * * @return String Ausgabe */ - public static function bbCode2Wiki( $inhalt ) + public static function bbCode2Wiki($inhalt) { - $inhalt = preg_replace('/\[b\]([^\[]*)\[\/b\]/i' , '*\\1*' ,$inhalt); - $inhalt = preg_replace('/\[i\]([^\[]*)\[\/i\]/i' , '_\\1_' ,$inhalt); - $inhalt = preg_replace('/\[code\]([^\[]*)\[\/code\]/i' , '=\\1=' ,$inhalt); + $inhalt = preg_replace('/\[b\]([^\[]*)\[\/b\]/i', '*\\1*', $inhalt); + $inhalt = preg_replace('/\[i\]([^\[]*)\[\/i\]/i', '_\\1_', $inhalt); + $inhalt = preg_replace('/\[code\]([^\[]*)\[\/code\]/i', '=\\1=', $inhalt); - $inhalt = preg_replace('/\[url\]([^\[]*)\[\/url\]/i' ,'"\\1"->"\\1"' ,$inhalt); - $inhalt = preg_replace('/\[url=([^\[]*)\]([^\[]*)\[\/url\]/i' ,'"\\2"->"\\1"' ,$inhalt); + $inhalt = preg_replace('/\[url\]([^\[]*)\[\/url\]/i', '"\\1"->"\\1"', $inhalt); + $inhalt = preg_replace('/\[url=([^\[]*)\]([^\[]*)\[\/url\]/i', '"\\2"->"\\1"', $inhalt); return $inhalt; } @@ -94,11 +93,11 @@ class Text * * @return String Ausgabe */ - public static function Html2Wiki( $inhalt ) + public static function Html2Wiki($inhalt) { - $inhalt = preg_replace('/<b(.*)>(.*)<\/b>/i','*\\2*' ,$inhalt); - $inhalt = preg_replace('/<i(.*)>(.*)<\/i>/i','_\\2_' ,$inhalt); - $inhalt = preg_replace('/<a(.*)href="(.*)">(.*)<\/a>/i','"\\3"->"\\2"' ,$inhalt); + $inhalt = preg_replace('/<b(.*)>(.*)<\/b>/i', '*\\2*', $inhalt); + $inhalt = preg_replace('/<i(.*)>(.*)<\/i>/i', '_\\2_', $inhalt); + $inhalt = preg_replace('/<a(.*)href="(.*)">(.*)<\/a>/i', '"\\3"->"\\2"', $inhalt); return $inhalt; } @@ -110,306 +109,270 @@ class Text * @param String Text, in dem HTML-Tags umgewandelt werden sollen * @return String Ausgabe */ - public static function encodeHtml( $inhalt ) + public static function encodeHtml($inhalt) { //$inhalt = str_replace('&','&amp;',$inhalt); - $inhalt = str_replace('"','&quot;',$inhalt); - $inhalt = str_replace('<','&lt;' ,$inhalt); - $inhalt = str_replace('>','&gt;' ,$inhalt); + $inhalt = str_replace('"', '&quot;', $inhalt); + $inhalt = str_replace('<', '&lt;', $inhalt); + $inhalt = str_replace('>', '&gt;', $inhalt); return $inhalt; } - - + /** * Ersetzt Sonderzeichen durch HTML-�quivalente.<br> * Z.B. Ersetzt "(c)" durch "&copy;". */ - public static function replaceHtmlChars( $text ) + public static function replaceHtmlChars($text) { global $conf; - - foreach( explode(' ',$conf['editor']['html']['replace']) as $repl ) - { - list( $ersetze, $mit ) = explode(':',$repl.':'); + + foreach (explode(' ', $conf['editor']['html']['replace']) as $repl) { + list($ersetze, $mit) = explode(':', $repl . ':'); $text = str_replace($ersetze, $mit, $text); } - + return $text; } - - - + + /** * HTML-Entitaeten fuer HTML-Tags verwenden * * @param String Text, in dem HTML-Tags umgewandelt werden sollen * @return String Ausgabe */ - public static function encodeHtmlSpecialChars( $inhalt ) + public static function encodeHtmlSpecialChars($inhalt) { - return Text::replaceHtmlChars( $inhalt ); + return Text::replaceHtmlChars($inhalt); } - - + /** * Vergleicht 2 Text-Arrays und ermittelt eine Darstellung der Unterschiede * */ - public static function diff( $from_text,$to_text ) + public static function diff($from_text, $to_text) { // Zaehler pro Textarray $pos_from = -1; - $pos_to = -1; + $pos_to = -1; // Ergebnis-Arrays $from_out = array(); - $to_out = array(); + $to_out = array(); - while( true ) - { + while (true) { $pos_from++; - $pos_to ++; + $pos_to++; - if ( !isset($from_text[$pos_from]) && - !isset($to_text [$pos_to ]) ) - { + if (!isset($from_text[$pos_from]) && + !isset($to_text [$pos_to])) { // Text in ist 'neu' und '