Merge pull request #250 from shreesh-webkul/qlo-update-pear
Updated Pear and Archive tar library
This commit is contained in:
@@ -31,7 +31,7 @@ class ConfigurationTestCore
|
||||
'/classes/log/index.php',
|
||||
'/classes/cache/index.php',
|
||||
'/config/index.php',
|
||||
'/tools/tar/Archive_Tar.php',
|
||||
'/tools/tar/Tar.php',
|
||||
'/tools/pear/PEAR.php',
|
||||
'/controllers/admin/AdminLoginController.php',
|
||||
'/css/index.php',
|
||||
|
||||
@@ -930,7 +930,7 @@ class LanguageCore extends ObjectModel
|
||||
if (!file_exists($file)) {
|
||||
$errors[] = Tools::displayError('No language pack is available for your version.');
|
||||
} elseif ($install) {
|
||||
require_once(_PS_TOOL_DIR_.'tar/Archive_Tar.php');
|
||||
require_once(_PS_TOOL_DIR_.'tar/Tar.php');
|
||||
$gz = new Archive_Tar($file, true);
|
||||
$files_list = AdminTranslationsController::filterTranslationFiles(Language::getLanguagePackListContent((string)$iso, $gz));
|
||||
$files_paths = AdminTranslationsController::filesListToPaths($files_list);
|
||||
@@ -1030,7 +1030,7 @@ class LanguageCore extends ObjectModel
|
||||
|
||||
public static function updateModulesTranslations(array $modules_list)
|
||||
{
|
||||
require_once(_PS_TOOL_DIR_.'tar/Archive_Tar.php');
|
||||
require_once(_PS_TOOL_DIR_.'tar/Tar.php');
|
||||
|
||||
$languages = Language::getLanguages(false);
|
||||
foreach ($languages as $lang) {
|
||||
|
||||
@@ -403,7 +403,7 @@ class AdminModulesControllerCore extends AdminController
|
||||
}
|
||||
}
|
||||
} else {
|
||||
require_once(_PS_TOOL_DIR_.'tar/Archive_Tar.php');
|
||||
require_once _PS_TOOL_DIR_.'tar/Tar.php';
|
||||
$archive = new Archive_Tar($file);
|
||||
if ($archive->extract($tmp_folder)) {
|
||||
$zip_folders = scandir($tmp_folder);
|
||||
|
||||
@@ -481,7 +481,7 @@ class AdminTranslationsControllerCore extends AdminController
|
||||
$this->exportTabs();
|
||||
$items = array_flip(Language::getFilesList($this->lang_selected->iso_code, $this->theme_selected, false, false, false, false, true));
|
||||
$file_name = _PS_TRANSLATIONS_DIR_.'/export/'.$this->lang_selected->iso_code.'.gzip';
|
||||
require_once(_PS_TOOL_DIR_.'tar/Archive_Tar.php');
|
||||
require_once(_PS_TOOL_DIR_.'tar/Tar.php');
|
||||
$gz = new Archive_Tar($file_name, true);
|
||||
if ($gz->createModify($items, null, _PS_ROOT_DIR_)) {
|
||||
ob_start();
|
||||
@@ -718,7 +718,7 @@ class AdminTranslationsControllerCore extends AdminController
|
||||
if (!isset($_FILES['file']['tmp_name']) || !$_FILES['file']['tmp_name']) {
|
||||
$this->errors[] = Tools::displayError('No file has been selected.');
|
||||
} else {
|
||||
require_once(_PS_TOOL_DIR_.'tar/Archive_Tar.php');
|
||||
require_once(_PS_TOOL_DIR_.'tar/Tar.php');
|
||||
$gz = new Archive_Tar($_FILES['file']['tmp_name'], true);
|
||||
$filename = $_FILES['file']['name'];
|
||||
$iso_code = str_replace(array('.tar.gz', '.gzip'), '', $filename);
|
||||
@@ -859,7 +859,7 @@ class AdminTranslationsControllerCore extends AdminController
|
||||
if ($content) {
|
||||
$file = _PS_TRANSLATIONS_DIR_.$arr_import_lang[0].'.gzip';
|
||||
if ((bool)@file_put_contents($file, $content)) {
|
||||
require_once(_PS_TOOL_DIR_.'/tar/Archive_Tar.php');
|
||||
require_once(_PS_TOOL_DIR_.'/tar/Tar.php');
|
||||
$gz = new Archive_Tar($file, true);
|
||||
if (_PS_MODE_DEV_) {
|
||||
$gz->setErrorHandling(PEAR_ERROR_TRIGGER, E_USER_WARNING);
|
||||
|
||||
343
tools/pear/OS/Guess.php
Normal file
343
tools/pear/OS/Guess.php
Normal file
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
/**
|
||||
* The OS_Guess class
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* @category pear
|
||||
* @package PEAR
|
||||
* @author Stig Bakken <ssb@php.net>
|
||||
* @author Gregory Beaver <cellog@php.net>
|
||||
* @copyright 1997-2009 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since File available since PEAR 0.1
|
||||
*/
|
||||
|
||||
// {{{ uname examples
|
||||
|
||||
// php_uname() without args returns the same as 'uname -a', or a PHP-custom
|
||||
// string for Windows.
|
||||
// PHP versions prior to 4.3 return the uname of the host where PHP was built,
|
||||
// as of 4.3 it returns the uname of the host running the PHP code.
|
||||
//
|
||||
// PC RedHat Linux 7.1:
|
||||
// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
|
||||
//
|
||||
// PC Debian Potato:
|
||||
// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
|
||||
//
|
||||
// PC FreeBSD 3.3:
|
||||
// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386
|
||||
//
|
||||
// PC FreeBSD 4.3:
|
||||
// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386
|
||||
//
|
||||
// PC FreeBSD 4.5:
|
||||
// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386
|
||||
//
|
||||
// PC FreeBSD 4.5 w/uname from GNU shellutils:
|
||||
// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown
|
||||
//
|
||||
// HP 9000/712 HP-UX 10:
|
||||
// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
|
||||
//
|
||||
// HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
|
||||
// HP-UX host B.10.10 A 9000/712 unknown
|
||||
//
|
||||
// IBM RS6000/550 AIX 4.3:
|
||||
// AIX host 3 4 000003531C00
|
||||
//
|
||||
// AIX 4.3 w/uname from GNU shellutils:
|
||||
// AIX host 3 4 000003531C00 unknown
|
||||
//
|
||||
// SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
|
||||
// IRIX64 host 6.5 01091820 IP19 mips
|
||||
//
|
||||
// SGI Onyx IRIX 6.5:
|
||||
// IRIX64 host 6.5 01091820 IP19
|
||||
//
|
||||
// SparcStation 20 Solaris 8 w/uname from GNU shellutils:
|
||||
// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
|
||||
//
|
||||
// SparcStation 20 Solaris 8:
|
||||
// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
|
||||
//
|
||||
// Mac OS X (Darwin)
|
||||
// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh
|
||||
//
|
||||
// Mac OS X early versions
|
||||
//
|
||||
|
||||
// }}}
|
||||
|
||||
/* TODO:
|
||||
* - define endianness, to allow matchSignature("bigend") etc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves information about the current operating system
|
||||
*
|
||||
* This class uses php_uname() to grok information about the current OS
|
||||
*
|
||||
* @category pear
|
||||
* @package PEAR
|
||||
* @author Stig Bakken <ssb@php.net>
|
||||
* @author Gregory Beaver <cellog@php.net>
|
||||
* @copyright 1997-2009 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: @package_version@
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since Class available since Release 0.1
|
||||
*/
|
||||
class OS_Guess
|
||||
{
|
||||
var $sysname;
|
||||
var $nodename;
|
||||
var $cpu;
|
||||
var $release;
|
||||
var $extra;
|
||||
|
||||
function __construct($uname = null)
|
||||
{
|
||||
list($this->sysname,
|
||||
$this->release,
|
||||
$this->cpu,
|
||||
$this->extra,
|
||||
$this->nodename) = $this->parseSignature($uname);
|
||||
}
|
||||
|
||||
function parseSignature($uname = null)
|
||||
{
|
||||
static $sysmap = array(
|
||||
'HP-UX' => 'hpux',
|
||||
'IRIX64' => 'irix',
|
||||
);
|
||||
static $cpumap = array(
|
||||
'i586' => 'i386',
|
||||
'i686' => 'i386',
|
||||
'ppc' => 'powerpc',
|
||||
);
|
||||
if ($uname === null) {
|
||||
$uname = php_uname();
|
||||
}
|
||||
$parts = preg_split('/\s+/', trim($uname));
|
||||
$n = count($parts);
|
||||
|
||||
$release = $machine = $cpu = '';
|
||||
$sysname = $parts[0];
|
||||
$nodename = $parts[1];
|
||||
$cpu = $parts[$n-1];
|
||||
$extra = '';
|
||||
if ($cpu == 'unknown') {
|
||||
$cpu = $parts[$n - 2];
|
||||
}
|
||||
|
||||
switch ($sysname) {
|
||||
case 'AIX' :
|
||||
$release = "$parts[3].$parts[2]";
|
||||
break;
|
||||
case 'Windows' :
|
||||
switch ($parts[1]) {
|
||||
case '95/98':
|
||||
$release = '9x';
|
||||
break;
|
||||
default:
|
||||
$release = $parts[1];
|
||||
break;
|
||||
}
|
||||
$cpu = 'i386';
|
||||
break;
|
||||
case 'Linux' :
|
||||
$extra = $this->_detectGlibcVersion();
|
||||
// use only the first two digits from the kernel version
|
||||
$release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]);
|
||||
break;
|
||||
case 'Mac' :
|
||||
$sysname = 'darwin';
|
||||
$nodename = $parts[2];
|
||||
$release = $parts[3];
|
||||
if ($cpu == 'Macintosh') {
|
||||
if ($parts[$n - 2] == 'Power') {
|
||||
$cpu = 'powerpc';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'Darwin' :
|
||||
if ($cpu == 'Macintosh') {
|
||||
if ($parts[$n - 2] == 'Power') {
|
||||
$cpu = 'powerpc';
|
||||
}
|
||||
}
|
||||
$release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]);
|
||||
break;
|
||||
default:
|
||||
$release = preg_replace('/-.*/', '', $parts[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($sysmap[$sysname])) {
|
||||
$sysname = $sysmap[$sysname];
|
||||
} else {
|
||||
$sysname = strtolower($sysname);
|
||||
}
|
||||
if (isset($cpumap[$cpu])) {
|
||||
$cpu = $cpumap[$cpu];
|
||||
}
|
||||
return array($sysname, $release, $cpu, $extra, $nodename);
|
||||
}
|
||||
|
||||
function _detectGlibcVersion()
|
||||
{
|
||||
static $glibc = false;
|
||||
if ($glibc !== false) {
|
||||
return $glibc; // no need to run this multiple times
|
||||
}
|
||||
$major = $minor = 0;
|
||||
include_once "System.php";
|
||||
|
||||
if (@is_link('/lib64/libc.so.6')) {
|
||||
// Let's try reading the libc.so.6 symlink
|
||||
if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib64/libc.so.6')), $matches)) {
|
||||
list($major, $minor) = explode('.', $matches[1]);
|
||||
}
|
||||
} else if (@is_link('/lib/libc.so.6')) {
|
||||
// Let's try reading the libc.so.6 symlink
|
||||
if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib/libc.so.6')), $matches)) {
|
||||
list($major, $minor) = explode('.', $matches[1]);
|
||||
}
|
||||
}
|
||||
// Use glibc's <features.h> header file to
|
||||
// get major and minor version number:
|
||||
if (!($major && $minor) &&
|
||||
@file_exists('/usr/include/features.h') &&
|
||||
@is_readable('/usr/include/features.h')) {
|
||||
if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
|
||||
$features_file = fopen('/usr/include/features.h', 'rb');
|
||||
while (!feof($features_file)) {
|
||||
$line = fgets($features_file, 8192);
|
||||
if (!$line || (strpos($line, '#define') === false)) {
|
||||
continue;
|
||||
}
|
||||
if (strpos($line, '__GLIBC__')) {
|
||||
// major version number #define __GLIBC__ version
|
||||
$line = preg_split('/\s+/', $line);
|
||||
$glibc_major = trim($line[2]);
|
||||
if (isset($glibc_minor)) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($line, '__GLIBC_MINOR__')) {
|
||||
// got the minor version number
|
||||
// #define __GLIBC_MINOR__ version
|
||||
$line = preg_split('/\s+/', $line);
|
||||
$glibc_minor = trim($line[2]);
|
||||
if (isset($glibc_major)) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose($features_file);
|
||||
if (!isset($glibc_major) || !isset($glibc_minor)) {
|
||||
return $glibc = '';
|
||||
}
|
||||
return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
|
||||
} // no cpp
|
||||
|
||||
$tmpfile = System::mktemp("glibctest");
|
||||
$fp = fopen($tmpfile, "w");
|
||||
fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
|
||||
fclose($fp);
|
||||
$cpp = popen("/usr/bin/cpp $tmpfile", "r");
|
||||
while ($line = fgets($cpp, 1024)) {
|
||||
if ($line[0] == '#' || trim($line) == '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (list($major, $minor) = explode(' ', trim($line))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pclose($cpp);
|
||||
unlink($tmpfile);
|
||||
} // features.h
|
||||
|
||||
if (!($major && $minor)) {
|
||||
return $glibc = '';
|
||||
}
|
||||
|
||||
return $glibc = "glibc{$major}.{$minor}";
|
||||
}
|
||||
|
||||
function getSignature()
|
||||
{
|
||||
if (empty($this->extra)) {
|
||||
return "{$this->sysname}-{$this->release}-{$this->cpu}";
|
||||
}
|
||||
return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
|
||||
}
|
||||
|
||||
function getSysname()
|
||||
{
|
||||
return $this->sysname;
|
||||
}
|
||||
|
||||
function getNodename()
|
||||
{
|
||||
return $this->nodename;
|
||||
}
|
||||
|
||||
function getCpu()
|
||||
{
|
||||
return $this->cpu;
|
||||
}
|
||||
|
||||
function getRelease()
|
||||
{
|
||||
return $this->release;
|
||||
}
|
||||
|
||||
function getExtra()
|
||||
{
|
||||
return $this->extra;
|
||||
}
|
||||
|
||||
function matchSignature($match)
|
||||
{
|
||||
$fragments = is_array($match) ? $match : explode('-', $match);
|
||||
$n = count($fragments);
|
||||
$matches = 0;
|
||||
if ($n > 0) {
|
||||
$matches += $this->_matchFragment($fragments[0], $this->sysname);
|
||||
}
|
||||
if ($n > 1) {
|
||||
$matches += $this->_matchFragment($fragments[1], $this->release);
|
||||
}
|
||||
if ($n > 2) {
|
||||
$matches += $this->_matchFragment($fragments[2], $this->cpu);
|
||||
}
|
||||
if ($n > 3) {
|
||||
$matches += $this->_matchFragment($fragments[3], $this->extra);
|
||||
}
|
||||
return ($matches == $n);
|
||||
}
|
||||
|
||||
function _matchFragment($fragment, $value)
|
||||
{
|
||||
if (strcspn($fragment, '*?') < strlen($fragment)) {
|
||||
$reg = '/^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '\\z/';
|
||||
return preg_match($reg, $value);
|
||||
}
|
||||
return ($fragment == '*' || !strcasecmp($fragment, $value));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: nil
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
||||
29
tools/pear/OS/index.php
Normal file
29
tools/pear/OS/index.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* 2010-2021 Webkul.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* All right is reserved,
|
||||
* Please go through this link for complete license : https://store.webkul.com/license.html
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade this module to newer
|
||||
* versions in the future. If you wish to customize this module for your
|
||||
* needs please refer to https://store.webkul.com/customisation-guidelines/ for more information.
|
||||
*
|
||||
* @author Webkul IN <support@webkul.com>
|
||||
* @copyright 2010-2021 Webkul IN
|
||||
* @license https://store.webkul.com/license.html
|
||||
*/
|
||||
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../../../');
|
||||
exit;
|
||||
2412
tools/pear/PEAR.php
2412
tools/pear/PEAR.php
File diff suppressed because it is too large
Load Diff
14
tools/pear/PEAR/Error.php
Normal file
14
tools/pear/PEAR/Error.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Dummy file to make autoloaders work
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PEAR
|
||||
* @package PEAR
|
||||
* @author Christian Weiske <cweiske@php.net>
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
*/
|
||||
require_once __DIR__ . '/../PEAR.php';
|
||||
?>
|
||||
979
tools/pear/PEAR/ErrorStack.php
Normal file
979
tools/pear/PEAR/ErrorStack.php
Normal file
@@ -0,0 +1,979 @@
|
||||
<?php
|
||||
/**
|
||||
* Error Stack Implementation
|
||||
*
|
||||
* This is an incredibly simple implementation of a very complex error handling
|
||||
* facility. It contains the ability
|
||||
* to track multiple errors from multiple packages simultaneously. In addition,
|
||||
* it can track errors of many levels, save data along with the error, context
|
||||
* information such as the exact file, line number, class and function that
|
||||
* generated the error, and if necessary, it can raise a traditional PEAR_Error.
|
||||
* It has built-in support for PEAR::Log, to log errors as they occur
|
||||
*
|
||||
* Since version 0.2alpha, it is also possible to selectively ignore errors,
|
||||
* through the use of an error callback, see {@link pushCallback()}
|
||||
*
|
||||
* Since version 0.3alpha, it is possible to specify the exception class
|
||||
* returned from {@link push()}
|
||||
*
|
||||
* Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class. This can
|
||||
* still be done quite handily in an error callback or by manipulating the returned array
|
||||
* @category Debugging
|
||||
* @package PEAR_ErrorStack
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @copyright 2004-2008 Greg Beaver
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @link http://pear.php.net/package/PEAR_ErrorStack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Singleton storage
|
||||
*
|
||||
* Format:
|
||||
* <pre>
|
||||
* array(
|
||||
* 'package1' => PEAR_ErrorStack object,
|
||||
* 'package2' => PEAR_ErrorStack object,
|
||||
* ...
|
||||
* )
|
||||
* </pre>
|
||||
* @access private
|
||||
* @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
|
||||
*/
|
||||
$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
|
||||
|
||||
/**
|
||||
* Global error callback (default)
|
||||
*
|
||||
* This is only used if set to non-false. * is the default callback for
|
||||
* all packages, whereas specific packages may set a default callback
|
||||
* for all instances, regardless of whether they are a singleton or not.
|
||||
*
|
||||
* To exclude non-singletons, only set the local callback for the singleton
|
||||
* @see PEAR_ErrorStack::setDefaultCallback()
|
||||
* @access private
|
||||
* @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
|
||||
*/
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
|
||||
'*' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
* Global Log object (default)
|
||||
*
|
||||
* This is only used if set to non-false. Use to set a default log object for
|
||||
* all stacks, regardless of instantiation order or location
|
||||
* @see PEAR_ErrorStack::setDefaultLogger()
|
||||
* @access private
|
||||
* @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
|
||||
*/
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
|
||||
|
||||
/**
|
||||
* Global Overriding Callback
|
||||
*
|
||||
* This callback will override any error callbacks that specific loggers have set.
|
||||
* Use with EXTREME caution
|
||||
* @see PEAR_ErrorStack::staticPushCallback()
|
||||
* @access private
|
||||
* @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
|
||||
*/
|
||||
$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
|
||||
|
||||
/**#@+
|
||||
* One of four possible return values from the error Callback
|
||||
* @see PEAR_ErrorStack::_errorCallback()
|
||||
*/
|
||||
/**
|
||||
* If this is returned, then the error will be both pushed onto the stack
|
||||
* and logged.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
|
||||
/**
|
||||
* If this is returned, then the error will only be pushed onto the stack,
|
||||
* and not logged.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_PUSH', 2);
|
||||
/**
|
||||
* If this is returned, then the error will only be logged, but not pushed
|
||||
* onto the error stack.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_LOG', 3);
|
||||
/**
|
||||
* If this is returned, then the error is completely ignored.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_IGNORE', 4);
|
||||
/**
|
||||
* If this is returned, then the error is logged and die() is called.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_DIE', 5);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
|
||||
* the singleton method.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
|
||||
|
||||
/**
|
||||
* Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
|
||||
* that has no __toString() method
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
|
||||
/**
|
||||
* Error Stack Implementation
|
||||
*
|
||||
* Usage:
|
||||
* <code>
|
||||
* // global error stack
|
||||
* $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
|
||||
* // local error stack
|
||||
* $local_stack = new PEAR_ErrorStack('MyPackage');
|
||||
* </code>
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @version @package_version@
|
||||
* @package PEAR_ErrorStack
|
||||
* @category Debugging
|
||||
* @copyright 2004-2008 Greg Beaver
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @link http://pear.php.net/package/PEAR_ErrorStack
|
||||
*/
|
||||
class PEAR_ErrorStack {
|
||||
/**
|
||||
* Errors are stored in the order that they are pushed on the stack.
|
||||
* @since 0.4alpha Errors are no longer organized by error level.
|
||||
* This renders pop() nearly unusable, and levels could be more easily
|
||||
* handled in a callback anyway
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_errors = array();
|
||||
|
||||
/**
|
||||
* Storage of errors by level.
|
||||
*
|
||||
* Allows easy retrieval and deletion of only errors from a particular level
|
||||
* @since PEAR 1.4.0dev
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_errorsByLevel = array();
|
||||
|
||||
/**
|
||||
* Package name this error stack represents
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
var $_package;
|
||||
|
||||
/**
|
||||
* Determines whether a PEAR_Error is thrown upon every error addition
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
var $_compat = false;
|
||||
|
||||
/**
|
||||
* If set to a valid callback, this will be used to generate the error
|
||||
* message from the error code, otherwise the message passed in will be
|
||||
* used
|
||||
* @var false|string|array
|
||||
* @access private
|
||||
*/
|
||||
var $_msgCallback = false;
|
||||
|
||||
/**
|
||||
* If set to a valid callback, this will be used to generate the error
|
||||
* context for an error. For PHP-related errors, this will be a file
|
||||
* and line number as retrieved from debug_backtrace(), but can be
|
||||
* customized for other purposes. The error might actually be in a separate
|
||||
* configuration file, or in a database query.
|
||||
* @var false|string|array
|
||||
* @access protected
|
||||
*/
|
||||
var $_contextCallback = false;
|
||||
|
||||
/**
|
||||
* If set to a valid callback, this will be called every time an error
|
||||
* is pushed onto the stack. The return value will be used to determine
|
||||
* whether to allow an error to be pushed or logged.
|
||||
*
|
||||
* The return value must be one an PEAR_ERRORSTACK_* constant
|
||||
* @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
|
||||
* @var false|string|array
|
||||
* @access protected
|
||||
*/
|
||||
var $_errorCallback = array();
|
||||
|
||||
/**
|
||||
* PEAR::Log object for logging errors
|
||||
* @var false|Log
|
||||
* @access protected
|
||||
*/
|
||||
var $_logger = false;
|
||||
|
||||
/**
|
||||
* Error messages - designed to be overridden
|
||||
* @var array
|
||||
* @abstract
|
||||
*/
|
||||
var $_errorMsgs = array();
|
||||
|
||||
/**
|
||||
* Set up a new error stack
|
||||
*
|
||||
* @param string $package name of the package this error stack represents
|
||||
* @param callback $msgCallback callback used for error message generation
|
||||
* @param callback $contextCallback callback used for context generation,
|
||||
* defaults to {@link getFileLine()}
|
||||
* @param boolean $throwPEAR_Error
|
||||
*/
|
||||
function __construct($package, $msgCallback = false, $contextCallback = false,
|
||||
$throwPEAR_Error = false)
|
||||
{
|
||||
$this->_package = $package;
|
||||
$this->setMessageCallback($msgCallback);
|
||||
$this->setContextCallback($contextCallback);
|
||||
$this->_compat = $throwPEAR_Error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a single error stack for this package.
|
||||
*
|
||||
* Note that all parameters are ignored if the stack for package $package
|
||||
* has already been instantiated
|
||||
* @param string $package name of the package this error stack represents
|
||||
* @param callback $msgCallback callback used for error message generation
|
||||
* @param callback $contextCallback callback used for context generation,
|
||||
* defaults to {@link getFileLine()}
|
||||
* @param boolean $throwPEAR_Error
|
||||
* @param string $stackClass class to instantiate
|
||||
*
|
||||
* @return PEAR_ErrorStack
|
||||
*/
|
||||
public static function &singleton(
|
||||
$package, $msgCallback = false, $contextCallback = false,
|
||||
$throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack'
|
||||
) {
|
||||
if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
|
||||
}
|
||||
if (!class_exists($stackClass)) {
|
||||
if (function_exists('debug_backtrace')) {
|
||||
$trace = debug_backtrace();
|
||||
}
|
||||
PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
|
||||
'exception', array('stackclass' => $stackClass),
|
||||
'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
|
||||
false, $trace);
|
||||
}
|
||||
$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
|
||||
new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
|
||||
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal error handler for PEAR_ErrorStack class
|
||||
*
|
||||
* Dies if the error is an exception (and would have died anyway)
|
||||
* @access private
|
||||
*/
|
||||
function _handleError($err)
|
||||
{
|
||||
if ($err['level'] == 'exception') {
|
||||
$message = $err['message'];
|
||||
if (isset($_SERVER['REQUEST_URI'])) {
|
||||
echo '<br />';
|
||||
} else {
|
||||
echo "\n";
|
||||
}
|
||||
var_dump($err['context']);
|
||||
die($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a PEAR::Log object for all error stacks that don't have one
|
||||
* @param Log $log
|
||||
*/
|
||||
public static function setDefaultLogger(&$log)
|
||||
{
|
||||
if (is_object($log) && method_exists($log, 'log') ) {
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
|
||||
} elseif (is_callable($log)) {
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a PEAR::Log object for this error stack
|
||||
* @param Log $log
|
||||
*/
|
||||
function setLogger(&$log)
|
||||
{
|
||||
if (is_object($log) && method_exists($log, 'log') ) {
|
||||
$this->_logger = &$log;
|
||||
} elseif (is_callable($log)) {
|
||||
$this->_logger = &$log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an error code => error message mapping callback
|
||||
*
|
||||
* This method sets the callback that can be used to generate error
|
||||
* messages for any instance
|
||||
* @param array|string Callback function/method
|
||||
*/
|
||||
function setMessageCallback($msgCallback)
|
||||
{
|
||||
if (!$msgCallback) {
|
||||
$this->_msgCallback = array(&$this, 'getErrorMessage');
|
||||
} else {
|
||||
if (is_callable($msgCallback)) {
|
||||
$this->_msgCallback = $msgCallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an error code => error message mapping callback
|
||||
*
|
||||
* This method returns the current callback that can be used to generate error
|
||||
* messages
|
||||
* @return array|string|false Callback function/method or false if none
|
||||
*/
|
||||
function getMessageCallback()
|
||||
{
|
||||
return $this->_msgCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default callback to be used by all error stacks
|
||||
*
|
||||
* This method sets the callback that can be used to generate error
|
||||
* messages for a singleton
|
||||
* @param array|string Callback function/method
|
||||
* @param string Package name, or false for all packages
|
||||
*/
|
||||
public static function setDefaultCallback($callback = false, $package = false)
|
||||
{
|
||||
if (!is_callable($callback)) {
|
||||
$callback = false;
|
||||
}
|
||||
$package = $package ? $package : '*';
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback that generates context information (location of error) for an error stack
|
||||
*
|
||||
* This method sets the callback that can be used to generate context
|
||||
* information for an error. Passing in NULL will disable context generation
|
||||
* and remove the expensive call to debug_backtrace()
|
||||
* @param array|string|null Callback function/method
|
||||
*/
|
||||
function setContextCallback($contextCallback)
|
||||
{
|
||||
if ($contextCallback === null) {
|
||||
return $this->_contextCallback = false;
|
||||
}
|
||||
if (!$contextCallback) {
|
||||
$this->_contextCallback = array(&$this, 'getFileLine');
|
||||
} else {
|
||||
if (is_callable($contextCallback)) {
|
||||
$this->_contextCallback = $contextCallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an error Callback
|
||||
* If set to a valid callback, this will be called every time an error
|
||||
* is pushed onto the stack. The return value will be used to determine
|
||||
* whether to allow an error to be pushed or logged.
|
||||
*
|
||||
* The return value must be one of the ERRORSTACK_* constants.
|
||||
*
|
||||
* This functionality can be used to emulate PEAR's pushErrorHandling, and
|
||||
* the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
|
||||
* the error stack or logging
|
||||
* @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
|
||||
* @see popCallback()
|
||||
* @param string|array $cb
|
||||
*/
|
||||
function pushCallback($cb)
|
||||
{
|
||||
array_push($this->_errorCallback, $cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a callback from the error callback stack
|
||||
* @see pushCallback()
|
||||
* @return array|string|false
|
||||
*/
|
||||
function popCallback()
|
||||
{
|
||||
if (!count($this->_errorCallback)) {
|
||||
return false;
|
||||
}
|
||||
return array_pop($this->_errorCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a temporary overriding error callback for every package error stack
|
||||
*
|
||||
* Use this to temporarily disable all existing callbacks (can be used
|
||||
* to emulate the @ operator, for instance)
|
||||
* @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
|
||||
* @see staticPopCallback(), pushCallback()
|
||||
* @param string|array $cb
|
||||
*/
|
||||
public static function staticPushCallback($cb)
|
||||
{
|
||||
array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a temporary overriding error callback
|
||||
* @see staticPushCallback()
|
||||
* @return array|string|false
|
||||
*/
|
||||
public static function staticPopCallback()
|
||||
{
|
||||
$ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
|
||||
if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
|
||||
$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error to the stack
|
||||
*
|
||||
* If the message generator exists, it is called with 2 parameters.
|
||||
* - the current Error Stack object
|
||||
* - an array that is in the same format as an error. Available indices
|
||||
* are 'code', 'package', 'time', 'params', 'level', and 'context'
|
||||
*
|
||||
* Next, if the error should contain context information, this is
|
||||
* handled by the context grabbing method.
|
||||
* Finally, the error is pushed onto the proper error stack
|
||||
* @param int $code Package-specific error code
|
||||
* @param string $level Error level. This is NOT spell-checked
|
||||
* @param array $params associative array of error parameters
|
||||
* @param string $msg Error message, or a portion of it if the message
|
||||
* is to be generated
|
||||
* @param array $repackage If this error re-packages an error pushed by
|
||||
* another package, place the array returned from
|
||||
* {@link pop()} in this parameter
|
||||
* @param array $backtrace Protected parameter: use this to pass in the
|
||||
* {@link debug_backtrace()} that should be used
|
||||
* to find error context
|
||||
* @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
|
||||
* thrown. If a PEAR_Error is returned, the userinfo
|
||||
* property is set to the following array:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'code' => $code,
|
||||
* 'params' => $params,
|
||||
* 'package' => $this->_package,
|
||||
* 'level' => $level,
|
||||
* 'time' => time(),
|
||||
* 'context' => $context,
|
||||
* 'message' => $msg,
|
||||
* //['repackage' => $err] repackaged error array/Exception class
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* Normally, the previous array is returned.
|
||||
*/
|
||||
function push($code, $level = 'error', $params = array(), $msg = false,
|
||||
$repackage = false, $backtrace = false)
|
||||
{
|
||||
$context = false;
|
||||
// grab error context
|
||||
if ($this->_contextCallback) {
|
||||
if (!$backtrace) {
|
||||
$backtrace = debug_backtrace();
|
||||
}
|
||||
$context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
|
||||
}
|
||||
|
||||
// save error
|
||||
$time = explode(' ', microtime());
|
||||
$time = $time[1] + $time[0];
|
||||
$err = array(
|
||||
'code' => $code,
|
||||
'params' => $params,
|
||||
'package' => $this->_package,
|
||||
'level' => $level,
|
||||
'time' => $time,
|
||||
'context' => $context,
|
||||
'message' => $msg,
|
||||
);
|
||||
|
||||
if ($repackage) {
|
||||
$err['repackage'] = $repackage;
|
||||
}
|
||||
|
||||
// set up the error message, if necessary
|
||||
if ($this->_msgCallback) {
|
||||
$msg = call_user_func_array($this->_msgCallback,
|
||||
array(&$this, $err));
|
||||
$err['message'] = $msg;
|
||||
}
|
||||
$push = $log = true;
|
||||
$die = false;
|
||||
// try the overriding callback first
|
||||
$callback = $this->staticPopCallback();
|
||||
if ($callback) {
|
||||
$this->staticPushCallback($callback);
|
||||
}
|
||||
if (!is_callable($callback)) {
|
||||
// try the local callback next
|
||||
$callback = $this->popCallback();
|
||||
if (is_callable($callback)) {
|
||||
$this->pushCallback($callback);
|
||||
} else {
|
||||
// try the default callback
|
||||
$callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
|
||||
}
|
||||
}
|
||||
if (is_callable($callback)) {
|
||||
switch(call_user_func($callback, $err)){
|
||||
case PEAR_ERRORSTACK_IGNORE:
|
||||
return $err;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_PUSH:
|
||||
$log = false;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_LOG:
|
||||
$push = false;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_DIE:
|
||||
$die = true;
|
||||
break;
|
||||
// anything else returned has the same effect as pushandlog
|
||||
}
|
||||
}
|
||||
if ($push) {
|
||||
array_unshift($this->_errors, $err);
|
||||
if (!isset($this->_errorsByLevel[$err['level']])) {
|
||||
$this->_errorsByLevel[$err['level']] = array();
|
||||
}
|
||||
$this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
|
||||
}
|
||||
if ($log) {
|
||||
if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
|
||||
$this->_log($err);
|
||||
}
|
||||
}
|
||||
if ($die) {
|
||||
die();
|
||||
}
|
||||
if ($this->_compat && $push) {
|
||||
return $this->raiseError($msg, $code, null, null, $err);
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static version of {@link push()}
|
||||
*
|
||||
* @param string $package Package name this error belongs to
|
||||
* @param int $code Package-specific error code
|
||||
* @param string $level Error level. This is NOT spell-checked
|
||||
* @param array $params associative array of error parameters
|
||||
* @param string $msg Error message, or a portion of it if the message
|
||||
* is to be generated
|
||||
* @param array $repackage If this error re-packages an error pushed by
|
||||
* another package, place the array returned from
|
||||
* {@link pop()} in this parameter
|
||||
* @param array $backtrace Protected parameter: use this to pass in the
|
||||
* {@link debug_backtrace()} that should be used
|
||||
* to find error context
|
||||
* @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
|
||||
* thrown. see docs for {@link push()}
|
||||
*/
|
||||
public static function staticPush(
|
||||
$package, $code, $level = 'error', $params = array(),
|
||||
$msg = false, $repackage = false, $backtrace = false
|
||||
) {
|
||||
$s = &PEAR_ErrorStack::singleton($package);
|
||||
if ($s->_contextCallback) {
|
||||
if (!$backtrace) {
|
||||
if (function_exists('debug_backtrace')) {
|
||||
$backtrace = debug_backtrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an error using PEAR::Log
|
||||
* @param array $err Error array
|
||||
* @param array $levels Error level => Log constant map
|
||||
* @access protected
|
||||
*/
|
||||
function _log($err)
|
||||
{
|
||||
if ($this->_logger) {
|
||||
$logger = &$this->_logger;
|
||||
} else {
|
||||
$logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
|
||||
}
|
||||
if (is_a($logger, 'Log')) {
|
||||
$levels = array(
|
||||
'exception' => PEAR_LOG_CRIT,
|
||||
'alert' => PEAR_LOG_ALERT,
|
||||
'critical' => PEAR_LOG_CRIT,
|
||||
'error' => PEAR_LOG_ERR,
|
||||
'warning' => PEAR_LOG_WARNING,
|
||||
'notice' => PEAR_LOG_NOTICE,
|
||||
'info' => PEAR_LOG_INFO,
|
||||
'debug' => PEAR_LOG_DEBUG);
|
||||
if (isset($levels[$err['level']])) {
|
||||
$level = $levels[$err['level']];
|
||||
} else {
|
||||
$level = PEAR_LOG_INFO;
|
||||
}
|
||||
$logger->log($err['message'], $level, $err);
|
||||
} else { // support non-standard logs
|
||||
call_user_func($logger, $err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pop an error off of the error stack
|
||||
*
|
||||
* @return false|array
|
||||
* @since 0.4alpha it is no longer possible to specify a specific error
|
||||
* level to return - the last error pushed will be returned, instead
|
||||
*/
|
||||
function pop()
|
||||
{
|
||||
$err = @array_shift($this->_errors);
|
||||
if (!is_null($err)) {
|
||||
@array_pop($this->_errorsByLevel[$err['level']]);
|
||||
if (!count($this->_errorsByLevel[$err['level']])) {
|
||||
unset($this->_errorsByLevel[$err['level']]);
|
||||
}
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop an error off of the error stack, static method
|
||||
*
|
||||
* @param string package name
|
||||
* @return boolean
|
||||
* @since PEAR1.5.0a1
|
||||
*/
|
||||
static function staticPop($package)
|
||||
{
|
||||
if ($package) {
|
||||
if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
|
||||
return false;
|
||||
}
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether there are any errors on the stack
|
||||
* @param string|array Level name. Use to determine if any errors
|
||||
* of level (string), or levels (array) have been pushed
|
||||
* @return boolean
|
||||
*/
|
||||
function hasErrors($level = false)
|
||||
{
|
||||
if ($level) {
|
||||
return isset($this->_errorsByLevel[$level]);
|
||||
}
|
||||
return count($this->_errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all errors since last purge
|
||||
*
|
||||
* @param boolean set in order to empty the error stack
|
||||
* @param string level name, to return only errors of a particular severity
|
||||
* @return array
|
||||
*/
|
||||
function getErrors($purge = false, $level = false)
|
||||
{
|
||||
if (!$purge) {
|
||||
if ($level) {
|
||||
if (!isset($this->_errorsByLevel[$level])) {
|
||||
return array();
|
||||
} else {
|
||||
return $this->_errorsByLevel[$level];
|
||||
}
|
||||
} else {
|
||||
return $this->_errors;
|
||||
}
|
||||
}
|
||||
if ($level) {
|
||||
$ret = $this->_errorsByLevel[$level];
|
||||
foreach ($this->_errorsByLevel[$level] as $i => $unused) {
|
||||
// entries are references to the $_errors array
|
||||
$this->_errorsByLevel[$level][$i] = false;
|
||||
}
|
||||
// array_filter removes all entries === false
|
||||
$this->_errors = array_filter($this->_errors);
|
||||
unset($this->_errorsByLevel[$level]);
|
||||
return $ret;
|
||||
}
|
||||
$ret = $this->_errors;
|
||||
$this->_errors = array();
|
||||
$this->_errorsByLevel = array();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether there are any errors on a single error stack, or on any error stack
|
||||
*
|
||||
* The optional parameter can be used to test the existence of any errors without the need of
|
||||
* singleton instantiation
|
||||
* @param string|false Package name to check for errors
|
||||
* @param string Level name to check for a particular severity
|
||||
* @return boolean
|
||||
*/
|
||||
public static function staticHasErrors($package = false, $level = false)
|
||||
{
|
||||
if ($package) {
|
||||
if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
|
||||
return false;
|
||||
}
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
|
||||
}
|
||||
foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
|
||||
if ($obj->hasErrors($level)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all errors since last purge, organized by package
|
||||
* @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
|
||||
* @param boolean $purge Set to purge the error stack of existing errors
|
||||
* @param string $level Set to a level name in order to retrieve only errors of a particular level
|
||||
* @param boolean $merge Set to return a flat array, not organized by package
|
||||
* @param array $sortfunc Function used to sort a merged array - default
|
||||
* sorts by time, and should be good for most cases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function staticGetErrors(
|
||||
$purge = false, $level = false, $merge = false,
|
||||
$sortfunc = array('PEAR_ErrorStack', '_sortErrors')
|
||||
) {
|
||||
$ret = array();
|
||||
if (!is_callable($sortfunc)) {
|
||||
$sortfunc = array('PEAR_ErrorStack', '_sortErrors');
|
||||
}
|
||||
foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
|
||||
$test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
|
||||
if ($test) {
|
||||
if ($merge) {
|
||||
$ret = array_merge($ret, $test);
|
||||
} else {
|
||||
$ret[$package] = $test;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($merge) {
|
||||
usort($ret, $sortfunc);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error sorting function, sorts by time
|
||||
* @access private
|
||||
*/
|
||||
public static function _sortErrors($a, $b)
|
||||
{
|
||||
if ($a['time'] == $b['time']) {
|
||||
return 0;
|
||||
}
|
||||
if ($a['time'] < $b['time']) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard file/line number/function/class context callback
|
||||
*
|
||||
* This function uses a backtrace generated from {@link debug_backtrace()}
|
||||
* and so will not work at all in PHP < 4.3.0. The frame should
|
||||
* reference the frame that contains the source of the error.
|
||||
* @return array|false either array('file' => file, 'line' => line,
|
||||
* 'function' => function name, 'class' => class name) or
|
||||
* if this doesn't work, then false
|
||||
* @param unused
|
||||
* @param integer backtrace frame.
|
||||
* @param array Results of debug_backtrace()
|
||||
*/
|
||||
public static function getFileLine($code, $params, $backtrace = null)
|
||||
{
|
||||
if ($backtrace === null) {
|
||||
return false;
|
||||
}
|
||||
$frame = 0;
|
||||
$functionframe = 1;
|
||||
if (!isset($backtrace[1])) {
|
||||
$functionframe = 0;
|
||||
} else {
|
||||
while (isset($backtrace[$functionframe]['function']) &&
|
||||
$backtrace[$functionframe]['function'] == 'eval' &&
|
||||
isset($backtrace[$functionframe + 1])) {
|
||||
$functionframe++;
|
||||
}
|
||||
}
|
||||
if (isset($backtrace[$frame])) {
|
||||
if (!isset($backtrace[$frame]['file'])) {
|
||||
$frame++;
|
||||
}
|
||||
$funcbacktrace = $backtrace[$functionframe];
|
||||
$filebacktrace = $backtrace[$frame];
|
||||
$ret = array('file' => $filebacktrace['file'],
|
||||
'line' => $filebacktrace['line']);
|
||||
// rearrange for eval'd code or create function errors
|
||||
if (strpos($filebacktrace['file'], '(') &&
|
||||
preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
|
||||
$matches)) {
|
||||
$ret['file'] = $matches[1];
|
||||
$ret['line'] = $matches[2] + 0;
|
||||
}
|
||||
if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
|
||||
if ($funcbacktrace['function'] != 'eval') {
|
||||
if ($funcbacktrace['function'] == '__lambda_func') {
|
||||
$ret['function'] = 'create_function() code';
|
||||
} else {
|
||||
$ret['function'] = $funcbacktrace['function'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
|
||||
$ret['class'] = $funcbacktrace['class'];
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard error message generation callback
|
||||
*
|
||||
* This method may also be called by a custom error message generator
|
||||
* to fill in template values from the params array, simply
|
||||
* set the third parameter to the error message template string to use
|
||||
*
|
||||
* The special variable %__msg% is reserved: use it only to specify
|
||||
* where a message passed in by the user should be placed in the template,
|
||||
* like so:
|
||||
*
|
||||
* Error message: %msg% - internal error
|
||||
*
|
||||
* If the message passed like so:
|
||||
*
|
||||
* <code>
|
||||
* $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
|
||||
* </code>
|
||||
*
|
||||
* The returned error message will be "Error message: server error 500 -
|
||||
* internal error"
|
||||
* @param PEAR_ErrorStack
|
||||
* @param array
|
||||
* @param string|false Pre-generated error message template
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getErrorMessage(&$stack, $err, $template = false)
|
||||
{
|
||||
if ($template) {
|
||||
$mainmsg = $template;
|
||||
} else {
|
||||
$mainmsg = $stack->getErrorMessageTemplate($err['code']);
|
||||
}
|
||||
$mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
|
||||
if (is_array($err['params']) && count($err['params'])) {
|
||||
foreach ($err['params'] as $name => $val) {
|
||||
if (is_array($val)) {
|
||||
// @ is needed in case $val is a multi-dimensional array
|
||||
$val = @implode(', ', $val);
|
||||
}
|
||||
if (is_object($val)) {
|
||||
if (method_exists($val, '__toString')) {
|
||||
$val = $val->__toString();
|
||||
} else {
|
||||
PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
|
||||
'warning', array('obj' => get_class($val)),
|
||||
'object %obj% passed into getErrorMessage, but has no __toString() method');
|
||||
$val = 'Object';
|
||||
}
|
||||
}
|
||||
$mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
|
||||
}
|
||||
}
|
||||
return $mainmsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Error Message Template generator from code
|
||||
* @return string
|
||||
*/
|
||||
function getErrorMessageTemplate($code)
|
||||
{
|
||||
if (!isset($this->_errorMsgs[$code])) {
|
||||
return '%__msg%';
|
||||
}
|
||||
return $this->_errorMsgs[$code];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Error Message Template array
|
||||
*
|
||||
* The array format must be:
|
||||
* <pre>
|
||||
* array(error code => 'message template',...)
|
||||
* </pre>
|
||||
*
|
||||
* Error message parameters passed into {@link push()} will be used as input
|
||||
* for the error message. If the template is 'message %foo% was %bar%', and the
|
||||
* parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
|
||||
* be 'message one was six'
|
||||
* @return string
|
||||
*/
|
||||
function setErrorMessageTemplate($template)
|
||||
{
|
||||
$this->_errorMsgs = $template;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* emulate PEAR::raiseError()
|
||||
*
|
||||
* @return PEAR_Error
|
||||
*/
|
||||
function raiseError()
|
||||
{
|
||||
require_once 'PEAR.php';
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(array('PEAR', 'raiseError'), $args);
|
||||
}
|
||||
}
|
||||
$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
|
||||
$stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
|
||||
?>
|
||||
29
tools/pear/PEAR/index.php
Normal file
29
tools/pear/PEAR/index.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* 2010-2021 Webkul.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* All right is reserved,
|
||||
* Please go through this link for complete license : https://store.webkul.com/license.html
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade this module to newer
|
||||
* versions in the future. If you wish to customize this module for your
|
||||
* needs please refer to https://store.webkul.com/customisation-guidelines/ for more information.
|
||||
*
|
||||
* @author Webkul IN <support@webkul.com>
|
||||
* @copyright 2010-2021 Webkul IN
|
||||
* @license https://store.webkul.com/license.html
|
||||
*/
|
||||
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../../../');
|
||||
exit;
|
||||
628
tools/pear/System.php
Normal file
628
tools/pear/System.php
Normal file
@@ -0,0 +1,628 @@
|
||||
<?php
|
||||
/**
|
||||
* File/Directory manipulation
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* @category pear
|
||||
* @package System
|
||||
* @author Tomas V.V.Cox <cox@idecnet.com>
|
||||
* @copyright 1997-2009 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since File available since Release 0.1
|
||||
*/
|
||||
|
||||
/**
|
||||
* base class
|
||||
*/
|
||||
require_once 'PEAR.php';
|
||||
require_once 'Console/Getopt.php';
|
||||
|
||||
$GLOBALS['_System_temp_files'] = array();
|
||||
|
||||
/**
|
||||
* System offers cross platform compatible system functions
|
||||
*
|
||||
* Static functions for different operations. Should work under
|
||||
* Unix and Windows. The names and usage has been taken from its respectively
|
||||
* GNU commands. The functions will return (bool) false on error and will
|
||||
* trigger the error with the PHP trigger_error() function (you can silence
|
||||
* the error by prefixing a '@' sign after the function call, but this
|
||||
* is not recommended practice. Instead use an error handler with
|
||||
* {@link set_error_handler()}).
|
||||
*
|
||||
* Documentation on this class you can find in:
|
||||
* http://pear.php.net/manual/
|
||||
*
|
||||
* Example usage:
|
||||
* if (!@System::rm('-r file1 dir1')) {
|
||||
* print "could not delete file1 or dir1";
|
||||
* }
|
||||
*
|
||||
* In case you need to to pass file names with spaces,
|
||||
* pass the params as an array:
|
||||
*
|
||||
* System::rm(array('-r', $file1, $dir1));
|
||||
*
|
||||
* @category pear
|
||||
* @package System
|
||||
* @author Tomas V.V. Cox <cox@idecnet.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: @package_version@
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since Class available since Release 0.1
|
||||
* @static
|
||||
*/
|
||||
class System
|
||||
{
|
||||
/**
|
||||
* returns the commandline arguments of a function
|
||||
*
|
||||
* @param string $argv the commandline
|
||||
* @param string $short_options the allowed option short-tags
|
||||
* @param string $long_options the allowed option long-tags
|
||||
* @return array the given options and there values
|
||||
*/
|
||||
public static function _parseArgs($argv, $short_options, $long_options = null)
|
||||
{
|
||||
if (!is_array($argv) && $argv !== null) {
|
||||
/*
|
||||
// Quote all items that are a short option
|
||||
$av = preg_split('/(\A| )--?[a-z0-9]+[ =]?((?<!\\\\)((,\s*)|((?<!,)\s+))?)/i', $argv, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
|
||||
$offset = 0;
|
||||
foreach ($av as $a) {
|
||||
$b = trim($a[0]);
|
||||
if ($b[0] == '"' || $b[0] == "'") {
|
||||
continue;
|
||||
}
|
||||
|
||||
$escape = escapeshellarg($b);
|
||||
$pos = $a[1] + $offset;
|
||||
$argv = substr_replace($argv, $escape, $pos, strlen($b));
|
||||
$offset += 2;
|
||||
}
|
||||
*/
|
||||
|
||||
// Find all items, quoted or otherwise
|
||||
preg_match_all("/(?:[\"'])(.*?)(?:['\"])|([^\s]+)/", $argv, $av);
|
||||
$argv = $av[1];
|
||||
foreach ($av[2] as $k => $a) {
|
||||
if (empty($a)) {
|
||||
continue;
|
||||
}
|
||||
$argv[$k] = trim($a) ;
|
||||
}
|
||||
}
|
||||
|
||||
return Console_Getopt::getopt2($argv, $short_options, $long_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output errors with PHP trigger_error(). You can silence the errors
|
||||
* with prefixing a "@" sign to the function call: @System::mkdir(..);
|
||||
*
|
||||
* @param mixed $error a PEAR error or a string with the error message
|
||||
* @return bool false
|
||||
*/
|
||||
protected static function raiseError($error)
|
||||
{
|
||||
if (PEAR::isError($error)) {
|
||||
$error = $error->getMessage();
|
||||
}
|
||||
trigger_error($error, E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nested array representing the structure of a directory
|
||||
*
|
||||
* System::_dirToStruct('dir1', 0) =>
|
||||
* Array
|
||||
* (
|
||||
* [dirs] => Array
|
||||
* (
|
||||
* [0] => dir1
|
||||
* )
|
||||
*
|
||||
* [files] => Array
|
||||
* (
|
||||
* [0] => dir1/file2
|
||||
* [1] => dir1/file3
|
||||
* )
|
||||
* )
|
||||
* @param string $sPath Name of the directory
|
||||
* @param integer $maxinst max. deep of the lookup
|
||||
* @param integer $aktinst starting deep of the lookup
|
||||
* @param bool $silent if true, do not emit errors.
|
||||
* @return array the structure of the dir
|
||||
*/
|
||||
protected static function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
|
||||
{
|
||||
$struct = array('dirs' => array(), 'files' => array());
|
||||
if (($dir = @opendir($sPath)) === false) {
|
||||
if (!$silent) {
|
||||
System::raiseError("Could not open dir $sPath");
|
||||
}
|
||||
return $struct; // XXX could not open error
|
||||
}
|
||||
|
||||
$struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
|
||||
$list = array();
|
||||
while (false !== ($file = readdir($dir))) {
|
||||
if ($file != '.' && $file != '..') {
|
||||
$list[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
closedir($dir);
|
||||
natsort($list);
|
||||
if ($aktinst < $maxinst || $maxinst == 0) {
|
||||
foreach ($list as $val) {
|
||||
$path = $sPath . DIRECTORY_SEPARATOR . $val;
|
||||
if (is_dir($path) && !is_link($path)) {
|
||||
$tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent);
|
||||
$struct = array_merge_recursive($struct, $tmp);
|
||||
} else {
|
||||
$struct['files'][] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nested array representing the structure of a directory and files
|
||||
*
|
||||
* @param array $files Array listing files and dirs
|
||||
* @return array
|
||||
* @static
|
||||
* @see System::_dirToStruct()
|
||||
*/
|
||||
protected static function _multipleToStruct($files)
|
||||
{
|
||||
$struct = array('dirs' => array(), 'files' => array());
|
||||
settype($files, 'array');
|
||||
foreach ($files as $file) {
|
||||
if (is_dir($file) && !is_link($file)) {
|
||||
$tmp = System::_dirToStruct($file, 0);
|
||||
$struct = array_merge_recursive($tmp, $struct);
|
||||
} else {
|
||||
if (!in_array($file, $struct['files'])) {
|
||||
$struct['files'][] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rm command for removing files.
|
||||
* Supports multiple files and dirs and also recursive deletes
|
||||
*
|
||||
* @param string $args the arguments for rm
|
||||
* @return mixed PEAR_Error or true for success
|
||||
* @static
|
||||
* @access public
|
||||
*/
|
||||
public static function rm($args)
|
||||
{
|
||||
$opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-)
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'r') {
|
||||
$do_recursive = true;
|
||||
}
|
||||
}
|
||||
$ret = true;
|
||||
if (isset($do_recursive)) {
|
||||
$struct = System::_multipleToStruct($opts[1]);
|
||||
foreach ($struct['files'] as $file) {
|
||||
if (!@unlink($file)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
rsort($struct['dirs']);
|
||||
foreach ($struct['dirs'] as $dir) {
|
||||
if (!@rmdir($dir)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($opts[1] as $file) {
|
||||
$delete = (is_dir($file)) ? 'rmdir' : 'unlink';
|
||||
if (!@$delete($file)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make directories.
|
||||
*
|
||||
* The -p option will create parent directories
|
||||
* @param string $args the name of the director(y|ies) to create
|
||||
* @return bool True for success
|
||||
*/
|
||||
public static function mkDir($args)
|
||||
{
|
||||
$opts = System::_parseArgs($args, 'pm:');
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
|
||||
$mode = 0777; // default mode
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'p') {
|
||||
$create_parents = true;
|
||||
} elseif ($opt[0] == 'm') {
|
||||
// if the mode is clearly an octal number (starts with 0)
|
||||
// convert it to decimal
|
||||
if (strlen($opt[1]) && $opt[1][0] == '0') {
|
||||
$opt[1] = octdec($opt[1]);
|
||||
} else {
|
||||
// convert to int
|
||||
$opt[1] += 0;
|
||||
}
|
||||
$mode = $opt[1];
|
||||
}
|
||||
}
|
||||
|
||||
$ret = true;
|
||||
if (isset($create_parents)) {
|
||||
foreach ($opts[1] as $dir) {
|
||||
$dirstack = array();
|
||||
while ((!file_exists($dir) || !is_dir($dir)) &&
|
||||
$dir != DIRECTORY_SEPARATOR) {
|
||||
array_unshift($dirstack, $dir);
|
||||
$dir = dirname($dir);
|
||||
}
|
||||
|
||||
while ($newdir = array_shift($dirstack)) {
|
||||
if (!is_writeable(dirname($newdir))) {
|
||||
$ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mkdir($newdir, $mode)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach($opts[1] as $dir) {
|
||||
if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate files
|
||||
*
|
||||
* Usage:
|
||||
* 1) $var = System::cat('sample.txt test.txt');
|
||||
* 2) System::cat('sample.txt test.txt > final.txt');
|
||||
* 3) System::cat('sample.txt test.txt >> final.txt');
|
||||
*
|
||||
* Note: as the class use fopen, urls should work also
|
||||
*
|
||||
* @param string $args the arguments
|
||||
* @return boolean true on success
|
||||
*/
|
||||
public static function &cat($args)
|
||||
{
|
||||
$ret = null;
|
||||
$files = array();
|
||||
if (!is_array($args)) {
|
||||
$args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
$count_args = count($args);
|
||||
for ($i = 0; $i < $count_args; $i++) {
|
||||
if ($args[$i] == '>') {
|
||||
$mode = 'wb';
|
||||
$outputfile = $args[$i+1];
|
||||
break;
|
||||
} elseif ($args[$i] == '>>') {
|
||||
$mode = 'ab+';
|
||||
$outputfile = $args[$i+1];
|
||||
break;
|
||||
} else {
|
||||
$files[] = $args[$i];
|
||||
}
|
||||
}
|
||||
$outputfd = false;
|
||||
if (isset($mode)) {
|
||||
if (!$outputfd = fopen($outputfile, $mode)) {
|
||||
$err = System::raiseError("Could not open $outputfile");
|
||||
return $err;
|
||||
}
|
||||
$ret = true;
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
if (!$fd = fopen($file, 'r')) {
|
||||
System::raiseError("Could not open $file");
|
||||
continue;
|
||||
}
|
||||
while ($cont = fread($fd, 2048)) {
|
||||
if (is_resource($outputfd)) {
|
||||
fwrite($outputfd, $cont);
|
||||
} else {
|
||||
$ret .= $cont;
|
||||
}
|
||||
}
|
||||
fclose($fd);
|
||||
}
|
||||
if (is_resource($outputfd)) {
|
||||
fclose($outputfd);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates temporary files or directories. This function will remove
|
||||
* the created files when the scripts finish its execution.
|
||||
*
|
||||
* Usage:
|
||||
* 1) $tempfile = System::mktemp("prefix");
|
||||
* 2) $tempdir = System::mktemp("-d prefix");
|
||||
* 3) $tempfile = System::mktemp();
|
||||
* 4) $tempfile = System::mktemp("-t /var/tmp prefix");
|
||||
*
|
||||
* prefix -> The string that will be prepended to the temp name
|
||||
* (defaults to "tmp").
|
||||
* -d -> A temporary dir will be created instead of a file.
|
||||
* -t -> The target dir where the temporary (file|dir) will be created. If
|
||||
* this param is missing by default the env vars TMP on Windows or
|
||||
* TMPDIR in Unix will be used. If these vars are also missing
|
||||
* c:\windows\temp or /tmp will be used.
|
||||
*
|
||||
* @param string $args The arguments
|
||||
* @return mixed the full path of the created (file|dir) or false
|
||||
* @see System::tmpdir()
|
||||
*/
|
||||
public static function mktemp($args = null)
|
||||
{
|
||||
static $first_time = true;
|
||||
$opts = System::_parseArgs($args, 't:d');
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'd') {
|
||||
$tmp_is_dir = true;
|
||||
} elseif ($opt[0] == 't') {
|
||||
$tmpdir = $opt[1];
|
||||
}
|
||||
}
|
||||
|
||||
$prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
|
||||
if (!isset($tmpdir)) {
|
||||
$tmpdir = System::tmpdir();
|
||||
}
|
||||
|
||||
if (!System::mkDir(array('-p', $tmpdir))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tmp = tempnam($tmpdir, $prefix);
|
||||
if (isset($tmp_is_dir)) {
|
||||
unlink($tmp); // be careful possible race condition here
|
||||
if (!mkdir($tmp, 0700)) {
|
||||
return System::raiseError("Unable to create temporary directory $tmpdir");
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['_System_temp_files'][] = $tmp;
|
||||
if (isset($tmp_is_dir)) {
|
||||
//$GLOBALS['_System_temp_files'][] = dirname($tmp);
|
||||
}
|
||||
|
||||
if ($first_time) {
|
||||
PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
|
||||
$first_time = false;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove temporary files created my mkTemp. This function is executed
|
||||
* at script shutdown time
|
||||
*/
|
||||
public static function _removeTmpFiles()
|
||||
{
|
||||
if (count($GLOBALS['_System_temp_files'])) {
|
||||
$delete = $GLOBALS['_System_temp_files'];
|
||||
array_unshift($delete, '-r');
|
||||
System::rm($delete);
|
||||
$GLOBALS['_System_temp_files'] = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the temporal directory set in the system
|
||||
* by looking in its environments variables.
|
||||
* Note: php.ini-recommended removes the "E" from the variables_order setting,
|
||||
* making unavaible the $_ENV array, that s why we do tests with _ENV
|
||||
*
|
||||
* @return string The temporary directory on the system
|
||||
*/
|
||||
public static function tmpdir()
|
||||
{
|
||||
if (OS_WINDOWS) {
|
||||
if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
|
||||
return $var;
|
||||
}
|
||||
return getenv('SystemRoot') . '\temp';
|
||||
}
|
||||
if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
|
||||
return $var;
|
||||
}
|
||||
return realpath(function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : '/tmp');
|
||||
}
|
||||
|
||||
/**
|
||||
* The "which" command (show the full path of a command)
|
||||
*
|
||||
* @param string $program The command to search for
|
||||
* @param mixed $fallback Value to return if $program is not found
|
||||
*
|
||||
* @return mixed A string with the full path or false if not found
|
||||
* @author Stig Bakken <ssb@php.net>
|
||||
*/
|
||||
public static function which($program, $fallback = false)
|
||||
{
|
||||
// enforce API
|
||||
if (!is_string($program) || '' == $program) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
// full path given
|
||||
if (basename($program) != $program) {
|
||||
$path_elements[] = dirname($program);
|
||||
$program = basename($program);
|
||||
} else {
|
||||
$path = getenv('PATH');
|
||||
if (!$path) {
|
||||
$path = getenv('Path'); // some OSes are just stupid enough to do this
|
||||
}
|
||||
|
||||
$path_elements = explode(PATH_SEPARATOR, $path);
|
||||
}
|
||||
|
||||
if (OS_WINDOWS) {
|
||||
$exe_suffixes = getenv('PATHEXT')
|
||||
? explode(PATH_SEPARATOR, getenv('PATHEXT'))
|
||||
: array('.exe','.bat','.cmd','.com');
|
||||
// allow passing a command.exe param
|
||||
if (strpos($program, '.') !== false) {
|
||||
array_unshift($exe_suffixes, '');
|
||||
}
|
||||
} else {
|
||||
$exe_suffixes = array('');
|
||||
}
|
||||
|
||||
foreach ($exe_suffixes as $suff) {
|
||||
foreach ($path_elements as $dir) {
|
||||
$file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
|
||||
// It's possible to run a .bat on Windows that is_executable
|
||||
// would return false for. The is_executable check is meaningless...
|
||||
if (OS_WINDOWS) {
|
||||
return $file;
|
||||
} else {
|
||||
if (is_executable($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "find" command
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* System::find($dir);
|
||||
* System::find("$dir -type d");
|
||||
* System::find("$dir -type f");
|
||||
* System::find("$dir -name *.php");
|
||||
* System::find("$dir -name *.php -name *.htm*");
|
||||
* System::find("$dir -maxdepth 1");
|
||||
*
|
||||
* Params implemented:
|
||||
* $dir -> Start the search at this directory
|
||||
* -type d -> return only directories
|
||||
* -type f -> return only files
|
||||
* -maxdepth <n> -> max depth of recursion
|
||||
* -name <pattern> -> search pattern (bash style). Multiple -name param allowed
|
||||
*
|
||||
* @param mixed Either array or string with the command line
|
||||
* @return array Array of found files
|
||||
*/
|
||||
public static function find($args)
|
||||
{
|
||||
if (!is_array($args)) {
|
||||
$args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
$dir = realpath(array_shift($args));
|
||||
if (!$dir) {
|
||||
return array();
|
||||
}
|
||||
$patterns = array();
|
||||
$depth = 0;
|
||||
$do_files = $do_dirs = true;
|
||||
$args_count = count($args);
|
||||
for ($i = 0; $i < $args_count; $i++) {
|
||||
switch ($args[$i]) {
|
||||
case '-type':
|
||||
if (in_array($args[$i+1], array('d', 'f'))) {
|
||||
if ($args[$i+1] == 'd') {
|
||||
$do_files = false;
|
||||
} else {
|
||||
$do_dirs = false;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
break;
|
||||
case '-name':
|
||||
$name = preg_quote($args[$i+1], '#');
|
||||
// our magic characters ? and * have just been escaped,
|
||||
// so now we change the escaped versions to PCRE operators
|
||||
$name = strtr($name, array('\?' => '.', '\*' => '.*'));
|
||||
$patterns[] = '('.$name.')';
|
||||
$i++;
|
||||
break;
|
||||
case '-maxdepth':
|
||||
$depth = $args[$i+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$path = System::_dirToStruct($dir, $depth, 0, true);
|
||||
if ($do_files && $do_dirs) {
|
||||
$files = array_merge($path['files'], $path['dirs']);
|
||||
} elseif ($do_dirs) {
|
||||
$files = $path['dirs'];
|
||||
} else {
|
||||
$files = $path['files'];
|
||||
}
|
||||
if (count($patterns)) {
|
||||
$dsq = preg_quote(DIRECTORY_SEPARATOR, '#');
|
||||
$pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#';
|
||||
$ret = array();
|
||||
$files_count = count($files);
|
||||
for ($i = 0; $i < $files_count; $i++) {
|
||||
// only search in the part of the file below the current directory
|
||||
$filepart = basename($files[$i]);
|
||||
if (preg_match($pattern, $filepart)) {
|
||||
$ret[] = $files[$i];
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
@@ -1,165 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -1,351 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Key gateway class for XML_Feed_Parser package
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
|
||||
* @version CVS: $Id: Parser.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* XML_Feed_Parser_Type is an abstract class required by all of our
|
||||
* feed types. It makes sense to load it here to keep the other files
|
||||
* clean.
|
||||
*/
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/Type.php');
|
||||
|
||||
/**
|
||||
* We will throw exceptions when errors occur.
|
||||
*/
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/Exception.php');
|
||||
|
||||
/**
|
||||
* This is the core of the XML_Feed_Parser package. It identifies feed types
|
||||
* and abstracts access to them. It is an iterator, allowing for easy access
|
||||
* to the entire feed.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser implements Iterator
|
||||
{
|
||||
/**
|
||||
* This is where we hold the feed object
|
||||
* @var Object
|
||||
*/
|
||||
private $feed;
|
||||
|
||||
/**
|
||||
* To allow for extensions, we make a public reference to the feed model
|
||||
* @var DOMDocument
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* A map between entry ID and offset
|
||||
* @var array
|
||||
*/
|
||||
protected $idMappings = array();
|
||||
|
||||
/**
|
||||
* A storage space for Namespace URIs.
|
||||
* @var array
|
||||
*/
|
||||
private $feedNamespaces = array(
|
||||
'rss2' => array(
|
||||
'http://backend.userland.com/rss',
|
||||
'http://backend.userland.com/rss2',
|
||||
'http://blogs.law.harvard.edu/tech/rss'));
|
||||
/**
|
||||
* Detects feed types and instantiate appropriate objects.
|
||||
*
|
||||
* Our constructor takes care of detecting feed types and instantiating
|
||||
* appropriate classes. For now we're going to treat Atom 0.3 as Atom 1.0
|
||||
* but raise a warning. I do not intend to introduce full support for
|
||||
* Atom 0.3 as it has been deprecated, but others are welcome to.
|
||||
*
|
||||
* @param string $feed XML serialization of the feed
|
||||
* @param bool $strict Whether or not to validate the feed
|
||||
* @param bool $suppressWarnings Trigger errors for deprecated feed types?
|
||||
* @param bool $tidy Whether or not to try and use the tidy library on input
|
||||
*/
|
||||
function __construct($feed, $strict = false, $suppressWarnings = false, $tidy = false)
|
||||
{
|
||||
$this->model = new DOMDocument;
|
||||
if (! @$this->model->loadXML($feed)) { /* PrestaShop - no error display */
|
||||
if (extension_loaded('tidy') && $tidy) {
|
||||
$tidy = new tidy;
|
||||
$tidy->parseString($feed,
|
||||
array('input-xml' => true, 'output-xml' => true));
|
||||
$tidy->cleanRepair();
|
||||
if (! @$this->model->loadXML((string) $tidy)) { /* PrestaShop - no error display */
|
||||
throw new XML_Feed_Parser_Exception('Invalid input: this is not ' .
|
||||
'valid XML');
|
||||
}
|
||||
} else {
|
||||
throw new XML_Feed_Parser_Exception('Invalid input: this is not valid XML');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* detect feed type */
|
||||
$doc_element = $this->model->documentElement;
|
||||
$error = false;
|
||||
|
||||
switch (true) {
|
||||
case ($doc_element->namespaceURI == 'http://www.w3.org/2005/Atom'):
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/Atom.php');
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/AtomElement.php');
|
||||
$class = 'XML_Feed_Parser_Atom';
|
||||
break;
|
||||
case ($doc_element->namespaceURI == 'http://purl.org/atom/ns#'):
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/Atom.php');
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/AtomElement.php');
|
||||
$class = 'XML_Feed_Parser_Atom';
|
||||
$error = 'Atom 0.3 deprecated, using 1.0 parser which won\'t provide ' .
|
||||
'all options';
|
||||
break;
|
||||
case ($doc_element->namespaceURI == 'http://purl.org/rss/1.0/' ||
|
||||
($doc_element->hasChildNodes() && $doc_element->childNodes->length > 1
|
||||
&& $doc_element->childNodes->item(1)->namespaceURI ==
|
||||
'http://purl.org/rss/1.0/')):
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS1.php');
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS1Element.php');
|
||||
$class = 'XML_Feed_Parser_RSS1';
|
||||
break;
|
||||
case ($doc_element->namespaceURI == 'http://purl.org/rss/1.1/' ||
|
||||
($doc_element->hasChildNodes() && $doc_element->childNodes->length > 1
|
||||
&& $doc_element->childNodes->item(1)->namespaceURI ==
|
||||
'http://purl.org/rss/1.1/')):
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS11.php');
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS11Element.php');
|
||||
$class = 'XML_Feed_Parser_RSS11';
|
||||
break;
|
||||
case (($doc_element->hasChildNodes() && $doc_element->childNodes->length > 1
|
||||
&& $doc_element->childNodes->item(1)->namespaceURI ==
|
||||
'http://my.netscape.com/rdf/simple/0.9/') ||
|
||||
$doc_element->namespaceURI == 'http://my.netscape.com/rdf/simple/0.9/'):
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS09.php');
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS09Element.php');
|
||||
$class = 'XML_Feed_Parser_RSS09';
|
||||
break;
|
||||
case ($doc_element->tagName == 'rss' and
|
||||
$doc_element->hasAttribute('version') &&
|
||||
$doc_element->getAttribute('version') == 0.91):
|
||||
$error = 'RSS 0.91 has been superceded by RSS2.0. Using RSS2.0 parser.';
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS2.php');
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS2Element.php');
|
||||
$class = 'XML_Feed_Parser_RSS2';
|
||||
break;
|
||||
case ($doc_element->tagName == 'rss' and
|
||||
$doc_element->hasAttribute('version') &&
|
||||
$doc_element->getAttribute('version') == 0.92):
|
||||
$error = 'RSS 0.92 has been superceded by RSS2.0. Using RSS2.0 parser.';
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS2.php');
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS2Element.php');
|
||||
$class = 'XML_Feed_Parser_RSS2';
|
||||
break;
|
||||
case (in_array($doc_element->namespaceURI, $this->feedNamespaces['rss2'])
|
||||
|| $doc_element->tagName == 'rss'):
|
||||
if (! $doc_element->hasAttribute('version') ||
|
||||
$doc_element->getAttribute('version') != 2) {
|
||||
$error = 'RSS version not specified. Parsing as RSS2.0';
|
||||
}
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS2.php');
|
||||
require_once(_PS_PEAR_XML_PARSER_PATH_.'Parser/RSS2Element.php');
|
||||
$class = 'XML_Feed_Parser_RSS2';
|
||||
break;
|
||||
default:
|
||||
throw new XML_Feed_Parser_Exception('Feed type unknown');
|
||||
break;
|
||||
}
|
||||
|
||||
if (! $suppressWarnings && ! empty($error)) {
|
||||
trigger_error($error, E_USER_WARNING);
|
||||
}
|
||||
|
||||
/* Instantiate feed object */
|
||||
$this->feed = new $class($this->model, $strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy to allow feed element names to be used as method names
|
||||
*
|
||||
* For top-level feed elements we will provide access using methods or
|
||||
* attributes. This function simply passes on a request to the appropriate
|
||||
* feed type object.
|
||||
*
|
||||
* @param string $call - the method being called
|
||||
* @param array $attributes
|
||||
*/
|
||||
function __call($call, $attributes)
|
||||
{
|
||||
$attributes = array_pad($attributes, 5, false);
|
||||
list($a, $b, $c, $d, $e) = $attributes;
|
||||
return $this->feed->$call($a, $b, $c, $d, $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy to allow feed element names to be used as attribute names
|
||||
*
|
||||
* To allow variable-like access to feed-level data we use this
|
||||
* method. It simply passes along to __call() which in turn passes
|
||||
* along to the relevant object.
|
||||
*
|
||||
* @param string $val - the name of the variable required
|
||||
*/
|
||||
function __get($val)
|
||||
{
|
||||
return $this->feed->$val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides iteration functionality.
|
||||
*
|
||||
* Of course we must be able to iterate... This function simply increases
|
||||
* our internal counter.
|
||||
*/
|
||||
function next()
|
||||
{
|
||||
if (isset($this->current_item) &&
|
||||
$this->current_item <= $this->feed->numberEntries - 1) {
|
||||
++$this->current_item;
|
||||
} elseif (! isset($this->current_item)) {
|
||||
$this->current_item = 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return XML_Feed_Type object for current element
|
||||
*
|
||||
* @return XML_Feed_Parser_Type Object
|
||||
*/
|
||||
function current()
|
||||
{
|
||||
return $this->getEntryByOffset($this->current_item);
|
||||
}
|
||||
|
||||
/**
|
||||
* For iteration -- returns the key for the current stage in the array.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function key()
|
||||
{
|
||||
return $this->current_item;
|
||||
}
|
||||
|
||||
/**
|
||||
* For iteration -- tells whether we have reached the
|
||||
* end.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function valid()
|
||||
{
|
||||
return $this->current_item < $this->feed->numberEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* For iteration -- resets the internal counter to the beginning.
|
||||
*/
|
||||
function rewind()
|
||||
{
|
||||
$this->current_item = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to entries by ID if one is specified in the source feed.
|
||||
*
|
||||
* As well as allowing the items to be iterated over we want to allow
|
||||
* users to be able to access a specific entry. This is one of two ways of
|
||||
* doing that, the other being by offset. This method can be quite slow
|
||||
* if dealing with a large feed that hasn't yet been processed as it
|
||||
* instantiates objects for every entry until it finds the one needed.
|
||||
*
|
||||
* @param string $id Valid ID for the given feed format
|
||||
* @return XML_Feed_Parser_Type|false
|
||||
*/
|
||||
function getEntryById($id)
|
||||
{
|
||||
if (isset($this->idMappings[$id])) {
|
||||
return $this->getEntryByOffset($this->idMappings[$id]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we have not yet encountered that ID, let's go through all the
|
||||
* remaining entries in order till we find it.
|
||||
* This is a fairly slow implementation, but it should work.
|
||||
*/
|
||||
return $this->feed->getEntryById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve entry by numeric offset, starting from zero.
|
||||
*
|
||||
* As well as allowing the items to be iterated over we want to allow
|
||||
* users to be able to access a specific entry. This is one of two ways of
|
||||
* doing that, the other being by ID.
|
||||
*
|
||||
* @param int $offset The position of the entry within the feed, starting from 0
|
||||
* @return XML_Feed_Parser_Type|false
|
||||
*/
|
||||
function getEntryByOffset($offset)
|
||||
{
|
||||
if ($offset < $this->feed->numberEntries) {
|
||||
if (isset($this->feed->entries[$offset])) {
|
||||
return $this->feed->entries[$offset];
|
||||
} else {
|
||||
try {
|
||||
$this->feed->getEntryByOffset($offset);
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
$id = $this->feed->entries[$offset]->getID();
|
||||
$this->idMappings[$id] = $offset;
|
||||
return $this->feed->entries[$offset];
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve version details from feed type class.
|
||||
*
|
||||
* @return void
|
||||
* @author James Stewart
|
||||
*/
|
||||
function version()
|
||||
{
|
||||
return $this->feed->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the feed.
|
||||
*
|
||||
* @return String
|
||||
**/
|
||||
function __toString()
|
||||
{
|
||||
return $this->feed->__toString();
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,365 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Atom feed class for XML_Feed_Parser
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: Atom.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is the class that determines how we manage Atom 1.0 feeds
|
||||
*
|
||||
* How we deal with constructs:
|
||||
* date - return as unix datetime for use with the 'date' function unless specified otherwise
|
||||
* text - return as is. optional parameter will give access to attributes
|
||||
* person - defaults to name, but parameter based access
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser_Atom extends XML_Feed_Parser_Type
|
||||
{
|
||||
/**
|
||||
* The URI of the RelaxNG schema used to (optionally) validate the feed
|
||||
* @var string
|
||||
*/
|
||||
protected $relax = 'atom.rng';
|
||||
|
||||
/**
|
||||
* We're likely to use XPath, so let's keep it global
|
||||
* @var DOMXPath
|
||||
*/
|
||||
public $xpath;
|
||||
|
||||
/**
|
||||
* When performing XPath queries we will use this prefix
|
||||
* @var string
|
||||
*/
|
||||
private $xpathPrefix = '//';
|
||||
|
||||
/**
|
||||
* The feed type we are parsing
|
||||
* @var string
|
||||
*/
|
||||
public $version = 'Atom 1.0';
|
||||
|
||||
/**
|
||||
* The class used to represent individual items
|
||||
* @var string
|
||||
*/
|
||||
protected $itemClass = 'XML_Feed_Parser_AtomElement';
|
||||
|
||||
/**
|
||||
* The element containing entries
|
||||
* @var string
|
||||
*/
|
||||
protected $itemElement = 'entry';
|
||||
|
||||
/**
|
||||
* Here we map those elements we're not going to handle individually
|
||||
* to the constructs they are. The optional second parameter in the array
|
||||
* tells the parser whether to 'fall back' (not apt. at the feed level) or
|
||||
* fail if the element is missing. If the parameter is not set, the function
|
||||
* will simply return false and leave it to the client to decide what to do.
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'author' => array('Person'),
|
||||
'contributor' => array('Person'),
|
||||
'icon' => array('Text'),
|
||||
'logo' => array('Text'),
|
||||
'id' => array('Text', 'fail'),
|
||||
'rights' => array('Text'),
|
||||
'subtitle' => array('Text'),
|
||||
'title' => array('Text', 'fail'),
|
||||
'updated' => array('Date', 'fail'),
|
||||
'link' => array('Link'),
|
||||
'generator' => array('Text'),
|
||||
'category' => array('Category'));
|
||||
|
||||
/**
|
||||
* Here we provide a few mappings for those very special circumstances in
|
||||
* which it makes sense to map back to the RSS2 spec. Key is RSS2 version
|
||||
* value is an array consisting of the equivalent in atom and any attributes
|
||||
* needed to make the mapping.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'guid' => array('id'),
|
||||
'links' => array('link'),
|
||||
'tags' => array('category'),
|
||||
'contributors' => array('contributor'));
|
||||
|
||||
/**
|
||||
* Our constructor does nothing more than its parent.
|
||||
*
|
||||
* @param DOMDocument $xml A DOM object representing the feed
|
||||
* @param bool (optional) $string Whether or not to validate this feed
|
||||
*/
|
||||
function __construct(DOMDocument $model, $strict = false)
|
||||
{
|
||||
$this->model = $model;
|
||||
|
||||
if ($strict) {
|
||||
if (! $this->relaxNGValidate()) {
|
||||
throw new XML_Feed_Parser_Exception('Failed required validation');
|
||||
}
|
||||
}
|
||||
|
||||
$this->xpath = new DOMXPath($this->model);
|
||||
$this->xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
|
||||
$this->numberEntries = $this->count('entry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement retrieval of an entry based on its ID for atom feeds.
|
||||
*
|
||||
* This function uses XPath to get the entry based on its ID. If DOMXPath::evaluate
|
||||
* is available, we also use that to store a reference to the entry in the array
|
||||
* used by getEntryByOffset so that method does not have to seek out the entry
|
||||
* if it's requested that way.
|
||||
*
|
||||
* @param string $id any valid Atom ID.
|
||||
* @return XML_Feed_Parser_AtomElement
|
||||
*/
|
||||
function getEntryById($id)
|
||||
{
|
||||
if (isset($this->idMappings[$id])) {
|
||||
return $this->entries[$this->idMappings[$id]];
|
||||
}
|
||||
|
||||
$entries = $this->xpath->query("//atom:entry[atom:id='$id']");
|
||||
|
||||
if ($entries->length > 0) {
|
||||
$xmlBase = $entries->item(0)->baseURI;
|
||||
$entry = new $this->itemClass($entries->item(0), $this, $xmlBase);
|
||||
|
||||
if (in_array('evaluate', get_class_methods($this->xpath))) {
|
||||
$offset = $this->xpath->evaluate("count(preceding-sibling::atom:entry)", $entries->item(0));
|
||||
$this->entries[$offset] = $entry;
|
||||
}
|
||||
|
||||
$this->idMappings[$id] = $entry;
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves data from a person construct.
|
||||
*
|
||||
* Get a person construct. We default to the 'name' element but allow
|
||||
* access to any of the elements.
|
||||
*
|
||||
* @param string $method The name of the person construct we want
|
||||
* @param array $arguments An array which we hope gives a 'param'
|
||||
* @return string|false
|
||||
*/
|
||||
protected function getPerson($method, $arguments)
|
||||
{
|
||||
$offset = empty($arguments[0]) ? 0 : $arguments[0];
|
||||
$parameter = empty($arguments[1]['param']) ? 'name' : $arguments[1]['param'];
|
||||
$section = $this->model->getElementsByTagName($method);
|
||||
|
||||
if ($parameter == 'url') {
|
||||
$parameter = 'uri';
|
||||
}
|
||||
|
||||
if ($section->length <= $offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$param = $section->item($offset)->getElementsByTagName($parameter);
|
||||
if ($param->length == 0) {
|
||||
return false;
|
||||
}
|
||||
return $param->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an element's content where that content is a text construct.
|
||||
*
|
||||
* Get a text construct. When calling this method, the two arguments
|
||||
* allowed are 'offset' and 'attribute', so $parser->subtitle() would
|
||||
* return the content of the element, while $parser->subtitle(false, 'type')
|
||||
* would return the value of the type attribute.
|
||||
*
|
||||
* @todo Clarify overlap with getContent()
|
||||
* @param string $method The name of the text construct we want
|
||||
* @param array $arguments An array which we hope gives a 'param'
|
||||
* @return string
|
||||
*/
|
||||
protected function getText($method, $arguments)
|
||||
{
|
||||
$offset = empty($arguments[0]) ? 0: $arguments[0];
|
||||
$attribute = empty($arguments[1]) ? false : $arguments[1];
|
||||
$tags = $this->model->getElementsByTagName($method);
|
||||
|
||||
if ($tags->length <= $offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = $tags->item($offset);
|
||||
|
||||
if (! $content->hasAttribute('type')) {
|
||||
$content->setAttribute('type', 'text');
|
||||
}
|
||||
$type = $content->getAttribute('type');
|
||||
|
||||
if (! empty($attribute) and
|
||||
! ($method == 'generator' and $attribute == 'name')) {
|
||||
if ($content->hasAttribute($attribute)) {
|
||||
return $content->getAttribute($attribute);
|
||||
} elseif ($attribute == 'href' and $content->hasAttribute('uri')) {
|
||||
return $content->getAttribute('uri');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->parseTextConstruct($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract content appropriately from atom text constructs
|
||||
*
|
||||
* Because of different rules applied to the content element and other text
|
||||
* constructs, they are deployed as separate functions, but they share quite
|
||||
* a bit of processing. This method performs the core common process, which is
|
||||
* to apply the rules for different mime types in order to extract the content.
|
||||
*
|
||||
* @param DOMNode $content the text construct node to be parsed
|
||||
* @return String
|
||||
* @author James Stewart
|
||||
**/
|
||||
protected function parseTextConstruct(DOMNode $content)
|
||||
{
|
||||
if ($content->hasAttribute('type')) {
|
||||
$type = $content->getAttribute('type');
|
||||
} else {
|
||||
$type = 'text';
|
||||
}
|
||||
|
||||
if (strpos($type, 'text/') === 0) {
|
||||
$type = 'text';
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'text':
|
||||
case 'html':
|
||||
return $content->textContent;
|
||||
break;
|
||||
case 'xhtml':
|
||||
$container = $content->getElementsByTagName('div');
|
||||
if ($container->length == 0) {
|
||||
return false;
|
||||
}
|
||||
$contents = $container->item(0);
|
||||
if ($contents->hasChildNodes()) {
|
||||
/* Iterate through, applying xml:base and store the result */
|
||||
$result = '';
|
||||
foreach ($contents->childNodes as $node) {
|
||||
$result .= $this->traverseNode($node);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
break;
|
||||
case preg_match('@^[a-zA-Z]+/[a-zA-Z+]*xml@i', $type) > 0:
|
||||
return $content;
|
||||
break;
|
||||
case 'application/octet-stream':
|
||||
default:
|
||||
return base64_decode(trim($content->nodeValue));
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Get a category from the entry.
|
||||
*
|
||||
* A feed or entry can have any number of categories. A category can have the
|
||||
* attributes term, scheme and label.
|
||||
*
|
||||
* @param string $method The name of the text construct we want
|
||||
* @param array $arguments An array which we hope gives a 'param'
|
||||
* @return string
|
||||
*/
|
||||
function getCategory($method, $arguments)
|
||||
{
|
||||
$offset = empty($arguments[0]) ? 0: $arguments[0];
|
||||
$attribute = empty($arguments[1]) ? 'term' : $arguments[1];
|
||||
$categories = $this->model->getElementsByTagName('category');
|
||||
if ($categories->length <= $offset) {
|
||||
$category = $categories->item($offset);
|
||||
if ($category->hasAttribute($attribute)) {
|
||||
return $category->getAttribute($attribute);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This element must be present at least once with rel="feed". This element may be
|
||||
* present any number of further times so long as there is no clash. If no 'rel' is
|
||||
* present and we're asked for one, we follow the example of the Universal Feed
|
||||
* Parser and presume 'alternate'.
|
||||
*
|
||||
* @param int $offset the position of the link within the container
|
||||
* @param string $attribute the attribute name required
|
||||
* @param array an array of attributes to search by
|
||||
* @return string the value of the attribute
|
||||
*/
|
||||
function getLink($offset = 0, $attribute = 'href', $params = false)
|
||||
{
|
||||
if (is_array($params) and !empty($params)) {
|
||||
$terms = array();
|
||||
$alt_predicate = '';
|
||||
$other_predicate = '';
|
||||
|
||||
foreach ($params as $key => $value) {
|
||||
if ($key == 'rel' && $value == 'alternate') {
|
||||
$alt_predicate = '[not(@rel) or @rel="alternate"]';
|
||||
} else {
|
||||
$terms[] = "@$key='$value'";
|
||||
}
|
||||
}
|
||||
if (!empty($terms)) {
|
||||
$other_predicate = '[' . join(' and ', $terms) . ']';
|
||||
}
|
||||
$query = $this->xpathPrefix . 'atom:link' . $alt_predicate . $other_predicate;
|
||||
$links = $this->xpath->query($query);
|
||||
} else {
|
||||
$links = $this->model->getElementsByTagName('link');
|
||||
}
|
||||
if ($links->length > $offset) {
|
||||
if ($links->item($offset)->hasAttribute($attribute)) {
|
||||
$value = $links->item($offset)->getAttribute($attribute);
|
||||
if ($attribute == 'href') {
|
||||
$value = $this->addBase($value, $links->item($offset));
|
||||
}
|
||||
return $value;
|
||||
} elseif ($attribute == 'rel') {
|
||||
return 'alternate';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,261 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* AtomElement class for XML_Feed_Parser package
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: AtomElement.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class provides support for atom entries. It will usually be called by
|
||||
* XML_Feed_Parser_Atom with which it shares many methods.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser_AtomElement extends XML_Feed_Parser_Atom
|
||||
{
|
||||
/**
|
||||
* This will be a reference to the parent object for when we want
|
||||
* to use a 'fallback' rule
|
||||
* @var XML_Feed_Parser_Atom
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* When performing XPath queries we will use this prefix
|
||||
* @var string
|
||||
*/
|
||||
private $xpathPrefix = '';
|
||||
|
||||
/**
|
||||
* xml:base values inherited by the element
|
||||
* @var string
|
||||
*/
|
||||
protected $xmlBase;
|
||||
|
||||
/**
|
||||
* Here we provide a few mappings for those very special circumstances in
|
||||
* which it makes sense to map back to the RSS2 spec or to manage other
|
||||
* compatibilities (eg. with the Univeral Feed Parser). Key is the other version's
|
||||
* name for the command, value is an array consisting of the equivalent in our atom
|
||||
* api and any attributes needed to make the mapping.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'guid' => array('id'),
|
||||
'links' => array('link'),
|
||||
'tags' => array('category'),
|
||||
'contributors' => array('contributor'));
|
||||
|
||||
/**
|
||||
* Our specific element map
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'author' => array('Person', 'fallback'),
|
||||
'contributor' => array('Person'),
|
||||
'id' => array('Text', 'fail'),
|
||||
'published' => array('Date'),
|
||||
'updated' => array('Date', 'fail'),
|
||||
'title' => array('Text', 'fail'),
|
||||
'rights' => array('Text', 'fallback'),
|
||||
'summary' => array('Text'),
|
||||
'content' => array('Content'),
|
||||
'link' => array('Link'),
|
||||
'enclosure' => array('Enclosure'),
|
||||
'category' => array('Category'));
|
||||
|
||||
/**
|
||||
* Store useful information for later.
|
||||
*
|
||||
* @param DOMElement $element - this item as a DOM element
|
||||
* @param XML_Feed_Parser_Atom $parent - the feed of which this is a member
|
||||
*/
|
||||
function __construct(DOMElement $element, $parent, $xmlBase = '')
|
||||
{
|
||||
$this->model = $element;
|
||||
$this->parent = $parent;
|
||||
$this->xmlBase = $xmlBase;
|
||||
$this->xpathPrefix = "//atom:entry[atom:id='" . $this->id . "']/";
|
||||
$this->xpath = $this->parent->xpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to specific aspects of the author data for an atom entry
|
||||
*
|
||||
* Author data at the entry level is more complex than at the feed level.
|
||||
* If atom:author is not present for the entry we need to look for it in
|
||||
* an atom:source child of the atom:entry. If it's not there either, then
|
||||
* we look to the parent for data.
|
||||
*
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
function getAuthor($arguments)
|
||||
{
|
||||
/* Find out which part of the author data we're looking for */
|
||||
if (isset($arguments['param'])) {
|
||||
$parameter = $arguments['param'];
|
||||
} else {
|
||||
$parameter = 'name';
|
||||
}
|
||||
|
||||
$test = $this->model->getElementsByTagName('author');
|
||||
if ($test->length > 0) {
|
||||
$item = $test->item(0);
|
||||
return $item->getElementsByTagName($parameter)->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
$source = $this->model->getElementsByTagName('source');
|
||||
if ($source->length > 0) {
|
||||
$test = $this->model->getElementsByTagName('author');
|
||||
if ($test->length > 0) {
|
||||
$item = $test->item(0);
|
||||
return $item->getElementsByTagName($parameter)->item(0)->nodeValue;
|
||||
}
|
||||
}
|
||||
return $this->parent->getAuthor($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of the content element or info on a specific attribute
|
||||
*
|
||||
* This element may or may not be present. It cannot be present more than
|
||||
* once. It may have a 'src' attribute, in which case there's no content
|
||||
* If not present, then the entry must have link with rel="alternate".
|
||||
* If there is content we return it, if not and there's a 'src' attribute
|
||||
* we return the value of that instead. The method can take an 'attribute'
|
||||
* argument, in which case we return the value of that attribute if present.
|
||||
* eg. $item->content("type") will return the type of the content. It is
|
||||
* recommended that all users check the type before getting the content to
|
||||
* ensure that their script is capable of handling the type of returned data.
|
||||
* (data carried in the content element can be either 'text', 'html', 'xhtml',
|
||||
* or any standard MIME type).
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
protected function getContent($method, $arguments = array())
|
||||
{
|
||||
$attribute = empty($arguments[0]) ? false : $arguments[0];
|
||||
$tags = $this->model->getElementsByTagName('content');
|
||||
|
||||
if ($tags->length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = $tags->item(0);
|
||||
|
||||
if (! $content->hasAttribute('type')) {
|
||||
$content->setAttribute('type', 'text');
|
||||
}
|
||||
if (! empty($attribute)) {
|
||||
return $content->getAttribute($attribute);
|
||||
}
|
||||
|
||||
$type = $content->getAttribute('type');
|
||||
|
||||
if (! empty($attribute)) {
|
||||
if ($content->hasAttribute($attribute))
|
||||
{
|
||||
return $content->getAttribute($attribute);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($content->hasAttribute('src')) {
|
||||
return $content->getAttribute('src');
|
||||
}
|
||||
|
||||
return $this->parseTextConstruct($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* For compatibility, this method provides a mapping to access enclosures.
|
||||
*
|
||||
* The Atom spec doesn't provide for an enclosure element, but it is
|
||||
* generally supported using the link element with rel='enclosure'.
|
||||
*
|
||||
* @param string $method - for compatibility with our __call usage
|
||||
* @param array $arguments - for compatibility with our __call usage
|
||||
* @return array|false
|
||||
*/
|
||||
function getEnclosure($method, $arguments = array())
|
||||
{
|
||||
$offset = isset($arguments[0]) ? $arguments[0] : 0;
|
||||
$query = "//atom:entry[atom:id='" . $this->getText('id', false) .
|
||||
"']/atom:link[@rel='enclosure']";
|
||||
|
||||
$encs = $this->parent->xpath->query($query);
|
||||
if ($encs->length > $offset) {
|
||||
try {
|
||||
if (! $encs->item($offset)->hasAttribute('href')) {
|
||||
return false;
|
||||
}
|
||||
$attrs = $encs->item($offset)->attributes;
|
||||
$length = $encs->item($offset)->hasAttribute('length') ?
|
||||
$encs->item($offset)->getAttribute('length') : false;
|
||||
return array(
|
||||
'url' => $attrs->getNamedItem('href')->value,
|
||||
'type' => $attrs->getNamedItem('type')->value,
|
||||
'length' => $length);
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of this entry's source, if available/relevant
|
||||
*
|
||||
* Where an atom:entry is taken from another feed then the aggregator
|
||||
* is supposed to include an atom:source element which replicates at least
|
||||
* the atom:id, atom:title, and atom:updated metadata from the original
|
||||
* feed. Atom:source therefore has a very similar structure to atom:feed
|
||||
* and if we find it we will return it as an XML_Feed_Parser_Atom object.
|
||||
*
|
||||
* @return XML_Feed_Parser_Atom|false
|
||||
*/
|
||||
function getSource()
|
||||
{
|
||||
$test = $this->model->getElementsByTagName('source');
|
||||
if ($test->length == 0) {
|
||||
return false;
|
||||
}
|
||||
$source = new XML_Feed_Parser_Atom($test->item(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entry as an XML string
|
||||
*
|
||||
* Return an XML serialization of the feed, should it be required. Most
|
||||
* users however, will already have a serialization that they used when
|
||||
* instantiating the object.
|
||||
*
|
||||
* @return string XML serialization of element
|
||||
*/
|
||||
function __toString()
|
||||
{
|
||||
$simple = simplexml_import_dom($this->model);
|
||||
return $simple->asXML();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Keeps the exception class for XML_Feed_Parser.
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
|
||||
* @version CVS: $Id: Exception.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* We are extending PEAR_Exception
|
||||
*/
|
||||
require_once(dirname(__FILE__).'/../../pear/PEAR.php');
|
||||
|
||||
/**
|
||||
* XML_Feed_Parser_Exception is a simple extension of PEAR_Exception, existing
|
||||
* to help with identification of the source of exceptions.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser_Exception extends PEAR_Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,221 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* RSS0.9 class for XML_Feed_Parser
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: RSS09.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class handles RSS0.9 feeds.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
* @todo Find a Relax NG URI we can use
|
||||
*/
|
||||
class XML_Feed_Parser_RSS09 extends XML_Feed_Parser_Type
|
||||
{
|
||||
/**
|
||||
* The URI of the RelaxNG schema used to (optionally) validate the feed
|
||||
* @var string
|
||||
*/
|
||||
protected $relax = '';
|
||||
|
||||
/**
|
||||
* We're likely to use XPath, so let's keep it global
|
||||
* @var DOMXPath
|
||||
*/
|
||||
protected $xpath;
|
||||
|
||||
/**
|
||||
* The feed type we are parsing
|
||||
* @var string
|
||||
*/
|
||||
public $version = 'RSS 0.9';
|
||||
|
||||
/**
|
||||
* The class used to represent individual items
|
||||
* @var string
|
||||
*/
|
||||
protected $itemClass = 'XML_Feed_Parser_RSS09Element';
|
||||
|
||||
/**
|
||||
* The element containing entries
|
||||
* @var string
|
||||
*/
|
||||
protected $itemElement = 'item';
|
||||
|
||||
/**
|
||||
* Here we map those elements we're not going to handle individually
|
||||
* to the constructs they are. The optional second parameter in the array
|
||||
* tells the parser whether to 'fall back' (not apt. at the feed level) or
|
||||
* fail if the element is missing. If the parameter is not set, the function
|
||||
* will simply return false and leave it to the client to decide what to do.
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'title' => array('Text'),
|
||||
'link' => array('Text'),
|
||||
'description' => array('Text'),
|
||||
'image' => array('Image'),
|
||||
'textinput' => array('TextInput'));
|
||||
|
||||
/**
|
||||
* Here we map some elements to their atom equivalents. This is going to be
|
||||
* quite tricky to pull off effectively (and some users' methods may vary)
|
||||
* but is worth trying. The key is the atom version, the value is RSS2.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'title' => array('title'),
|
||||
'link' => array('link'),
|
||||
'subtitle' => array('description'));
|
||||
|
||||
/**
|
||||
* We will be working with multiple namespaces and it is useful to
|
||||
* keep them together
|
||||
* @var array
|
||||
*/
|
||||
protected $namespaces = array(
|
||||
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
|
||||
|
||||
/**
|
||||
* Our constructor does nothing more than its parent.
|
||||
*
|
||||
* @todo RelaxNG validation
|
||||
* @param DOMDocument $xml A DOM object representing the feed
|
||||
* @param bool (optional) $string Whether or not to validate this feed
|
||||
*/
|
||||
function __construct(DOMDocument $model, $strict = false)
|
||||
{
|
||||
$this->model = $model;
|
||||
|
||||
$this->xpath = new DOMXPath($model);
|
||||
foreach ($this->namespaces as $key => $value) {
|
||||
$this->xpath->registerNamespace($key, $value);
|
||||
}
|
||||
$this->numberEntries = $this->count('item');
|
||||
}
|
||||
|
||||
/**
|
||||
* Included for compatibility -- will not work with RSS 0.9
|
||||
*
|
||||
* This is not something that will work with RSS0.9 as it does not have
|
||||
* clear restrictions on the global uniqueness of IDs.
|
||||
*
|
||||
* @param string $id any valid ID.
|
||||
* @return false
|
||||
*/
|
||||
function getEntryById($id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of the image associated with the feed.
|
||||
*
|
||||
* @return array|false an array simply containing the child elements
|
||||
*/
|
||||
protected function getImage()
|
||||
{
|
||||
$images = $this->model->getElementsByTagName('image');
|
||||
if ($images->length > 0) {
|
||||
$image = $images->item(0);
|
||||
$details = array();
|
||||
if ($image->hasChildNodes()) {
|
||||
$details = array(
|
||||
'title' => $image->getElementsByTagName('title')->item(0)->value,
|
||||
'link' => $image->getElementsByTagName('link')->item(0)->value,
|
||||
'url' => $image->getElementsByTagName('url')->item(0)->value);
|
||||
} else {
|
||||
$details = array('title' => false,
|
||||
'link' => false,
|
||||
'url' => $image->attributes->getNamedItem('resource')->nodeValue);
|
||||
}
|
||||
$details = array_merge($details,
|
||||
array('description' => false, 'height' => false, 'width' => false));
|
||||
if (! empty($details)) {
|
||||
return $details;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The textinput element is little used, but in the interests of
|
||||
* completeness we will support it.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
protected function getTextInput()
|
||||
{
|
||||
$inputs = $this->model->getElementsByTagName('textinput');
|
||||
if ($inputs->length > 0) {
|
||||
$input = $inputs->item(0);
|
||||
$results = array();
|
||||
$results['title'] = isset(
|
||||
$input->getElementsByTagName('title')->item(0)->value) ?
|
||||
$input->getElementsByTagName('title')->item(0)->value : null;
|
||||
$results['description'] = isset(
|
||||
$input->getElementsByTagName('description')->item(0)->value) ?
|
||||
$input->getElementsByTagName('description')->item(0)->value : null;
|
||||
$results['name'] = isset(
|
||||
$input->getElementsByTagName('name')->item(0)->value) ?
|
||||
$input->getElementsByTagName('name')->item(0)->value : null;
|
||||
$results['link'] = isset(
|
||||
$input->getElementsByTagName('link')->item(0)->value) ?
|
||||
$input->getElementsByTagName('link')->item(0)->value : null;
|
||||
if (empty($results['link']) &&
|
||||
$input->attributes->getNamedItem('resource')) {
|
||||
$results['link'] = $input->attributes->getNamedItem('resource')->nodeValue;
|
||||
}
|
||||
if (! empty($results)) {
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of a link from the feed.
|
||||
*
|
||||
* In RSS1 a link is a text element but in order to ensure that we resolve
|
||||
* URLs properly we have a special function for them.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getLink($offset = 0, $attribute = 'href', $params = false)
|
||||
{
|
||||
$links = $this->model->getElementsByTagName('link');
|
||||
if ($links->length <= $offset) {
|
||||
return false;
|
||||
}
|
||||
$link = $links->item($offset);
|
||||
return $this->addBase($link->nodeValue, $link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented - no available validation.
|
||||
*/
|
||||
public function relaxNGValidate() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* RSS0.9 Element class for XML_Feed_Parser
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: RSS09Element.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class provides support for RSS 0.9 entries. It will usually be called by
|
||||
* XML_Feed_Parser_RSS09 with which it shares many methods.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser_RSS09Element extends XML_Feed_Parser_RSS09
|
||||
{
|
||||
/**
|
||||
* This will be a reference to the parent object for when we want
|
||||
* to use a 'fallback' rule
|
||||
* @var XML_Feed_Parser_RSS09
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Our specific element map
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'title' => array('Text'),
|
||||
'link' => array('Link'));
|
||||
|
||||
/**
|
||||
* Store useful information for later.
|
||||
*
|
||||
* @param DOMElement $element - this item as a DOM element
|
||||
* @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member
|
||||
*/
|
||||
function __construct(DOMElement $element, $parent, $xmlBase = '')
|
||||
{
|
||||
$this->model = $element;
|
||||
$this->parent = $parent;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,275 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* RSS1 class for XML_Feed_Parser
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: RSS1.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class handles RSS1.0 feeds.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
* @todo Find a Relax NG URI we can use
|
||||
*/
|
||||
class XML_Feed_Parser_RSS1 extends XML_Feed_Parser_Type
|
||||
{
|
||||
/**
|
||||
* The URI of the RelaxNG schema used to (optionally) validate the feed
|
||||
* @var string
|
||||
*/
|
||||
protected $relax = 'rss10.rng';
|
||||
|
||||
/**
|
||||
* We're likely to use XPath, so let's keep it global
|
||||
* @var DOMXPath
|
||||
*/
|
||||
protected $xpath;
|
||||
|
||||
/**
|
||||
* The feed type we are parsing
|
||||
* @var string
|
||||
*/
|
||||
public $version = 'RSS 1.0';
|
||||
|
||||
/**
|
||||
* The class used to represent individual items
|
||||
* @var string
|
||||
*/
|
||||
protected $itemClass = 'XML_Feed_Parser_RSS1Element';
|
||||
|
||||
/**
|
||||
* The element containing entries
|
||||
* @var string
|
||||
*/
|
||||
protected $itemElement = 'item';
|
||||
|
||||
/**
|
||||
* Here we map those elements we're not going to handle individually
|
||||
* to the constructs they are. The optional second parameter in the array
|
||||
* tells the parser whether to 'fall back' (not apt. at the feed level) or
|
||||
* fail if the element is missing. If the parameter is not set, the function
|
||||
* will simply return false and leave it to the client to decide what to do.
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'title' => array('Text'),
|
||||
'link' => array('Text'),
|
||||
'description' => array('Text'),
|
||||
'image' => array('Image'),
|
||||
'textinput' => array('TextInput'),
|
||||
'updatePeriod' => array('Text'),
|
||||
'updateFrequency' => array('Text'),
|
||||
'updateBase' => array('Date'),
|
||||
'rights' => array('Text'), # dc:rights
|
||||
'description' => array('Text'), # dc:description
|
||||
'creator' => array('Text'), # dc:creator
|
||||
'publisher' => array('Text'), # dc:publisher
|
||||
'contributor' => array('Text'), # dc:contributor
|
||||
'date' => array('Date') # dc:contributor
|
||||
);
|
||||
|
||||
/**
|
||||
* Here we map some elements to their atom equivalents. This is going to be
|
||||
* quite tricky to pull off effectively (and some users' methods may vary)
|
||||
* but is worth trying. The key is the atom version, the value is RSS2.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'title' => array('title'),
|
||||
'link' => array('link'),
|
||||
'subtitle' => array('description'),
|
||||
'author' => array('creator'),
|
||||
'updated' => array('date'));
|
||||
|
||||
/**
|
||||
* We will be working with multiple namespaces and it is useful to
|
||||
* keep them together
|
||||
* @var array
|
||||
*/
|
||||
protected $namespaces = array(
|
||||
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
'rss' => 'http://purl.org/rss/1.0/',
|
||||
'dc' => 'http://purl.org/rss/1.0/modules/dc/',
|
||||
'content' => 'http://purl.org/rss/1.0/modules/content/',
|
||||
'sy' => 'http://web.resource.org/rss/1.0/modules/syndication/');
|
||||
|
||||
/**
|
||||
* Our constructor does nothing more than its parent.
|
||||
*
|
||||
* @param DOMDocument $xml A DOM object representing the feed
|
||||
* @param bool (optional) $string Whether or not to validate this feed
|
||||
*/
|
||||
function __construct(DOMDocument $model, $strict = false)
|
||||
{
|
||||
$this->model = $model;
|
||||
if ($strict) {
|
||||
if (! $this->relaxNGValidate()) {
|
||||
throw new XML_Feed_Parser_Exception('Failed required validation');
|
||||
}
|
||||
}
|
||||
|
||||
$this->xpath = new DOMXPath($model);
|
||||
foreach ($this->namespaces as $key => $value) {
|
||||
$this->xpath->registerNamespace($key, $value);
|
||||
}
|
||||
$this->numberEntries = $this->count('item');
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows retrieval of an entry by ID where the rdf:about attribute is used
|
||||
*
|
||||
* This is not really something that will work with RSS1 as it does not have
|
||||
* clear restrictions on the global uniqueness of IDs. We will employ the
|
||||
* _very_ hit and miss method of selecting entries based on the rdf:about
|
||||
* attribute. If DOMXPath::evaluate is available, we also use that to store
|
||||
* a reference to the entry in the array used by getEntryByOffset so that
|
||||
* method does not have to seek out the entry if it's requested that way.
|
||||
*
|
||||
* @param string $id any valid ID.
|
||||
* @return XML_Feed_Parser_RSS1Element
|
||||
*/
|
||||
function getEntryById($id)
|
||||
{
|
||||
if (isset($this->idMappings[$id])) {
|
||||
return $this->entries[$this->idMappings[$id]];
|
||||
}
|
||||
|
||||
$entries = $this->xpath->query("//rss:item[@rdf:about='$id']");
|
||||
if ($entries->length > 0) {
|
||||
$classname = $this->itemClass;
|
||||
$entry = new $classname($entries->item(0), $this);
|
||||
if (in_array('evaluate', get_class_methods($this->xpath))) {
|
||||
$offset = $this->xpath->evaluate("count(preceding-sibling::rss:item)", $entries->item(0));
|
||||
$this->entries[$offset] = $entry;
|
||||
}
|
||||
$this->idMappings[$id] = $entry;
|
||||
return $entry;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of the image associated with the feed.
|
||||
*
|
||||
* @return array|false an array simply containing the child elements
|
||||
*/
|
||||
protected function getImage()
|
||||
{
|
||||
$images = $this->model->getElementsByTagName('image');
|
||||
if ($images->length > 0) {
|
||||
$image = $images->item(0);
|
||||
$details = array();
|
||||
if ($image->hasChildNodes()) {
|
||||
$details = array(
|
||||
'title' => $image->getElementsByTagName('title')->item(0)->value,
|
||||
'link' => $image->getElementsByTagName('link')->item(0)->value,
|
||||
'url' => $image->getElementsByTagName('url')->item(0)->value);
|
||||
} else {
|
||||
$details = array('title' => false,
|
||||
'link' => false,
|
||||
'url' => $image->attributes->getNamedItem('resource')->nodeValue);
|
||||
}
|
||||
$details = array_merge($details, array('description' => false, 'height' => false, 'width' => false));
|
||||
if (! empty($details)) {
|
||||
return $details;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The textinput element is little used, but in the interests of
|
||||
* completeness we will support it.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
protected function getTextInput()
|
||||
{
|
||||
$inputs = $this->model->getElementsByTagName('textinput');
|
||||
if ($inputs->length > 0) {
|
||||
$input = $inputs->item(0);
|
||||
$results = array();
|
||||
$results['title'] = isset(
|
||||
$input->getElementsByTagName('title')->item(0)->value) ?
|
||||
$input->getElementsByTagName('title')->item(0)->value : null;
|
||||
$results['description'] = isset(
|
||||
$input->getElementsByTagName('description')->item(0)->value) ?
|
||||
$input->getElementsByTagName('description')->item(0)->value : null;
|
||||
$results['name'] = isset(
|
||||
$input->getElementsByTagName('name')->item(0)->value) ?
|
||||
$input->getElementsByTagName('name')->item(0)->value : null;
|
||||
$results['link'] = isset(
|
||||
$input->getElementsByTagName('link')->item(0)->value) ?
|
||||
$input->getElementsByTagName('link')->item(0)->value : null;
|
||||
if (empty($results['link']) and
|
||||
$input->attributes->getNamedItem('resource')) {
|
||||
$results['link'] =
|
||||
$input->attributes->getNamedItem('resource')->nodeValue;
|
||||
}
|
||||
if (! empty($results)) {
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Employs various techniques to identify the author
|
||||
*
|
||||
* Dublin Core provides the dc:creator, dc:contributor, and dc:publisher
|
||||
* elements for defining authorship in RSS1. We will try each of those in
|
||||
* turn in order to simulate the atom author element and will return it
|
||||
* as text.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
function getAuthor()
|
||||
{
|
||||
$options = array('creator', 'contributor', 'publisher');
|
||||
foreach ($options as $element) {
|
||||
$test = $this->model->getElementsByTagName($element);
|
||||
if ($test->length > 0) {
|
||||
return $test->item(0)->value;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a link
|
||||
*
|
||||
* In RSS1 a link is a text element but in order to ensure that we resolve
|
||||
* URLs properly we have a special function for them.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getLink($offset = 0, $attribute = 'href', $params = false)
|
||||
{
|
||||
$links = $this->model->getElementsByTagName('link');
|
||||
if ($links->length <= $offset) {
|
||||
return false;
|
||||
}
|
||||
$link = $links->item($offset);
|
||||
return $this->addBase($link->nodeValue, $link);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,274 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* RSS1.1 class for XML_Feed_Parser
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: RSS11.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class handles RSS1.1 feeds. RSS1.1 is documented at:
|
||||
* http://inamidst.com/rss1.1/
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
* @todo Support for RDF:List
|
||||
* @todo Ensure xml:lang is accessible to users
|
||||
*/
|
||||
class XML_Feed_Parser_RSS11 extends XML_Feed_Parser_Type
|
||||
{
|
||||
/**
|
||||
* The URI of the RelaxNG schema used to (optionally) validate the feed
|
||||
* @var string
|
||||
*/
|
||||
protected $relax = 'rss11.rng';
|
||||
|
||||
/**
|
||||
* We're likely to use XPath, so let's keep it global
|
||||
* @var DOMXPath
|
||||
*/
|
||||
protected $xpath;
|
||||
|
||||
/**
|
||||
* The feed type we are parsing
|
||||
* @var string
|
||||
*/
|
||||
public $version = 'RSS 1.0';
|
||||
|
||||
/**
|
||||
* The class used to represent individual items
|
||||
* @var string
|
||||
*/
|
||||
protected $itemClass = 'XML_Feed_Parser_RSS1Element';
|
||||
|
||||
/**
|
||||
* The element containing entries
|
||||
* @var string
|
||||
*/
|
||||
protected $itemElement = 'item';
|
||||
|
||||
/**
|
||||
* Here we map those elements we're not going to handle individually
|
||||
* to the constructs they are. The optional second parameter in the array
|
||||
* tells the parser whether to 'fall back' (not apt. at the feed level) or
|
||||
* fail if the element is missing. If the parameter is not set, the function
|
||||
* will simply return false and leave it to the client to decide what to do.
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'title' => array('Text'),
|
||||
'link' => array('Text'),
|
||||
'description' => array('Text'),
|
||||
'image' => array('Image'),
|
||||
'updatePeriod' => array('Text'),
|
||||
'updateFrequency' => array('Text'),
|
||||
'updateBase' => array('Date'),
|
||||
'rights' => array('Text'), # dc:rights
|
||||
'description' => array('Text'), # dc:description
|
||||
'creator' => array('Text'), # dc:creator
|
||||
'publisher' => array('Text'), # dc:publisher
|
||||
'contributor' => array('Text'), # dc:contributor
|
||||
'date' => array('Date') # dc:contributor
|
||||
);
|
||||
|
||||
/**
|
||||
* Here we map some elements to their atom equivalents. This is going to be
|
||||
* quite tricky to pull off effectively (and some users' methods may vary)
|
||||
* but is worth trying. The key is the atom version, the value is RSS2.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'title' => array('title'),
|
||||
'link' => array('link'),
|
||||
'subtitle' => array('description'),
|
||||
'author' => array('creator'),
|
||||
'updated' => array('date'));
|
||||
|
||||
/**
|
||||
* We will be working with multiple namespaces and it is useful to
|
||||
* keep them together. We will retain support for some common RSS1.0 modules
|
||||
* @var array
|
||||
*/
|
||||
protected $namespaces = array(
|
||||
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
'rss' => 'http://purl.org/net/rss1.1#',
|
||||
'dc' => 'http://purl.org/rss/1.0/modules/dc/',
|
||||
'content' => 'http://purl.org/rss/1.0/modules/content/',
|
||||
'sy' => 'http://web.resource.org/rss/1.0/modules/syndication/');
|
||||
|
||||
/**
|
||||
* Our constructor does nothing more than its parent.
|
||||
*
|
||||
* @param DOMDocument $xml A DOM object representing the feed
|
||||
* @param bool (optional) $string Whether or not to validate this feed
|
||||
*/
|
||||
function __construct(DOMDocument $model, $strict = false)
|
||||
{
|
||||
$this->model = $model;
|
||||
|
||||
if ($strict) {
|
||||
if (! $this->relaxNGValidate()) {
|
||||
throw new XML_Feed_Parser_Exception('Failed required validation');
|
||||
}
|
||||
}
|
||||
|
||||
$this->xpath = new DOMXPath($model);
|
||||
foreach ($this->namespaces as $key => $value) {
|
||||
$this->xpath->registerNamespace($key, $value);
|
||||
}
|
||||
$this->numberEntries = $this->count('item');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to identify an element by ID given by the rdf:about attribute
|
||||
*
|
||||
* This is not really something that will work with RSS1.1 as it does not have
|
||||
* clear restrictions on the global uniqueness of IDs. We will employ the
|
||||
* _very_ hit and miss method of selecting entries based on the rdf:about
|
||||
* attribute. Please note that this is even more hit and miss with RSS1.1 than
|
||||
* with RSS1.0 since RSS1.1 does not require the rdf:about attribute for items.
|
||||
*
|
||||
* @param string $id any valid ID.
|
||||
* @return XML_Feed_Parser_RSS1Element
|
||||
*/
|
||||
function getEntryById($id)
|
||||
{
|
||||
if (isset($this->idMappings[$id])) {
|
||||
return $this->entries[$this->idMappings[$id]];
|
||||
}
|
||||
|
||||
$entries = $this->xpath->query("//rss:item[@rdf:about='$id']");
|
||||
if ($entries->length > 0) {
|
||||
$classname = $this->itemClass;
|
||||
$entry = new $classname($entries->item(0), $this);
|
||||
return $entry;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of the image associated with the feed.
|
||||
*
|
||||
* @return array|false an array simply containing the child elements
|
||||
*/
|
||||
protected function getImage()
|
||||
{
|
||||
$images = $this->model->getElementsByTagName('image');
|
||||
if ($images->length > 0) {
|
||||
$image = $images->item(0);
|
||||
$details = array();
|
||||
if ($image->hasChildNodes()) {
|
||||
$details = array(
|
||||
'title' => $image->getElementsByTagName('title')->item(0)->value,
|
||||
'url' => $image->getElementsByTagName('url')->item(0)->value);
|
||||
if ($image->getElementsByTagName('link')->length > 0) {
|
||||
$details['link'] =
|
||||
$image->getElementsByTagName('link')->item(0)->value;
|
||||
}
|
||||
} else {
|
||||
$details = array('title' => false,
|
||||
'link' => false,
|
||||
'url' => $image->attributes->getNamedItem('resource')->nodeValue);
|
||||
}
|
||||
$details = array_merge($details,
|
||||
array('description' => false, 'height' => false, 'width' => false));
|
||||
if (! empty($details)) {
|
||||
return $details;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The textinput element is little used, but in the interests of
|
||||
* completeness we will support it.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
protected function getTextInput()
|
||||
{
|
||||
$inputs = $this->model->getElementsByTagName('textinput');
|
||||
if ($inputs->length > 0) {
|
||||
$input = $inputs->item(0);
|
||||
$results = array();
|
||||
$results['title'] = isset(
|
||||
$input->getElementsByTagName('title')->item(0)->value) ?
|
||||
$input->getElementsByTagName('title')->item(0)->value : null;
|
||||
$results['description'] = isset(
|
||||
$input->getElementsByTagName('description')->item(0)->value) ?
|
||||
$input->getElementsByTagName('description')->item(0)->value : null;
|
||||
$results['name'] = isset(
|
||||
$input->getElementsByTagName('name')->item(0)->value) ?
|
||||
$input->getElementsByTagName('name')->item(0)->value : null;
|
||||
$results['link'] = isset(
|
||||
$input->getElementsByTagName('link')->item(0)->value) ?
|
||||
$input->getElementsByTagName('link')->item(0)->value : null;
|
||||
if (empty($results['link']) and
|
||||
$input->attributes->getNamedItem('resource')) {
|
||||
$results['link'] = $input->attributes->getNamedItem('resource')->nodeValue;
|
||||
}
|
||||
if (! empty($results)) {
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to discern authorship
|
||||
*
|
||||
* Dublin Core provides the dc:creator, dc:contributor, and dc:publisher
|
||||
* elements for defining authorship in RSS1. We will try each of those in
|
||||
* turn in order to simulate the atom author element and will return it
|
||||
* as text.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
function getAuthor()
|
||||
{
|
||||
$options = array('creator', 'contributor', 'publisher');
|
||||
foreach ($options as $element) {
|
||||
$test = $this->model->getElementsByTagName($element);
|
||||
if ($test->length > 0) {
|
||||
return $test->item(0)->value;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a link
|
||||
*
|
||||
* In RSS1 a link is a text element but in order to ensure that we resolve
|
||||
* URLs properly we have a special function for them.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getLink($offset = 0, $attribute = 'href', $params = false)
|
||||
{
|
||||
$links = $this->model->getElementsByTagName('link');
|
||||
if ($links->length <= $offset) {
|
||||
return false;
|
||||
}
|
||||
$link = $links->item($offset);
|
||||
return $this->addBase($link->nodeValue, $link);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,151 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* RSS1 Element class for XML_Feed_Parser
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: RSS11Element.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class provides support for RSS 1.1 entries. It will usually be called by
|
||||
* XML_Feed_Parser_RSS11 with which it shares many methods.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser_RSS11Element extends XML_Feed_Parser_RSS11
|
||||
{
|
||||
/**
|
||||
* This will be a reference to the parent object for when we want
|
||||
* to use a 'fallback' rule
|
||||
* @var XML_Feed_Parser_RSS1
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Our specific element map
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'id' => array('Id'),
|
||||
'title' => array('Text'),
|
||||
'link' => array('Link'),
|
||||
'description' => array('Text'), # or dc:description
|
||||
'category' => array('Category'),
|
||||
'rights' => array('Text'), # dc:rights
|
||||
'creator' => array('Text'), # dc:creator
|
||||
'publisher' => array('Text'), # dc:publisher
|
||||
'contributor' => array('Text'), # dc:contributor
|
||||
'date' => array('Date'), # dc:date
|
||||
'content' => array('Content')
|
||||
);
|
||||
|
||||
/**
|
||||
* Here we map some elements to their atom equivalents. This is going to be
|
||||
* quite tricky to pull off effectively (and some users' methods may vary)
|
||||
* but is worth trying. The key is the atom version, the value is RSS1.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'content' => array('content'),
|
||||
'updated' => array('lastBuildDate'),
|
||||
'published' => array('date'),
|
||||
'subtitle' => array('description'),
|
||||
'updated' => array('date'),
|
||||
'author' => array('creator'),
|
||||
'contributor' => array('contributor')
|
||||
);
|
||||
|
||||
/**
|
||||
* Store useful information for later.
|
||||
*
|
||||
* @param DOMElement $element - this item as a DOM element
|
||||
* @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member
|
||||
*/
|
||||
function __construct(DOMElement $element, $parent, $xmlBase = '')
|
||||
{
|
||||
$this->model = $element;
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* If an rdf:about attribute is specified, return that as an ID
|
||||
*
|
||||
* There is no established way of showing an ID for an RSS1 entry. We will
|
||||
* simulate it using the rdf:about attribute of the entry element. This cannot
|
||||
* be relied upon for unique IDs but may prove useful.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
function getId()
|
||||
{
|
||||
if ($this->model->attributes->getNamedItem('about')) {
|
||||
return $this->model->attributes->getNamedItem('about')->nodeValue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entry's content
|
||||
*
|
||||
* The official way to include full content in an RSS1 entry is to use
|
||||
* the content module's element 'encoded'. Often, however, the 'description'
|
||||
* element is used instead. We will offer that as a fallback.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
function getContent()
|
||||
{
|
||||
$options = array('encoded', 'description');
|
||||
foreach ($options as $element) {
|
||||
$test = $this->model->getElementsByTagName($element);
|
||||
if ($test->length == 0) {
|
||||
continue;
|
||||
}
|
||||
if ($test->item(0)->hasChildNodes()) {
|
||||
$value = '';
|
||||
foreach ($test->item(0)->childNodes as $child) {
|
||||
if ($child instanceof DOMText) {
|
||||
$value .= $child->nodeValue;
|
||||
} else {
|
||||
$simple = simplexml_import_dom($child);
|
||||
$value .= $simple->asXML();
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
} elseif ($test->length > 0) {
|
||||
return $test->item(0)->nodeValue;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* How RSS1.1 should support for enclosures is not clear. For now we will return
|
||||
* false.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
function getEnclosure()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* RSS1 Element class for XML_Feed_Parser
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: RSS1Element.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class provides support for RSS 1.0 entries. It will usually be called by
|
||||
* XML_Feed_Parser_RSS1 with which it shares many methods.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser_RSS1Element extends XML_Feed_Parser_RSS1
|
||||
{
|
||||
/**
|
||||
* This will be a reference to the parent object for when we want
|
||||
* to use a 'fallback' rule
|
||||
* @var XML_Feed_Parser_RSS1
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Our specific element map
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'id' => array('Id'),
|
||||
'title' => array('Text'),
|
||||
'link' => array('Link'),
|
||||
'description' => array('Text'), # or dc:description
|
||||
'category' => array('Category'),
|
||||
'rights' => array('Text'), # dc:rights
|
||||
'creator' => array('Text'), # dc:creator
|
||||
'publisher' => array('Text'), # dc:publisher
|
||||
'contributor' => array('Text'), # dc:contributor
|
||||
'date' => array('Date'), # dc:date
|
||||
'content' => array('Content')
|
||||
);
|
||||
|
||||
/**
|
||||
* Here we map some elements to their atom equivalents. This is going to be
|
||||
* quite tricky to pull off effectively (and some users' methods may vary)
|
||||
* but is worth trying. The key is the atom version, the value is RSS1.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'content' => array('content'),
|
||||
'updated' => array('lastBuildDate'),
|
||||
'published' => array('date'),
|
||||
'subtitle' => array('description'),
|
||||
'updated' => array('date'),
|
||||
'author' => array('creator'),
|
||||
'contributor' => array('contributor')
|
||||
);
|
||||
|
||||
/**
|
||||
* Store useful information for later.
|
||||
*
|
||||
* @param DOMElement $element - this item as a DOM element
|
||||
* @param XML_Feed_Parser_RSS1 $parent - the feed of which this is a member
|
||||
*/
|
||||
function __construct(DOMElement $element, $parent, $xmlBase = '')
|
||||
{
|
||||
$this->model = $element;
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* If an rdf:about attribute is specified, return it as an ID
|
||||
*
|
||||
* There is no established way of showing an ID for an RSS1 entry. We will
|
||||
* simulate it using the rdf:about attribute of the entry element. This cannot
|
||||
* be relied upon for unique IDs but may prove useful.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
function getId()
|
||||
{
|
||||
if ($this->model->attributes->getNamedItem('about')) {
|
||||
return $this->model->attributes->getNamedItem('about')->nodeValue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* How RSS1 should support for enclosures is not clear. For now we will return
|
||||
* false.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
function getEnclosure()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,334 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Class representing feed-level data for an RSS2 feed
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: RSS2.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class handles RSS2 feeds.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser_RSS2 extends XML_Feed_Parser_Type
|
||||
{
|
||||
/**
|
||||
* The URI of the RelaxNG schema used to (optionally) validate the feed
|
||||
* @var string
|
||||
*/
|
||||
protected $relax = 'rss20.rng';
|
||||
|
||||
/**
|
||||
* We're likely to use XPath, so let's keep it global
|
||||
* @var DOMXPath
|
||||
*/
|
||||
protected $xpath;
|
||||
|
||||
/**
|
||||
* The feed type we are parsing
|
||||
* @var string
|
||||
*/
|
||||
public $version = 'RSS 2.0';
|
||||
|
||||
/**
|
||||
* The class used to represent individual items
|
||||
* @var string
|
||||
*/
|
||||
protected $itemClass = 'XML_Feed_Parser_RSS2Element';
|
||||
|
||||
/**
|
||||
* The element containing entries
|
||||
* @var string
|
||||
*/
|
||||
protected $itemElement = 'item';
|
||||
|
||||
/**
|
||||
* Here we map those elements we're not going to handle individually
|
||||
* to the constructs they are. The optional second parameter in the array
|
||||
* tells the parser whether to 'fall back' (not apt. at the feed level) or
|
||||
* fail if the element is missing. If the parameter is not set, the function
|
||||
* will simply return false and leave it to the client to decide what to do.
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'ttl' => array('Text'),
|
||||
'pubDate' => array('Date'),
|
||||
'lastBuildDate' => array('Date'),
|
||||
'title' => array('Text'),
|
||||
'link' => array('Link'),
|
||||
'description' => array('Text'),
|
||||
'language' => array('Text'),
|
||||
'copyright' => array('Text'),
|
||||
'managingEditor' => array('Text'),
|
||||
'webMaster' => array('Text'),
|
||||
'category' => array('Text'),
|
||||
'generator' => array('Text'),
|
||||
'docs' => array('Text'),
|
||||
'ttl' => array('Text'),
|
||||
'image' => array('Image'),
|
||||
'skipDays' => array('skipDays'),
|
||||
'skipHours' => array('skipHours'));
|
||||
|
||||
/**
|
||||
* Here we map some elements to their atom equivalents. This is going to be
|
||||
* quite tricky to pull off effectively (and some users' methods may vary)
|
||||
* but is worth trying. The key is the atom version, the value is RSS2.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'title' => array('title'),
|
||||
'rights' => array('copyright'),
|
||||
'updated' => array('lastBuildDate'),
|
||||
'subtitle' => array('description'),
|
||||
'date' => array('pubDate'),
|
||||
'author' => array('managingEditor'));
|
||||
|
||||
protected $namespaces = array(
|
||||
'dc' => 'http://purl.org/rss/1.0/modules/dc/',
|
||||
'content' => 'http://purl.org/rss/1.0/modules/content/');
|
||||
|
||||
/**
|
||||
* Our constructor does nothing more than its parent.
|
||||
*
|
||||
* @param DOMDocument $xml A DOM object representing the feed
|
||||
* @param bool (optional) $string Whether or not to validate this feed
|
||||
*/
|
||||
function __construct(DOMDocument $model, $strict = false)
|
||||
{
|
||||
$this->model = $model;
|
||||
|
||||
if ($strict) {
|
||||
if (! $this->relaxNGValidate()) {
|
||||
throw new XML_Feed_Parser_Exception('Failed required validation');
|
||||
}
|
||||
}
|
||||
|
||||
$this->xpath = new DOMXPath($this->model);
|
||||
foreach ($this->namespaces as $key => $value) {
|
||||
$this->xpath->registerNamespace($key, $value);
|
||||
}
|
||||
$this->numberEntries = $this->count('item');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an entry by ID, if the ID is specified with the guid element
|
||||
*
|
||||
* This is not really something that will work with RSS2 as it does not have
|
||||
* clear restrictions on the global uniqueness of IDs. But we can emulate
|
||||
* it by allowing access based on the 'guid' element. If DOMXPath::evaluate
|
||||
* is available, we also use that to store a reference to the entry in the array
|
||||
* used by getEntryByOffset so that method does not have to seek out the entry
|
||||
* if it's requested that way.
|
||||
*
|
||||
* @param string $id any valid ID.
|
||||
* @return XML_Feed_Parser_RSS2Element
|
||||
*/
|
||||
function getEntryById($id)
|
||||
{
|
||||
if (isset($this->idMappings[$id])) {
|
||||
return $this->entries[$this->idMappings[$id]];
|
||||
}
|
||||
|
||||
$entries = $this->xpath->query("//item[guid='$id']");
|
||||
if ($entries->length > 0) {
|
||||
$entry = new $this->itemElement($entries->item(0), $this);
|
||||
if (in_array('evaluate', get_class_methods($this->xpath))) {
|
||||
$offset = $this->xpath->evaluate("count(preceding-sibling::item)", $entries->item(0));
|
||||
$this->entries[$offset] = $entry;
|
||||
}
|
||||
$this->idMappings[$id] = $entry;
|
||||
return $entry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a category from the element
|
||||
*
|
||||
* The category element is a simple text construct which can occur any number
|
||||
* of times. We allow access by offset or access to an array of results.
|
||||
*
|
||||
* @param string $call for compatibility with our overloading
|
||||
* @param array $arguments - arg 0 is the offset, arg 1 is whether to return as array
|
||||
* @return string|array|false
|
||||
*/
|
||||
function getCategory($call, $arguments = array())
|
||||
{
|
||||
$categories = $this->model->getElementsByTagName('category');
|
||||
$offset = empty($arguments[0]) ? 0 : $arguments[0];
|
||||
$array = empty($arguments[1]) ? false : true;
|
||||
if ($categories->length <= $offset) {
|
||||
return false;
|
||||
}
|
||||
if ($array) {
|
||||
$list = array();
|
||||
foreach ($categories as $category) {
|
||||
array_push($list, $category->nodeValue);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
return $categories->item($offset)->nodeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of the image associated with the feed.
|
||||
*
|
||||
* @return array|false an array simply containing the child elements
|
||||
*/
|
||||
protected function getImage()
|
||||
{
|
||||
$images = $this->xpath->query("//image");
|
||||
if ($images->length > 0) {
|
||||
$image = $images->item(0);
|
||||
$desc = $image->getElementsByTagName('description');
|
||||
$description = $desc->length ? $desc->item(0)->nodeValue : false;
|
||||
$heigh = $image->getElementsByTagName('height');
|
||||
$height = $heigh->length ? $heigh->item(0)->nodeValue : false;
|
||||
$widt = $image->getElementsByTagName('width');
|
||||
$width = $widt->length ? $widt->item(0)->nodeValue : false;
|
||||
return array(
|
||||
'title' => $image->getElementsByTagName('title')->item(0)->nodeValue,
|
||||
'link' => $image->getElementsByTagName('link')->item(0)->nodeValue,
|
||||
'url' => $image->getElementsByTagName('url')->item(0)->nodeValue,
|
||||
'description' => $description,
|
||||
'height' => $height,
|
||||
'width' => $width);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The textinput element is little used, but in the interests of
|
||||
* completeness...
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
function getTextInput()
|
||||
{
|
||||
$inputs = $this->model->getElementsByTagName('input');
|
||||
if ($inputs->length > 0) {
|
||||
$input = $inputs->item(0);
|
||||
return array(
|
||||
'title' => $input->getElementsByTagName('title')->item(0)->value,
|
||||
'description' =>
|
||||
$input->getElementsByTagName('description')->item(0)->value,
|
||||
'name' => $input->getElementsByTagName('name')->item(0)->value,
|
||||
'link' => $input->getElementsByTagName('link')->item(0)->value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for getSkipDays and getSkipHours
|
||||
*
|
||||
* This is a general function used by both getSkipDays and getSkipHours. It simply
|
||||
* returns an array of the values of the children of the appropriate tag.
|
||||
*
|
||||
* @param string $tagName The tag name (getSkipDays or getSkipHours)
|
||||
* @return array|false
|
||||
*/
|
||||
protected function getSkips($tagName)
|
||||
{
|
||||
$hours = $this->model->getElementsByTagName($tagName);
|
||||
if ($hours->length == 0) {
|
||||
return false;
|
||||
}
|
||||
$skipHours = array();
|
||||
foreach($hours->item(0)->childNodes as $hour) {
|
||||
if ($hour instanceof DOMElement) {
|
||||
array_push($skipHours, $hour->nodeValue);
|
||||
}
|
||||
}
|
||||
return $skipHours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve skipHours data
|
||||
*
|
||||
* The skiphours element provides a list of hours on which this feed should
|
||||
* not be checked. We return an array of those hours (integers, 24 hour clock)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getSkipHours()
|
||||
{
|
||||
return $this->getSkips('skipHours');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve skipDays data
|
||||
*
|
||||
* The skipdays element provides a list of days on which this feed should
|
||||
* not be checked. We return an array of those days.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getSkipDays()
|
||||
{
|
||||
return $this->getSkips('skipDays');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return content of the little-used 'cloud' element
|
||||
*
|
||||
* The cloud element is rarely used. It is designed to provide some details
|
||||
* of a location to update the feed.
|
||||
*
|
||||
* @return array an array of the attributes of the element
|
||||
*/
|
||||
function getCloud()
|
||||
{
|
||||
$cloud = $this->model->getElementsByTagName('cloud');
|
||||
if ($cloud->length == 0) {
|
||||
return false;
|
||||
}
|
||||
$cloudData = array();
|
||||
foreach ($cloud->item(0)->attributes as $attribute) {
|
||||
$cloudData[$attribute->name] = $attribute->value;
|
||||
}
|
||||
return $cloudData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get link URL
|
||||
*
|
||||
* In RSS2 a link is a text element but in order to ensure that we resolve
|
||||
* URLs properly we have a special function for them. We maintain the
|
||||
* parameter used by the atom getLink method, though we only use the offset
|
||||
* parameter.
|
||||
*
|
||||
* @param int $offset The position of the link within the feed. Starts from 0
|
||||
* @param string $attribute The attribute of the link element required
|
||||
* @param array $params An array of other parameters. Not used.
|
||||
* @return string
|
||||
*/
|
||||
function getLink($offset, $attribute = 'href', $params = array())
|
||||
{
|
||||
$links = $this->model->getElementsByTagName('link');
|
||||
|
||||
if ($links->length <= $offset) {
|
||||
return false;
|
||||
}
|
||||
$link = $links->item($offset);
|
||||
return $this->addBase($link->nodeValue, $link);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,171 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Class representing entries in an RSS2 feed.
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: RSS2Element.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class provides support for RSS 2.0 entries. It will usually be
|
||||
* called by XML_Feed_Parser_RSS2 with which it shares many methods.
|
||||
*
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
* @package XML_Feed_Parser
|
||||
*/
|
||||
class XML_Feed_Parser_RSS2Element extends XML_Feed_Parser_RSS2
|
||||
{
|
||||
/**
|
||||
* This will be a reference to the parent object for when we want
|
||||
* to use a 'fallback' rule
|
||||
* @var XML_Feed_Parser_RSS2
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Our specific element map
|
||||
* @var array
|
||||
*/
|
||||
protected $map = array(
|
||||
'title' => array('Text'),
|
||||
'guid' => array('Guid'),
|
||||
'description' => array('Text'),
|
||||
'author' => array('Text'),
|
||||
'comments' => array('Text'),
|
||||
'enclosure' => array('Enclosure'),
|
||||
'pubDate' => array('Date'),
|
||||
'source' => array('Source'),
|
||||
'link' => array('Text'),
|
||||
'content' => array('Content'));
|
||||
|
||||
/**
|
||||
* Here we map some elements to their atom equivalents. This is going to be
|
||||
* quite tricky to pull off effectively (and some users' methods may vary)
|
||||
* but is worth trying. The key is the atom version, the value is RSS2.
|
||||
* @var array
|
||||
*/
|
||||
protected $compatMap = array(
|
||||
'id' => array('guid'),
|
||||
'updated' => array('lastBuildDate'),
|
||||
'published' => array('pubdate'),
|
||||
'guidislink' => array('guid', 'ispermalink'),
|
||||
'summary' => array('description'));
|
||||
|
||||
/**
|
||||
* Store useful information for later.
|
||||
*
|
||||
* @param DOMElement $element - this item as a DOM element
|
||||
* @param XML_Feed_Parser_RSS2 $parent - the feed of which this is a member
|
||||
*/
|
||||
function __construct(DOMElement $element, $parent, $xmlBase = '')
|
||||
{
|
||||
$this->model = $element;
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the guid element, if specified
|
||||
*
|
||||
* guid is the closest RSS2 has to atom's ID. It is usually but not always a
|
||||
* URI. The one attribute that RSS2 can posess is 'ispermalink' which specifies
|
||||
* whether the guid is itself dereferencable. Use of guid is not obligatory,
|
||||
* but is advisable. To get the guid you would call $item->id() (for atom
|
||||
* compatibility) or $item->guid(). To check if this guid is a permalink call
|
||||
* $item->guid("ispermalink").
|
||||
*
|
||||
* @param string $method - the method name being called
|
||||
* @param array $params - parameters required
|
||||
* @return string the guid or value of ispermalink
|
||||
*/
|
||||
protected function getGuid($method, $params)
|
||||
{
|
||||
$attribute = (isset($params[0]) and $params[0] == 'ispermalink') ?
|
||||
true : false;
|
||||
$tag = $this->model->getElementsByTagName('guid');
|
||||
if ($tag->length > 0) {
|
||||
if ($attribute) {
|
||||
if ($tag->hasAttribute("ispermalink")) {
|
||||
return $tag->getAttribute("ispermalink");
|
||||
}
|
||||
}
|
||||
return $tag->item(0)->nodeValue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access details of file enclosures
|
||||
*
|
||||
* The RSS2 spec is ambiguous as to whether an enclosure element must be
|
||||
* unique in a given entry. For now we will assume it needn't, and allow
|
||||
* for an offset.
|
||||
*
|
||||
* @param string $method - the method being called
|
||||
* @param array $parameters - we expect the first of these to be our offset
|
||||
* @return array|false
|
||||
*/
|
||||
protected function getEnclosure($method, $parameters)
|
||||
{
|
||||
$encs = $this->model->getElementsByTagName('enclosure');
|
||||
$offset = isset($parameters[0]) ? $parameters[0] : 0;
|
||||
if ($encs->length > $offset) {
|
||||
try {
|
||||
if (! $encs->item($offset)->hasAttribute('url')) {
|
||||
return false;
|
||||
}
|
||||
$attrs = $encs->item($offset)->attributes;
|
||||
return array(
|
||||
'url' => $attrs->getNamedItem('url')->value,
|
||||
'length' => $attrs->getNamedItem('length')->value,
|
||||
'type' => $attrs->getNamedItem('type')->value);
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entry source if specified
|
||||
*
|
||||
* source is an optional sub-element of item. Like atom:source it tells
|
||||
* us about where the entry came from (eg. if it's been copied from another
|
||||
* feed). It is not a rich source of metadata in the same way as atom:source
|
||||
* and while it would be good to maintain compatibility by returning an
|
||||
* XML_Feed_Parser_RSS2 element, it makes a lot more sense to return an array.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
protected function getSource()
|
||||
{
|
||||
$get = $this->model->getElementsByTagName('source');
|
||||
if ($get->length) {
|
||||
$source = $get->item(0);
|
||||
$array = array(
|
||||
'content' => $source->nodeValue);
|
||||
foreach ($source->attributes as $attribute) {
|
||||
$array[$attribute->name] = $attribute->value;
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,475 +0,0 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Abstract class providing common methods for XML_Feed_Parser feeds.
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category XML
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @copyright 2005 James Stewart <james@jystewart.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL 2.1
|
||||
* @version CVS: $Id: Type.php 6844 2011-06-03 14:46:51Z dMetzger $
|
||||
* @link http://pear.php.net/package/XML_Feed_Parser/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This abstract class provides some general methods that are likely to be
|
||||
* implemented exactly the same way for all feed types.
|
||||
*
|
||||
* @package XML_Feed_Parser
|
||||
* @author James Stewart <james@jystewart.net>
|
||||
* @version Release: @package_version@
|
||||
*/
|
||||
abstract class XML_Feed_Parser_Type
|
||||
{
|
||||
/**
|
||||
* Where we store our DOM object for this feed
|
||||
* @var DOMDocument
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* For iteration we'll want a count of the number of entries
|
||||
* @var int
|
||||
*/
|
||||
public $numberEntries;
|
||||
|
||||
/**
|
||||
* Where we store our entry objects once instantiated
|
||||
* @var array
|
||||
*/
|
||||
public $entries = array();
|
||||
|
||||
/**
|
||||
* Store mappings between entry IDs and their position in the feed
|
||||
*/
|
||||
public $idMappings = array();
|
||||
|
||||
/**
|
||||
* Proxy to allow use of element names as method names
|
||||
*
|
||||
* We are not going to provide methods for every entry type so this
|
||||
* function will allow for a lot of mapping. We rely pretty heavily
|
||||
* on this to handle our mappings between other feed types and atom.
|
||||
*
|
||||
* @param string $call - the method attempted
|
||||
* @param array $arguments - arguments to that method
|
||||
* @return mixed
|
||||
*/
|
||||
function __call($call, $arguments = array())
|
||||
{
|
||||
if (! is_array($arguments)) {
|
||||
$arguments = array();
|
||||
}
|
||||
|
||||
if (isset($this->compatMap[$call])) {
|
||||
$tempMap = $this->compatMap;
|
||||
$tempcall = array_pop($tempMap[$call]);
|
||||
if (! empty($tempMap)) {
|
||||
$arguments = array_merge($arguments, $tempMap[$call]);
|
||||
}
|
||||
$call = $tempcall;
|
||||
}
|
||||
|
||||
/* To be helpful, we allow a case-insensitive search for this method */
|
||||
if (! isset($this->map[$call])) {
|
||||
foreach (array_keys($this->map) as $key) {
|
||||
if (strtoupper($key) == strtoupper($call)) {
|
||||
$call = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->map[$call])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$method = 'get' . $this->map[$call][0];
|
||||
if ($method == 'getLink') {
|
||||
$offset = empty($arguments[0]) ? 0 : $arguments[0];
|
||||
$attribute = empty($arguments[1]) ? 'href' : $arguments[1];
|
||||
$params = isset($arguments[2]) ? $arguments[2] : array();
|
||||
return $this->getLink($offset, $attribute, $params);
|
||||
}
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->$method($call, $arguments);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy to allow use of element names as attribute names
|
||||
*
|
||||
* For many elements variable-style access will be desirable. This function
|
||||
* provides for that.
|
||||
*
|
||||
* @param string $value - the variable required
|
||||
* @return mixed
|
||||
*/
|
||||
function __get($value)
|
||||
{
|
||||
return $this->__call($value, array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to help us resolve xml:base values
|
||||
*
|
||||
* We have other methods which will traverse the DOM and work out the different
|
||||
* xml:base declarations we need to be aware of. We then need to combine them.
|
||||
* If a declaration starts with a protocol then we restart the string. If it
|
||||
* starts with a / then we add on to the domain name. Otherwise we simply tag
|
||||
* it on to the end.
|
||||
*
|
||||
* @param string $base - the base to add the link to
|
||||
* @param string $link
|
||||
*/
|
||||
function combineBases($base, $link)
|
||||
{
|
||||
if (preg_match('/^[A-Za-z]+:\/\//', $link)) {
|
||||
return $link;
|
||||
} elseif (preg_match('/^\//', $link)) {
|
||||
/* Extract domain and suffix link to that */
|
||||
preg_match('/^([A-Za-z]+:\/\/.*)?\/*/', $base, $results);
|
||||
$firstLayer = $results[0];
|
||||
return $firstLayer . "/" . $link;
|
||||
} elseif (preg_match('/^\.\.\//', $base)) {
|
||||
/* Step up link to find place to be */
|
||||
preg_match('/^((\.\.\/)+)(.*)$/', $link, $bases);
|
||||
$suffix = $bases[3];
|
||||
$count = preg_match_all('/\.\.\//', $bases[1], $steps);
|
||||
$url = explode("/", $base);
|
||||
for ($i = 0; $i <= $count; $i++) {
|
||||
array_pop($url);
|
||||
}
|
||||
return implode("/", $url) . "/" . $suffix;
|
||||
} elseif (preg_match('/^(?!\/$)/', $base)) {
|
||||
$base = preg_replace('/(.*\/).*$/', '$1', $base) ;
|
||||
return $base . $link;
|
||||
} else {
|
||||
/* Just stick it on the end */
|
||||
return $base . $link;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether we need to apply our xml:base rules
|
||||
*
|
||||
* Gets us the xml:base data and then processes that with regard
|
||||
* to our current link.
|
||||
*
|
||||
* @param string
|
||||
* @param DOMElement
|
||||
* @return string
|
||||
*/
|
||||
function addBase($link, $element)
|
||||
{
|
||||
if (preg_match('/^[A-Za-z]+:\/\//', $link)) {
|
||||
return $link;
|
||||
}
|
||||
|
||||
return $this->combineBases($element->baseURI, $link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an entry by its position in the feed, starting from zero
|
||||
*
|
||||
* As well as allowing the items to be iterated over we want to allow
|
||||
* users to be able to access a specific entry. This is one of two ways of
|
||||
* doing that, the other being by ID.
|
||||
*
|
||||
* @param int $offset
|
||||
* @return XML_Feed_Parser_RSS1Element
|
||||
*/
|
||||
function getEntryByOffset($offset)
|
||||
{
|
||||
if (! isset($this->entries[$offset])) {
|
||||
$entries = $this->model->getElementsByTagName($this->itemElement);
|
||||
if ($entries->length > $offset) {
|
||||
$xmlBase = $entries->item($offset)->baseURI;
|
||||
$this->entries[$offset] = new $this->itemClass(
|
||||
$entries->item($offset), $this, $xmlBase);
|
||||
if ($id = $this->entries[$offset]->id) {
|
||||
$this->idMappings[$id] = $this->entries[$offset];
|
||||
}
|
||||
} else {
|
||||
throw new XML_Feed_Parser_Exception('No entries found');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->entries[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a date in seconds since epoch.
|
||||
*
|
||||
* Get a date construct. We use PHP's strtotime to return it as a unix datetime, which
|
||||
* is the number of seconds since 1970-01-01 00:00:00.
|
||||
*
|
||||
* @link http://php.net/strtotime
|
||||
* @param string $method The name of the date construct we want
|
||||
* @param array $arguments Included for compatibility with our __call usage
|
||||
* @return int|false datetime
|
||||
*/
|
||||
protected function getDate($method, $arguments)
|
||||
{
|
||||
$time = $this->model->getElementsByTagName($method);
|
||||
if ($time->length == 0 || empty($time->item(0)->nodeValue)) {
|
||||
return false;
|
||||
}
|
||||
return strtotime($time->item(0)->nodeValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a text construct.
|
||||
*
|
||||
* @param string $method The name of the text construct we want
|
||||
* @param array $arguments Included for compatibility with our __call usage
|
||||
* @return string
|
||||
*/
|
||||
protected function getText($method, $arguments = array())
|
||||
{
|
||||
$tags = $this->model->getElementsByTagName($method);
|
||||
if ($tags->length > 0) {
|
||||
$value = $tags->item(0)->nodeValue;
|
||||
return $value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply various rules to retrieve category data.
|
||||
*
|
||||
* There is no single way of declaring a category in RSS1/1.1 as there is in RSS2
|
||||
* and Atom. Instead the usual approach is to use the dublin core namespace to
|
||||
* declare categories. For example delicious use both:
|
||||
* <dc:subject>PEAR</dc:subject> and: <taxo:topics><rdf:Bag>
|
||||
* <rdf:li resource="http://del.icio.us/tag/PEAR" /></rdf:Bag></taxo:topics>
|
||||
* to declare a categorisation of 'PEAR'.
|
||||
*
|
||||
* We need to be sensitive to this where possible.
|
||||
*
|
||||
* @param string $call for compatibility with our overloading
|
||||
* @param array $arguments - arg 0 is the offset, arg 1 is whether to return as array
|
||||
* @return string|array|false
|
||||
*/
|
||||
protected function getCategory($call, $arguments)
|
||||
{
|
||||
$categories = $this->model->getElementsByTagName('subject');
|
||||
$offset = empty($arguments[0]) ? 0 : $arguments[0];
|
||||
$array = empty($arguments[1]) ? false : true;
|
||||
if ($categories->length <= $offset) {
|
||||
return false;
|
||||
}
|
||||
if ($array) {
|
||||
$list = array();
|
||||
foreach ($categories as $category) {
|
||||
array_push($list, $category->nodeValue);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
return $categories->item($offset)->nodeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count occurrences of an element
|
||||
*
|
||||
* This function will tell us how many times the element $type
|
||||
* appears at this level of the feed.
|
||||
*
|
||||
* @param string $type the element we want to get a count of
|
||||
* @return int
|
||||
*/
|
||||
protected function count($type)
|
||||
{
|
||||
if ($tags = $this->model->getElementsByTagName($type)) {
|
||||
return $tags->length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of our xml:base processing code
|
||||
*
|
||||
* We need a couple of methods to access XHTML content stored in feeds.
|
||||
* This is because we dereference all xml:base references before returning
|
||||
* the element. This method handles the attributes.
|
||||
*
|
||||
* @param DOMElement $node The DOM node we are iterating over
|
||||
* @return string
|
||||
*/
|
||||
function processXHTMLAttributes($node) {
|
||||
$return = '';
|
||||
foreach ($node->attributes as $attribute) {
|
||||
if ($attribute->name == 'src' or $attribute->name == 'href') {
|
||||
$attribute->value = $this->addBase(htmlentities($attribute->value, null, 'utf-8'), $attribute);
|
||||
}
|
||||
if ($attribute->name == 'base') {
|
||||
continue;
|
||||
}
|
||||
$return .= $attribute->name . '="' . htmlentities($attribute->value, null, 'utf-8') .'" ';
|
||||
}
|
||||
if (! empty($return)) {
|
||||
return ' ' . trim($return);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML entities based on the current character set.
|
||||
*
|
||||
* @param String
|
||||
* @return String
|
||||
*/
|
||||
function processEntitiesForNodeValue($node)
|
||||
{
|
||||
if (function_exists('iconv')) {
|
||||
$current_encoding = $node->ownerDocument->encoding;
|
||||
$value = iconv($current_encoding, 'UTF-8', $node->nodeValue);
|
||||
} elseif ($current_encoding == 'iso-8859-1') {
|
||||
$value = utf8_encode($node->nodeValue);
|
||||
} else {
|
||||
$value = $node->nodeValue;
|
||||
}
|
||||
|
||||
$decoded = html_entity_decode($value, null, 'UTF-8');
|
||||
return htmlentities($decoded, null, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of our xml:base processing code
|
||||
*
|
||||
* We need a couple of methods to access XHTML content stored in feeds.
|
||||
* This is because we dereference all xml:base references before returning
|
||||
* the element. This method recurs through the tree descending from the node
|
||||
* and builds our string.
|
||||
*
|
||||
* @param DOMElement $node The DOM node we are processing
|
||||
* @return string
|
||||
*/
|
||||
function traverseNode($node)
|
||||
{
|
||||
$content = '';
|
||||
|
||||
/* Add the opening of this node to the content */
|
||||
if ($node instanceof DOMElement) {
|
||||
$content .= '<' . $node->tagName .
|
||||
$this->processXHTMLAttributes($node) . '>';
|
||||
}
|
||||
|
||||
/* Process children */
|
||||
if ($node->hasChildNodes()) {
|
||||
foreach ($node->childNodes as $child) {
|
||||
$content .= $this->traverseNode($child);
|
||||
}
|
||||
}
|
||||
|
||||
if ($node instanceof DOMText) {
|
||||
$content .= $this->processEntitiesForNodeValue($node);
|
||||
}
|
||||
|
||||
/* Add the closing of this node to the content */
|
||||
if ($node instanceof DOMElement) {
|
||||
$content .= '</' . $node->tagName . '>';
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content from RSS feeds (atom has its own implementation)
|
||||
*
|
||||
* The official way to include full content in an RSS1 entry is to use
|
||||
* the content module's element 'encoded', and RSS2 feeds often duplicate that.
|
||||
* Often, however, the 'description' element is used instead. We will offer that
|
||||
* as a fallback. Atom uses its own approach and overrides this method.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
protected function getContent()
|
||||
{
|
||||
$options = array('encoded', 'description');
|
||||
foreach ($options as $element) {
|
||||
$test = $this->model->getElementsByTagName($element);
|
||||
if ($test->length == 0) {
|
||||
continue;
|
||||
}
|
||||
if ($test->item(0)->hasChildNodes()) {
|
||||
$value = '';
|
||||
foreach ($test->item(0)->childNodes as $child) {
|
||||
if ($child instanceof DOMText) {
|
||||
$value .= $child->nodeValue;
|
||||
} else {
|
||||
$simple = simplexml_import_dom($child);
|
||||
$value .= $simple->asXML();
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
} elseif ($test->length > 0) {
|
||||
return $test->item(0)->nodeValue;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this element has a particular child element.
|
||||
*
|
||||
* @param String
|
||||
* @param Integer
|
||||
* @return bool
|
||||
**/
|
||||
function hasKey($name, $offset = 0)
|
||||
{
|
||||
$search = $this->model->getElementsByTagName($name);
|
||||
return $search->length > $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an XML serialization of the feed, should it be required. Most
|
||||
* users however, will already have a serialization that they used when
|
||||
* instantiating the object.
|
||||
*
|
||||
* @return string XML serialization of element
|
||||
*/
|
||||
function __toString()
|
||||
{
|
||||
$simple = simplexml_import_dom($this->model);
|
||||
return $simple->asXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get directory holding RNG schemas. Method is based on that
|
||||
* found in Contact_AddressBook.
|
||||
*
|
||||
* @return string PEAR data directory.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
static function getSchemaDir()
|
||||
{
|
||||
require_once 'PEAR/Config.php';
|
||||
$config = new PEAR_Config;
|
||||
return $config->get('data_dir') . '/XML_Feed_Parser/schemas';
|
||||
}
|
||||
|
||||
public function relaxNGValidate() {
|
||||
$dir = self::getSchemaDir();
|
||||
|
||||
$path = $dir . '/' . $this->relax;
|
||||
|
||||
return $this->model->relaxNGValidate($path);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* 2007-2017 PrestaShop
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License (AFL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* http://opensource.org/licenses/afl-3.0.php
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2017 PrestaShop SA
|
||||
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
|
||||
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
header("Location: ../");
|
||||
exit;
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* 2007-2017 PrestaShop
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License (AFL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* http://opensource.org/licenses/afl-3.0.php
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2017 PrestaShop SA
|
||||
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
|
||||
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
header("Location: ../");
|
||||
exit;
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user