first commit

This commit is contained in:
alazhar
2020-01-02 23:15:16 +07:00
commit eda9661806
3433 changed files with 595883 additions and 0 deletions

View File

@ -0,0 +1,157 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Manages all author-related data
*
* Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
*
* This class can be overloaded with {@see SimplePie::set_author_class()}
*
* @package SimplePie
* @subpackage API
*/
class SimplePie_Author
{
/**
* Author's name
*
* @var string
* @see get_name()
*/
var $name;
/**
* Author's link
*
* @var string
* @see get_link()
*/
var $link;
/**
* Author's email address
*
* @var string
* @see get_email()
*/
var $email;
/**
* Constructor, used to input the data
*
* @param string $name
* @param string $link
* @param string $email
*/
public function __construct($name = null, $link = null, $email = null)
{
$this->name = $name;
$this->link = $link;
$this->email = $email;
}
/**
* String-ified version
*
* @return string
*/
public function __toString()
{
// There is no $this->data here
return md5(serialize($this));
}
/**
* Author's name
*
* @return string|null
*/
public function get_name()
{
if ($this->name !== null)
{
return $this->name;
}
else
{
return null;
}
}
/**
* Author's link
*
* @return string|null
*/
public function get_link()
{
if ($this->link !== null)
{
return $this->link;
}
else
{
return null;
}
}
/**
* Author's email address
*
* @return string|null
*/
public function get_email()
{
if ($this->email !== null)
{
return $this->email;
}
else
{
return null;
}
}
}

View File

@ -0,0 +1,133 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Used to create cache objects
*
* This class can be overloaded with {@see SimplePie::set_cache_class()},
* although the preferred way is to create your own handler
* via {@see register()}
*
* @package SimplePie
* @subpackage Caching
*/
class SimplePie_Cache
{
/**
* Cache handler classes
*
* These receive 3 parameters to their constructor, as documented in
* {@see register()}
* @var array
*/
protected static $handlers = array(
'mysql' => 'SimplePie_Cache_MySQL',
'memcache' => 'SimplePie_Cache_Memcache',
);
/**
* Don't call the constructor. Please.
*/
private function __construct() { }
/**
* Create a new SimplePie_Cache object
*
* @param string $location URL location (scheme is used to determine handler)
* @param string $filename Unique identifier for cache object
* @param string $extension 'spi' or 'spc'
* @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
*/
public static function get_handler($location, $filename, $extension)
{
$type = explode(':', $location, 2);
$type = $type[0];
if (!empty(self::$handlers[$type]))
{
$class = self::$handlers[$type];
return new $class($location, $filename, $extension);
}
return new SimplePie_Cache_File($location, $filename, $extension);
}
/**
* Create a new SimplePie_Cache object
*
* @deprecated Use {@see get_handler} instead
*/
public function create($location, $filename, $extension)
{
trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
return self::get_handler($location, $filename, $extension);
}
/**
* Register a handler
*
* @param string $type DSN type to register for
* @param string $class Name of handler class. Must implement SimplePie_Cache_Base
*/
public static function register($type, $class)
{
self::$handlers[$type] = $class;
}
/**
* Parse a URL into an array
*
* @param string $url
* @return array
*/
public static function parse_URL($url)
{
$params = parse_url($url);
$params['extras'] = array();
if (isset($params['query']))
{
parse_str($params['query'], $params['extras']);
}
return $params;
}
}

View File

@ -0,0 +1,114 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Base for cache objects
*
* Classes to be used with {@see SimplePie_Cache::register()} are expected
* to implement this interface.
*
* @package SimplePie
* @subpackage Caching
*/
interface SimplePie_Cache_Base
{
/**
* Feed cache type
*
* @var string
*/
const TYPE_FEED = 'spc';
/**
* Image cache type
*
* @var string
*/
const TYPE_IMAGE = 'spi';
/**
* Create a new cache object
*
* @param string $location Location string (from SimplePie::$cache_location)
* @param string $name Unique ID for the cache
* @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
*/
public function __construct($location, $name, $type);
/**
* Save data to the cache
*
* @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
* @return bool Successfulness
*/
public function save($data);
/**
* Retrieve the data saved to the cache
*
* @return array Data for SimplePie::$data
*/
public function load();
/**
* Retrieve the last modified time for the cache
*
* @return int Timestamp
*/
public function mtime();
/**
* Set the last modified time to the current time
*
* @return bool Success status
*/
public function touch();
/**
* Remove the cache
*
* @return bool Success status
*/
public function unlink();
}

View File

@ -0,0 +1,137 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Base class for database-based caches
*
* @package SimplePie
* @subpackage Caching
*/
abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
{
/**
* Helper for database conversion
*
* Converts a given {@see SimplePie} object into data to be stored
*
* @param SimplePie $data
* @return array First item is the serialized data for storage, second item is the unique ID for this item
*/
protected static function prepare_simplepie_object_for_cache($data)
{
$items = $data->get_items();
$items_by_id = array();
if (!empty($items))
{
foreach ($items as $item)
{
$items_by_id[$item->get_id()] = $item;
}
if (count($items_by_id) !== count($items))
{
$items_by_id = array();
foreach ($items as $item)
{
$items_by_id[$item->get_id(true)] = $item;
}
}
if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
{
$channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
}
elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
{
$channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
}
elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
{
$channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
}
elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
{
$channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
}
else
{
$channel = null;
}
if ($channel !== null)
{
if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
{
unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
}
if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
{
unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
}
if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
{
unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
}
if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
{
unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
}
if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
{
unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
}
}
if (isset($data->data['items']))
{
unset($data->data['items']);
}
if (isset($data->data['ordered_items']))
{
unset($data->data['ordered_items']);
}
}
return array(serialize($data->data), $items_by_id);
}
}

View File

@ -0,0 +1,173 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Caches data to the filesystem
*
* @package SimplePie
* @subpackage Caching
*/
class SimplePie_Cache_File implements SimplePie_Cache_Base
{
/**
* Location string
*
* @see SimplePie::$cache_location
* @var string
*/
protected $location;
/**
* Filename
*
* @var string
*/
protected $filename;
/**
* File extension
*
* @var string
*/
protected $extension;
/**
* File path
*
* @var string
*/
protected $name;
/**
* Create a new cache object
*
* @param string $location Location string (from SimplePie::$cache_location)
* @param string $name Unique ID for the cache
* @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
*/
public function __construct($location, $name, $type)
{
$this->location = $location;
$this->filename = $name;
$this->extension = $type;
$this->name = "$this->location/$this->filename.$this->extension";
}
/**
* Save data to the cache
*
* @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
* @return bool Successfulness
*/
public function save($data)
{
if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
{
if ($data instanceof SimplePie)
{
$data = $data->data;
}
$data = serialize($data);
return (bool) file_put_contents($this->name, $data);
}
return false;
}
/**
* Retrieve the data saved to the cache
*
* @return array Data for SimplePie::$data
*/
public function load()
{
if (file_exists($this->name) && is_readable($this->name))
{
return unserialize(file_get_contents($this->name));
}
return false;
}
/**
* Retrieve the last modified time for the cache
*
* @return int Timestamp
*/
public function mtime()
{
if (file_exists($this->name))
{
return filemtime($this->name);
}
return false;
}
/**
* Set the last modified time to the current time
*
* @return bool Success status
*/
public function touch()
{
if (file_exists($this->name))
{
return touch($this->name);
}
return false;
}
/**
* Remove the cache
*
* @return bool Success status
*/
public function unlink()
{
if (file_exists($this->name))
{
return unlink($this->name);
}
return false;
}
}

View File

@ -0,0 +1,183 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Caches data to memcache
*
* Registered for URLs with the "memcache" protocol
*
* For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
* connect to memcache on `localhost` on port 11211. All tables will be
* prefixed with `sp_` and data will expire after 3600 seconds
*
* @package SimplePie
* @subpackage Caching
* @uses Memcache
*/
class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
{
/**
* Memcache instance
*
* @var Memcache
*/
protected $cache;
/**
* Options
*
* @var array
*/
protected $options;
/**
* Cache name
*
* @var string
*/
protected $name;
/**
* Create a new cache object
*
* @param string $location Location string (from SimplePie::$cache_location)
* @param string $name Unique ID for the cache
* @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
*/
public function __construct($location, $name, $type)
{
$this->options = array(
'host' => '127.0.0.1',
'port' => 11211,
'extras' => array(
'timeout' => 3600, // one hour
'prefix' => 'simplepie_',
),
);
$parsed = SimplePie_Cache::parse_URL($location);
$this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
$this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
$this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
$this->name = $this->options['extras']['prefix'] . md5("$name:$type");
$this->cache = new Memcache();
$this->cache->addServer($this->options['host'], (int) $this->options['port']);
}
/**
* Save data to the cache
*
* @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
* @return bool Successfulness
*/
public function save($data)
{
if ($data instanceof SimplePie)
{
$data = $data->data;
}
return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
}
/**
* Retrieve the data saved to the cache
*
* @return array Data for SimplePie::$data
*/
public function load()
{
$data = $this->cache->get($this->name);
if ($data !== false)
{
return unserialize($data);
}
return false;
}
/**
* Retrieve the last modified time for the cache
*
* @return int Timestamp
*/
public function mtime()
{
$data = $this->cache->get($this->name);
if ($data !== false)
{
// essentially ignore the mtime because Memcache expires on it's own
return time();
}
return false;
}
/**
* Set the last modified time to the current time
*
* @return bool Success status
*/
public function touch()
{
$data = $this->cache->get($this->name);
if ($data !== false)
{
return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
}
return false;
}
/**
* Remove the cache
*
* @return bool Success status
*/
public function unlink()
{
return $this->cache->delete($this->name, 0);
}
}

View File

@ -0,0 +1,438 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Caches data to a MySQL database
*
* Registered for URLs with the "mysql" protocol
*
* For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
* connect to the `mydb` database on `localhost` on port 3306, with the user
* `root` and the password `password`. All tables will be prefixed with `sp_`
*
* @package SimplePie
* @subpackage Caching
*/
class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
{
/**
* PDO instance
*
* @var PDO
*/
protected $mysql;
/**
* Options
*
* @var array
*/
protected $options;
/**
* Cache ID
*
* @var string
*/
protected $id;
/**
* Create a new cache object
*
* @param string $location Location string (from SimplePie::$cache_location)
* @param string $name Unique ID for the cache
* @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
*/
public function __construct($location, $name, $type)
{
$this->options = array(
'user' => null,
'pass' => null,
'host' => '127.0.0.1',
'port' => '3306',
'path' => '',
'extras' => array(
'prefix' => '',
),
);
$this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
// Path is prefixed with a "/"
$this->options['dbname'] = substr($this->options['path'], 1);
try
{
$this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
}
catch (PDOException $e)
{
$this->mysql = null;
return;
}
$this->id = $name . $type;
if (!$query = $this->mysql->query('SHOW TABLES'))
{
$this->mysql = null;
return;
}
$db = array();
while ($row = $query->fetchColumn())
{
$db[] = $row;
}
if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
{
$query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
if ($query === false)
{
$this->mysql = null;
}
}
if (!in_array($this->options['extras']['prefix'] . 'items', $db))
{
$query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
if ($query === false)
{
$this->mysql = null;
}
}
}
/**
* Save data to the cache
*
* @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
* @return bool Successfulness
*/
public function save($data)
{
if ($this->mysql === null)
{
return false;
}
if ($data instanceof SimplePie)
{
$data = clone $data;
$prepared = self::prepare_simplepie_object_for_cache($data);
$query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
$query->bindValue(':feed', $this->id);
if ($query->execute())
{
if ($query->fetchColumn() > 0)
{
$items = count($prepared[1]);
if ($items)
{
$sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
$query = $this->mysql->prepare($sql);
$query->bindValue(':items', $items);
}
else
{
$sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
$query = $this->mysql->prepare($sql);
}
$query->bindValue(':data', $prepared[0]);
$query->bindValue(':time', time());
$query->bindValue(':feed', $this->id);
if (!$query->execute())
{
return false;
}
}
else
{
$query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
$query->bindValue(':feed', $this->id);
$query->bindValue(':count', count($prepared[1]));
$query->bindValue(':data', $prepared[0]);
$query->bindValue(':time', time());
if (!$query->execute())
{
return false;
}
}
$ids = array_keys($prepared[1]);
if (!empty($ids))
{
foreach ($ids as $id)
{
$database_ids[] = $this->mysql->quote($id);
}
$query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
$query->bindValue(':feed', $this->id);
if ($query->execute())
{
$existing_ids = array();
while ($row = $query->fetchColumn())
{
$existing_ids[] = $row;
}
$new_ids = array_diff($ids, $existing_ids);
foreach ($new_ids as $new_id)
{
if (!($date = $prepared[1][$new_id]->get_date('U')))
{
$date = time();
}
$query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
$query->bindValue(':feed', $this->id);
$query->bindValue(':id', $new_id);
$query->bindValue(':data', serialize($prepared[1][$new_id]->data));
$query->bindValue(':date', $date);
if (!$query->execute())
{
return false;
}
}
return true;
}
}
else
{
return true;
}
}
}
else
{
$query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
$query->bindValue(':feed', $this->id);
if ($query->execute())
{
if ($query->rowCount() > 0)
{
$query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
$query->bindValue(':data', serialize($data));
$query->bindValue(':time', time());
$query->bindValue(':feed', $this->id);
if ($this->execute())
{
return true;
}
}
else
{
$query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
$query->bindValue(':id', $this->id);
$query->bindValue(':data', serialize($data));
$query->bindValue(':time', time());
if ($query->execute())
{
return true;
}
}
}
}
return false;
}
/**
* Retrieve the data saved to the cache
*
* @return array Data for SimplePie::$data
*/
public function load()
{
if ($this->mysql === null)
{
return false;
}
$query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
$query->bindValue(':id', $this->id);
if ($query->execute() && ($row = $query->fetch()))
{
$data = unserialize($row[1]);
if (isset($this->options['items'][0]))
{
$items = (int) $this->options['items'][0];
}
else
{
$items = (int) $row[0];
}
if ($items !== 0)
{
if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
{
$feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
}
elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
{
$feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
}
elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
{
$feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
}
elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
{
$feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
}
else
{
$feed = null;
}
if ($feed !== null)
{
$sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
if ($items > 0)
{
$sql .= ' LIMIT ' . $items;
}
$query = $this->mysql->prepare($sql);
$query->bindValue(':feed', $this->id);
if ($query->execute())
{
while ($row = $query->fetchColumn())
{
$feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
}
}
else
{
return false;
}
}
}
return $data;
}
return false;
}
/**
* Retrieve the last modified time for the cache
*
* @return int Timestamp
*/
public function mtime()
{
if ($this->mysql === null)
{
return false;
}
$query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
$query->bindValue(':id', $this->id);
if ($query->execute() && ($time = $query->fetchColumn()))
{
return $time;
}
else
{
return false;
}
}
/**
* Set the last modified time to the current time
*
* @return bool Success status
*/
public function touch()
{
if ($this->mysql === null)
{
return false;
}
$query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
$query->bindValue(':time', time());
$query->bindValue(':id', $this->id);
if ($query->execute() && $query->rowCount() > 0)
{
return true;
}
else
{
return false;
}
}
/**
* Remove the cache
*
* @return bool Success status
*/
public function unlink()
{
if ($this->mysql === null)
{
return false;
}
$query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
$query->bindValue(':id', $this->id);
$query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
$query2->bindValue(':id', $this->id);
if ($query->execute() && $query2->execute())
{
return true;
}
else
{
return false;
}
}
}

View File

@ -0,0 +1,210 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Handles `<media:text>` captions as defined in Media RSS.
*
* Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
*
* This class can be overloaded with {@see SimplePie::set_caption_class()}
*
* @package SimplePie
* @subpackage API
*/
class SimplePie_Caption
{
/**
* Content type
*
* @var string
* @see get_type()
*/
var $type;
/**
* Language
*
* @var string
* @see get_language()
*/
var $lang;
/**
* Start time
*
* @var string
* @see get_starttime()
*/
var $startTime;
/**
* End time
*
* @var string
* @see get_endtime()
*/
var $endTime;
/**
* Caption text
*
* @var string
* @see get_text()
*/
var $text;
/**
* Constructor, used to input the data
*
* For documentation on all the parameters, see the corresponding
* properties and their accessors
*/
public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
{
$this->type = $type;
$this->lang = $lang;
$this->startTime = $startTime;
$this->endTime = $endTime;
$this->text = $text;
}
/**
* String-ified version
*
* @return string
*/
public function __toString()
{
// There is no $this->data here
return md5(serialize($this));
}
/**
* Get the end time
*
* @return string|null Time in the format 'hh:mm:ss.SSS'
*/
public function get_endtime()
{
if ($this->endTime !== null)
{
return $this->endTime;
}
else
{
return null;
}
}
/**
* Get the language
*
* @link http://tools.ietf.org/html/rfc3066
* @return string|null Language code as per RFC 3066
*/
public function get_language()
{
if ($this->lang !== null)
{
return $this->lang;
}
else
{
return null;
}
}
/**
* Get the start time
*
* @return string|null Time in the format 'hh:mm:ss.SSS'
*/
public function get_starttime()
{
if ($this->startTime !== null)
{
return $this->startTime;
}
else
{
return null;
}
}
/**
* Get the text of the caption
*
* @return string|null
*/
public function get_text()
{
if ($this->text !== null)
{
return $this->text;
}
else
{
return null;
}
}
/**
* Get the content type (not MIME type)
*
* @return string|null Either 'text' or 'html'
*/
public function get_type()
{
if ($this->type !== null)
{
return $this->type;
}
else
{
return null;
}
}
}

View File

@ -0,0 +1,157 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Manages all category-related data
*
* Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
*
* This class can be overloaded with {@see SimplePie::set_category_class()}
*
* @package SimplePie
* @subpackage API
*/
class SimplePie_Category
{
/**
* Category identifier
*
* @var string
* @see get_term
*/
var $term;
/**
* Categorization scheme identifier
*
* @var string
* @see get_scheme()
*/
var $scheme;
/**
* Human readable label
*
* @var string
* @see get_label()
*/
var $label;
/**
* Constructor, used to input the data
*
* @param string $term
* @param string $scheme
* @param string $label
*/
public function __construct($term = null, $scheme = null, $label = null)
{
$this->term = $term;
$this->scheme = $scheme;
$this->label = $label;
}
/**
* String-ified version
*
* @return string
*/
public function __toString()
{
// There is no $this->data here
return md5(serialize($this));
}
/**
* Get the category identifier
*
* @return string|null
*/
public function get_term()
{
if ($this->term !== null)
{
return $this->term;
}
else
{
return null;
}
}
/**
* Get the categorization scheme identifier
*
* @return string|null
*/
public function get_scheme()
{
if ($this->scheme !== null)
{
return $this->scheme;
}
else
{
return null;
}
}
/**
* Get the human readable label
*
* @return string|null
*/
public function get_label()
{
if ($this->label !== null)
{
return $this->label;
}
else
{
return $this->get_term();
}
}
}

View File

@ -0,0 +1,332 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Content-type sniffing
*
* Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
*
* This is used since we can't always trust Content-Type headers, and is based
* upon the HTML5 parsing rules.
*
*
* This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
*
* @package SimplePie
* @subpackage HTTP
*/
class SimplePie_Content_Type_Sniffer
{
/**
* File object
*
* @var SimplePie_File
*/
var $file;
/**
* Create an instance of the class with the input file
*
* @param SimplePie_Content_Type_Sniffer $file Input file
*/
public function __construct($file)
{
$this->file = $file;
}
/**
* Get the Content-Type of the specified file
*
* @return string Actual Content-Type
*/
public function get_type()
{
if (isset($this->file->headers['content-type']))
{
if (!isset($this->file->headers['content-encoding'])
&& ($this->file->headers['content-type'] === 'text/plain'
|| $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
|| $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
|| $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
{
return $this->text_or_binary();
}
if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
{
$official = substr($this->file->headers['content-type'], 0, $pos);
}
else
{
$official = $this->file->headers['content-type'];
}
$official = trim(strtolower($official));
if ($official === 'unknown/unknown'
|| $official === 'application/unknown')
{
return $this->unknown();
}
elseif (substr($official, -4) === '+xml'
|| $official === 'text/xml'
|| $official === 'application/xml')
{
return $official;
}
elseif (substr($official, 0, 6) === 'image/')
{
if ($return = $this->image())
{
return $return;
}
else
{
return $official;
}
}
elseif ($official === 'text/html')
{
return $this->feed_or_html();
}
else
{
return $official;
}
}
else
{
return $this->unknown();
}
}
/**
* Sniff text or binary
*
* @return string Actual Content-Type
*/
public function text_or_binary()
{
if (substr($this->file->body, 0, 2) === "\xFE\xFF"
|| substr($this->file->body, 0, 2) === "\xFF\xFE"
|| substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
|| substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
{
return 'text/plain';
}
elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
{
return 'application/octect-stream';
}
else
{
return 'text/plain';
}
}
/**
* Sniff unknown
*
* @return string Actual Content-Type
*/
public function unknown()
{
$ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
|| strtolower(substr($this->file->body, $ws, 5)) === '<html'
|| strtolower(substr($this->file->body, $ws, 7)) === '<script')
{
return 'text/html';
}
elseif (substr($this->file->body, 0, 5) === '%PDF-')
{
return 'application/pdf';
}
elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
{
return 'application/postscript';
}
elseif (substr($this->file->body, 0, 6) === 'GIF87a'
|| substr($this->file->body, 0, 6) === 'GIF89a')
{
return 'image/gif';
}
elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
{
return 'image/png';
}
elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
{
return 'image/jpeg';
}
elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
{
return 'image/bmp';
}
elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
{
return 'image/vnd.microsoft.icon';
}
else
{
return $this->text_or_binary();
}
}
/**
* Sniff images
*
* @return string Actual Content-Type
*/
public function image()
{
if (substr($this->file->body, 0, 6) === 'GIF87a'
|| substr($this->file->body, 0, 6) === 'GIF89a')
{
return 'image/gif';
}
elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
{
return 'image/png';
}
elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
{
return 'image/jpeg';
}
elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
{
return 'image/bmp';
}
elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
{
return 'image/vnd.microsoft.icon';
}
else
{
return false;
}
}
/**
* Sniff HTML
*
* @return string Actual Content-Type
*/
public function feed_or_html()
{
$len = strlen($this->file->body);
$pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
while ($pos < $len)
{
switch ($this->file->body[$pos])
{
case "\x09":
case "\x0A":
case "\x0D":
case "\x20":
$pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
continue 2;
case '<':
$pos++;
break;
default:
return 'text/html';
}
if (substr($this->file->body, $pos, 3) === '!--')
{
$pos += 3;
if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
{
$pos += 3;
}
else
{
return 'text/html';
}
}
elseif (substr($this->file->body, $pos, 1) === '!')
{
if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
{
$pos++;
}
else
{
return 'text/html';
}
}
elseif (substr($this->file->body, $pos, 1) === '?')
{
if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
{
$pos += 2;
}
else
{
return 'text/html';
}
}
elseif (substr($this->file->body, $pos, 3) === 'rss'
|| substr($this->file->body, $pos, 7) === 'rdf:RDF')
{
return 'application/rss+xml';
}
elseif (substr($this->file->body, $pos, 4) === 'feed')
{
return 'application/atom+xml';
}
else
{
return 'text/html';
}
}
return 'text/html';
}
}

View File

@ -0,0 +1,130 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Manages `<media:copyright>` copyright tags as defined in Media RSS
*
* Used by {@see SimplePie_Enclosure::get_copyright()}
*
* This class can be overloaded with {@see SimplePie::set_copyright_class()}
*
* @package SimplePie
* @subpackage API
*/
class SimplePie_Copyright
{
/**
* Copyright URL
*
* @var string
* @see get_url()
*/
var $url;
/**
* Attribution
*
* @var string
* @see get_attribution()
*/
var $label;
/**
* Constructor, used to input the data
*
* For documentation on all the parameters, see the corresponding
* properties and their accessors
*/
public function __construct($url = null, $label = null)
{
$this->url = $url;
$this->label = $label;
}
/**
* String-ified version
*
* @return string
*/
public function __toString()
{
// There is no $this->data here
return md5(serialize($this));
}
/**
* Get the copyright URL
*
* @return string|null URL to copyright information
*/
public function get_url()
{
if ($this->url !== null)
{
return $this->url;
}
else
{
return null;
}
}
/**
* Get the attribution text
*
* @return string|null
*/
public function get_attribution()
{
if ($this->label !== null)
{
return $this->label;
}
else
{
return null;
}
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* SimplePie class.
*
* Class for backward compatibility.
*
* @deprecated Use {@see SimplePie} directly
* @package SimplePie
* @subpackage API
*/
class SimplePie_Core extends SimplePie
{
}

View File

@ -0,0 +1,156 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Handles `<media:credit>` as defined in Media RSS
*
* Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
*
* This class can be overloaded with {@see SimplePie::set_credit_class()}
*
* @package SimplePie
* @subpackage API
*/
class SimplePie_Credit
{
/**
* Credited role
*
* @var string
* @see get_role()
*/
var $role;
/**
* Organizational scheme
*
* @var string
* @see get_scheme()
*/
var $scheme;
/**
* Credited name
*
* @var string
* @see get_name()
*/
var $name;
/**
* Constructor, used to input the data
*
* For documentation on all the parameters, see the corresponding
* properties and their accessors
*/
public function __construct($role = null, $scheme = null, $name = null)
{
$this->role = $role;
$this->scheme = $scheme;
$this->name = $name;
}
/**
* String-ified version
*
* @return string
*/
public function __toString()
{
// There is no $this->data here
return md5(serialize($this));
}
/**
* Get the role of the person receiving credit
*
* @return string|null
*/
public function get_role()
{
if ($this->role !== null)
{
return $this->role;
}
else
{
return null;
}
}
/**
* Get the organizational scheme
*
* @return string|null
*/
public function get_scheme()
{
if ($this->scheme !== null)
{
return $this->scheme;
}
else
{
return null;
}
}
/**
* Get the credited person/entity's name
*
* @return string|null
*/
public function get_name()
{
if ($this->name !== null)
{
return $this->name;
}
else
{
return null;
}
}
}

View File

@ -0,0 +1,617 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Decode HTML Entities
*
* This implements HTML5 as of revision 967 (2007-06-28)
*
* @deprecated Use DOMDocument instead!
* @package SimplePie
*/
class SimplePie_Decode_HTML_Entities
{
/**
* Data to be parsed
*
* @access private
* @var string
*/
var $data = '';
/**
* Currently consumed bytes
*
* @access private
* @var string
*/
var $consumed = '';
/**
* Position of the current byte being parsed
*
* @access private
* @var int
*/
var $position = 0;
/**
* Create an instance of the class with the input data
*
* @access public
* @param string $data Input data
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Parse the input data
*
* @access public
* @return string Output data
*/
public function parse()
{
while (($this->position = strpos($this->data, '&', $this->position)) !== false)
{
$this->consume();
$this->entity();
$this->consumed = '';
}
return $this->data;
}
/**
* Consume the next byte
*
* @access private
* @return mixed The next byte, or false, if there is no more data
*/
public function consume()
{
if (isset($this->data[$this->position]))
{
$this->consumed .= $this->data[$this->position];
return $this->data[$this->position++];
}
else
{
return false;
}
}
/**
* Consume a range of characters
*
* @access private
* @param string $chars Characters to consume
* @return mixed A series of characters that match the range, or false
*/
public function consume_range($chars)
{
if ($len = strspn($this->data, $chars, $this->position))
{
$data = substr($this->data, $this->position, $len);
$this->consumed .= $data;
$this->position += $len;
return $data;
}
else
{
return false;
}
}
/**
* Unconsume one byte
*
* @access private
*/
public function unconsume()
{
$this->consumed = substr($this->consumed, 0, -1);
$this->position--;
}
/**
* Decode an entity
*
* @access private
*/
public function entity()
{
switch ($this->consume())
{
case "\x09":
case "\x0A":
case "\x0B":
case "\x0B":
case "\x0C":
case "\x20":
case "\x3C":
case "\x26":
case false:
break;
case "\x23":
switch ($this->consume())
{
case "\x78":
case "\x58":
$range = '0123456789ABCDEFabcdef';
$hex = true;
break;
default:
$range = '0123456789';
$hex = false;
$this->unconsume();
break;
}
if ($codepoint = $this->consume_range($range))
{
static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
if ($hex)
{
$codepoint = hexdec($codepoint);
}
else
{
$codepoint = intval($codepoint);
}
if (isset($windows_1252_specials[$codepoint]))
{
$replacement = $windows_1252_specials[$codepoint];
}
else
{
$replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
}
if (!in_array($this->consume(), array(';', false), true))
{
$this->unconsume();
}
$consumed_length = strlen($this->consumed);
$this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
$this->position += strlen($replacement) - $consumed_length;
}
break;
default:
static $entities = array(
'Aacute' => "\xC3\x81",
'aacute' => "\xC3\xA1",
'Aacute;' => "\xC3\x81",
'aacute;' => "\xC3\xA1",
'Acirc' => "\xC3\x82",
'acirc' => "\xC3\xA2",
'Acirc;' => "\xC3\x82",
'acirc;' => "\xC3\xA2",
'acute' => "\xC2\xB4",
'acute;' => "\xC2\xB4",
'AElig' => "\xC3\x86",
'aelig' => "\xC3\xA6",
'AElig;' => "\xC3\x86",
'aelig;' => "\xC3\xA6",
'Agrave' => "\xC3\x80",
'agrave' => "\xC3\xA0",
'Agrave;' => "\xC3\x80",
'agrave;' => "\xC3\xA0",
'alefsym;' => "\xE2\x84\xB5",
'Alpha;' => "\xCE\x91",
'alpha;' => "\xCE\xB1",
'AMP' => "\x26",
'amp' => "\x26",
'AMP;' => "\x26",
'amp;' => "\x26",
'and;' => "\xE2\x88\xA7",
'ang;' => "\xE2\x88\xA0",
'apos;' => "\x27",
'Aring' => "\xC3\x85",
'aring' => "\xC3\xA5",
'Aring;' => "\xC3\x85",
'aring;' => "\xC3\xA5",
'asymp;' => "\xE2\x89\x88",
'Atilde' => "\xC3\x83",
'atilde' => "\xC3\xA3",
'Atilde;' => "\xC3\x83",
'atilde;' => "\xC3\xA3",
'Auml' => "\xC3\x84",
'auml' => "\xC3\xA4",
'Auml;' => "\xC3\x84",
'auml;' => "\xC3\xA4",
'bdquo;' => "\xE2\x80\x9E",
'Beta;' => "\xCE\x92",
'beta;' => "\xCE\xB2",
'brvbar' => "\xC2\xA6",
'brvbar;' => "\xC2\xA6",
'bull;' => "\xE2\x80\xA2",
'cap;' => "\xE2\x88\xA9",
'Ccedil' => "\xC3\x87",
'ccedil' => "\xC3\xA7",
'Ccedil;' => "\xC3\x87",
'ccedil;' => "\xC3\xA7",
'cedil' => "\xC2\xB8",
'cedil;' => "\xC2\xB8",
'cent' => "\xC2\xA2",
'cent;' => "\xC2\xA2",
'Chi;' => "\xCE\xA7",
'chi;' => "\xCF\x87",
'circ;' => "\xCB\x86",
'clubs;' => "\xE2\x99\xA3",
'cong;' => "\xE2\x89\x85",
'COPY' => "\xC2\xA9",
'copy' => "\xC2\xA9",
'COPY;' => "\xC2\xA9",
'copy;' => "\xC2\xA9",
'crarr;' => "\xE2\x86\xB5",
'cup;' => "\xE2\x88\xAA",
'curren' => "\xC2\xA4",
'curren;' => "\xC2\xA4",
'Dagger;' => "\xE2\x80\xA1",
'dagger;' => "\xE2\x80\xA0",
'dArr;' => "\xE2\x87\x93",
'darr;' => "\xE2\x86\x93",
'deg' => "\xC2\xB0",
'deg;' => "\xC2\xB0",
'Delta;' => "\xCE\x94",
'delta;' => "\xCE\xB4",
'diams;' => "\xE2\x99\xA6",
'divide' => "\xC3\xB7",
'divide;' => "\xC3\xB7",
'Eacute' => "\xC3\x89",
'eacute' => "\xC3\xA9",
'Eacute;' => "\xC3\x89",
'eacute;' => "\xC3\xA9",
'Ecirc' => "\xC3\x8A",
'ecirc' => "\xC3\xAA",
'Ecirc;' => "\xC3\x8A",
'ecirc;' => "\xC3\xAA",
'Egrave' => "\xC3\x88",
'egrave' => "\xC3\xA8",
'Egrave;' => "\xC3\x88",
'egrave;' => "\xC3\xA8",
'empty;' => "\xE2\x88\x85",
'emsp;' => "\xE2\x80\x83",
'ensp;' => "\xE2\x80\x82",
'Epsilon;' => "\xCE\x95",
'epsilon;' => "\xCE\xB5",
'equiv;' => "\xE2\x89\xA1",
'Eta;' => "\xCE\x97",
'eta;' => "\xCE\xB7",
'ETH' => "\xC3\x90",
'eth' => "\xC3\xB0",
'ETH;' => "\xC3\x90",
'eth;' => "\xC3\xB0",
'Euml' => "\xC3\x8B",
'euml' => "\xC3\xAB",
'Euml;' => "\xC3\x8B",
'euml;' => "\xC3\xAB",
'euro;' => "\xE2\x82\xAC",
'exist;' => "\xE2\x88\x83",
'fnof;' => "\xC6\x92",
'forall;' => "\xE2\x88\x80",
'frac12' => "\xC2\xBD",
'frac12;' => "\xC2\xBD",
'frac14' => "\xC2\xBC",
'frac14;' => "\xC2\xBC",
'frac34' => "\xC2\xBE",
'frac34;' => "\xC2\xBE",
'frasl;' => "\xE2\x81\x84",
'Gamma;' => "\xCE\x93",
'gamma;' => "\xCE\xB3",
'ge;' => "\xE2\x89\xA5",
'GT' => "\x3E",
'gt' => "\x3E",
'GT;' => "\x3E",
'gt;' => "\x3E",
'hArr;' => "\xE2\x87\x94",
'harr;' => "\xE2\x86\x94",
'hearts;' => "\xE2\x99\xA5",
'hellip;' => "\xE2\x80\xA6",
'Iacute' => "\xC3\x8D",
'iacute' => "\xC3\xAD",
'Iacute;' => "\xC3\x8D",
'iacute;' => "\xC3\xAD",
'Icirc' => "\xC3\x8E",
'icirc' => "\xC3\xAE",
'Icirc;' => "\xC3\x8E",
'icirc;' => "\xC3\xAE",
'iexcl' => "\xC2\xA1",
'iexcl;' => "\xC2\xA1",
'Igrave' => "\xC3\x8C",
'igrave' => "\xC3\xAC",
'Igrave;' => "\xC3\x8C",
'igrave;' => "\xC3\xAC",
'image;' => "\xE2\x84\x91",
'infin;' => "\xE2\x88\x9E",
'int;' => "\xE2\x88\xAB",
'Iota;' => "\xCE\x99",
'iota;' => "\xCE\xB9",
'iquest' => "\xC2\xBF",
'iquest;' => "\xC2\xBF",
'isin;' => "\xE2\x88\x88",
'Iuml' => "\xC3\x8F",
'iuml' => "\xC3\xAF",
'Iuml;' => "\xC3\x8F",
'iuml;' => "\xC3\xAF",
'Kappa;' => "\xCE\x9A",
'kappa;' => "\xCE\xBA",
'Lambda;' => "\xCE\x9B",
'lambda;' => "\xCE\xBB",
'lang;' => "\xE3\x80\x88",
'laquo' => "\xC2\xAB",
'laquo;' => "\xC2\xAB",
'lArr;' => "\xE2\x87\x90",
'larr;' => "\xE2\x86\x90",
'lceil;' => "\xE2\x8C\x88",
'ldquo;' => "\xE2\x80\x9C",
'le;' => "\xE2\x89\xA4",
'lfloor;' => "\xE2\x8C\x8A",
'lowast;' => "\xE2\x88\x97",
'loz;' => "\xE2\x97\x8A",
'lrm;' => "\xE2\x80\x8E",
'lsaquo;' => "\xE2\x80\xB9",
'lsquo;' => "\xE2\x80\x98",
'LT' => "\x3C",
'lt' => "\x3C",
'LT;' => "\x3C",
'lt;' => "\x3C",
'macr' => "\xC2\xAF",
'macr;' => "\xC2\xAF",
'mdash;' => "\xE2\x80\x94",
'micro' => "\xC2\xB5",
'micro;' => "\xC2\xB5",
'middot' => "\xC2\xB7",
'middot;' => "\xC2\xB7",
'minus;' => "\xE2\x88\x92",
'Mu;' => "\xCE\x9C",
'mu;' => "\xCE\xBC",
'nabla;' => "\xE2\x88\x87",
'nbsp' => "\xC2\xA0",
'nbsp;' => "\xC2\xA0",
'ndash;' => "\xE2\x80\x93",
'ne;' => "\xE2\x89\xA0",
'ni;' => "\xE2\x88\x8B",
'not' => "\xC2\xAC",
'not;' => "\xC2\xAC",
'notin;' => "\xE2\x88\x89",
'nsub;' => "\xE2\x8A\x84",
'Ntilde' => "\xC3\x91",
'ntilde' => "\xC3\xB1",
'Ntilde;' => "\xC3\x91",
'ntilde;' => "\xC3\xB1",
'Nu;' => "\xCE\x9D",
'nu;' => "\xCE\xBD",
'Oacute' => "\xC3\x93",
'oacute' => "\xC3\xB3",
'Oacute;' => "\xC3\x93",
'oacute;' => "\xC3\xB3",
'Ocirc' => "\xC3\x94",
'ocirc' => "\xC3\xB4",
'Ocirc;' => "\xC3\x94",
'ocirc;' => "\xC3\xB4",
'OElig;' => "\xC5\x92",
'oelig;' => "\xC5\x93",
'Ograve' => "\xC3\x92",
'ograve' => "\xC3\xB2",
'Ograve;' => "\xC3\x92",
'ograve;' => "\xC3\xB2",
'oline;' => "\xE2\x80\xBE",
'Omega;' => "\xCE\xA9",
'omega;' => "\xCF\x89",
'Omicron;' => "\xCE\x9F",
'omicron;' => "\xCE\xBF",
'oplus;' => "\xE2\x8A\x95",
'or;' => "\xE2\x88\xA8",
'ordf' => "\xC2\xAA",
'ordf;' => "\xC2\xAA",
'ordm' => "\xC2\xBA",
'ordm;' => "\xC2\xBA",
'Oslash' => "\xC3\x98",
'oslash' => "\xC3\xB8",
'Oslash;' => "\xC3\x98",
'oslash;' => "\xC3\xB8",
'Otilde' => "\xC3\x95",
'otilde' => "\xC3\xB5",
'Otilde;' => "\xC3\x95",
'otilde;' => "\xC3\xB5",
'otimes;' => "\xE2\x8A\x97",
'Ouml' => "\xC3\x96",
'ouml' => "\xC3\xB6",
'Ouml;' => "\xC3\x96",
'ouml;' => "\xC3\xB6",
'para' => "\xC2\xB6",
'para;' => "\xC2\xB6",
'part;' => "\xE2\x88\x82",
'permil;' => "\xE2\x80\xB0",
'perp;' => "\xE2\x8A\xA5",
'Phi;' => "\xCE\xA6",
'phi;' => "\xCF\x86",
'Pi;' => "\xCE\xA0",
'pi;' => "\xCF\x80",
'piv;' => "\xCF\x96",
'plusmn' => "\xC2\xB1",
'plusmn;' => "\xC2\xB1",
'pound' => "\xC2\xA3",
'pound;' => "\xC2\xA3",
'Prime;' => "\xE2\x80\xB3",
'prime;' => "\xE2\x80\xB2",
'prod;' => "\xE2\x88\x8F",
'prop;' => "\xE2\x88\x9D",
'Psi;' => "\xCE\xA8",
'psi;' => "\xCF\x88",
'QUOT' => "\x22",
'quot' => "\x22",
'QUOT;' => "\x22",
'quot;' => "\x22",
'radic;' => "\xE2\x88\x9A",
'rang;' => "\xE3\x80\x89",
'raquo' => "\xC2\xBB",
'raquo;' => "\xC2\xBB",
'rArr;' => "\xE2\x87\x92",
'rarr;' => "\xE2\x86\x92",
'rceil;' => "\xE2\x8C\x89",
'rdquo;' => "\xE2\x80\x9D",
'real;' => "\xE2\x84\x9C",
'REG' => "\xC2\xAE",
'reg' => "\xC2\xAE",
'REG;' => "\xC2\xAE",
'reg;' => "\xC2\xAE",
'rfloor;' => "\xE2\x8C\x8B",
'Rho;' => "\xCE\xA1",
'rho;' => "\xCF\x81",
'rlm;' => "\xE2\x80\x8F",
'rsaquo;' => "\xE2\x80\xBA",
'rsquo;' => "\xE2\x80\x99",
'sbquo;' => "\xE2\x80\x9A",
'Scaron;' => "\xC5\xA0",
'scaron;' => "\xC5\xA1",
'sdot;' => "\xE2\x8B\x85",
'sect' => "\xC2\xA7",
'sect;' => "\xC2\xA7",
'shy' => "\xC2\xAD",
'shy;' => "\xC2\xAD",
'Sigma;' => "\xCE\xA3",
'sigma;' => "\xCF\x83",
'sigmaf;' => "\xCF\x82",
'sim;' => "\xE2\x88\xBC",
'spades;' => "\xE2\x99\xA0",
'sub;' => "\xE2\x8A\x82",
'sube;' => "\xE2\x8A\x86",
'sum;' => "\xE2\x88\x91",
'sup;' => "\xE2\x8A\x83",
'sup1' => "\xC2\xB9",
'sup1;' => "\xC2\xB9",
'sup2' => "\xC2\xB2",
'sup2;' => "\xC2\xB2",
'sup3' => "\xC2\xB3",
'sup3;' => "\xC2\xB3",
'supe;' => "\xE2\x8A\x87",
'szlig' => "\xC3\x9F",
'szlig;' => "\xC3\x9F",
'Tau;' => "\xCE\xA4",
'tau;' => "\xCF\x84",
'there4;' => "\xE2\x88\xB4",
'Theta;' => "\xCE\x98",
'theta;' => "\xCE\xB8",
'thetasym;' => "\xCF\x91",
'thinsp;' => "\xE2\x80\x89",
'THORN' => "\xC3\x9E",
'thorn' => "\xC3\xBE",
'THORN;' => "\xC3\x9E",
'thorn;' => "\xC3\xBE",
'tilde;' => "\xCB\x9C",
'times' => "\xC3\x97",
'times;' => "\xC3\x97",
'TRADE;' => "\xE2\x84\xA2",
'trade;' => "\xE2\x84\xA2",
'Uacute' => "\xC3\x9A",
'uacute' => "\xC3\xBA",
'Uacute;' => "\xC3\x9A",
'uacute;' => "\xC3\xBA",
'uArr;' => "\xE2\x87\x91",
'uarr;' => "\xE2\x86\x91",
'Ucirc' => "\xC3\x9B",
'ucirc' => "\xC3\xBB",
'Ucirc;' => "\xC3\x9B",
'ucirc;' => "\xC3\xBB",
'Ugrave' => "\xC3\x99",
'ugrave' => "\xC3\xB9",
'Ugrave;' => "\xC3\x99",
'ugrave;' => "\xC3\xB9",
'uml' => "\xC2\xA8",
'uml;' => "\xC2\xA8",
'upsih;' => "\xCF\x92",
'Upsilon;' => "\xCE\xA5",
'upsilon;' => "\xCF\x85",
'Uuml' => "\xC3\x9C",
'uuml' => "\xC3\xBC",
'Uuml;' => "\xC3\x9C",
'uuml;' => "\xC3\xBC",
'weierp;' => "\xE2\x84\x98",
'Xi;' => "\xCE\x9E",
'xi;' => "\xCE\xBE",
'Yacute' => "\xC3\x9D",
'yacute' => "\xC3\xBD",
'Yacute;' => "\xC3\x9D",
'yacute;' => "\xC3\xBD",
'yen' => "\xC2\xA5",
'yen;' => "\xC2\xA5",
'yuml' => "\xC3\xBF",
'Yuml;' => "\xC5\xB8",
'yuml;' => "\xC3\xBF",
'Zeta;' => "\xCE\x96",
'zeta;' => "\xCE\xB6",
'zwj;' => "\xE2\x80\x8D",
'zwnj;' => "\xE2\x80\x8C"
);
for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
{
$consumed = substr($this->consumed, 1);
if (isset($entities[$consumed]))
{
$match = $consumed;
}
}
if ($match !== null)
{
$this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
$this->position += strlen($entities[$match]) - strlen($consumed) - 1;
}
break;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* General SimplePie exception class
*
* @package SimplePie
*/
class SimplePie_Exception extends Exception
{
}

View File

@ -0,0 +1,292 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Used for fetching remote files and reading local files
*
* Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
*
* This class can be overloaded with {@see SimplePie::set_file_class()}
*
* @package SimplePie
* @subpackage HTTP
* @todo Move to properly supporting RFC2616 (HTTP/1.1)
*/
class SimplePie_File
{
var $url;
var $useragent;
var $success = true;
var $headers = array();
var $body;
var $status_code;
var $redirects = 0;
var $error;
var $method = SIMPLEPIE_FILE_SOURCE_NONE;
public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
{
if (class_exists('idna_convert'))
{
$idn = new idna_convert();
$parsed = SimplePie_Misc::parse_url($url);
$url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
}
$this->url = $url;
$this->useragent = $useragent;
if (preg_match('/^http(s)?:\/\//i', $url))
{
if ($useragent === null)
{
$useragent = ini_get('user_agent');
$this->useragent = $useragent;
}
if (!is_array($headers))
{
$headers = array();
}
if (!$force_fsockopen && function_exists('curl_exec'))
{
$this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
$fp = curl_init();
$headers2 = array();
foreach ($headers as $key => $value)
{
$headers2[] = "$key: $value";
}
if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
{
curl_setopt($fp, CURLOPT_ENCODING, '');
}
curl_setopt($fp, CURLOPT_URL, $url);
curl_setopt($fp, CURLOPT_HEADER, 1);
curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($fp, CURLOPT_REFERER, $url);
curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
{
curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
}
$this->headers = curl_exec($fp);
if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
{
curl_setopt($fp, CURLOPT_ENCODING, 'none');
$this->headers = curl_exec($fp);
}
if (curl_errno($fp))
{
$this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
$this->success = false;
}
else
{
$info = curl_getinfo($fp);
curl_close($fp);
$this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
$this->headers = array_pop($this->headers);
$parser = new SimplePie_HTTP_Parser($this->headers);
if ($parser->parse())
{
$this->headers = $parser->headers;
$this->body = $parser->body;
$this->status_code = $parser->status_code;
if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
{
$this->redirects++;
$location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
}
}
}
}
else
{
$this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
$url_parts = parse_url($url);
$socket_host = $url_parts['host'];
if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
{
$socket_host = "ssl://$url_parts[host]";
$url_parts['port'] = 443;
}
if (!isset($url_parts['port']))
{
$url_parts['port'] = 80;
}
$fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
if (!$fp)
{
$this->error = 'fsockopen error: ' . $errstr;
$this->success = false;
}
else
{
stream_set_timeout($fp, $timeout);
if (isset($url_parts['path']))
{
if (isset($url_parts['query']))
{
$get = "$url_parts[path]?$url_parts[query]";
}
else
{
$get = $url_parts['path'];
}
}
else
{
$get = '/';
}
$out = "GET $get HTTP/1.1\r\n";
$out .= "Host: $url_parts[host]\r\n";
$out .= "User-Agent: $useragent\r\n";
if (extension_loaded('zlib'))
{
$out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
}
if (isset($url_parts['user']) && isset($url_parts['pass']))
{
$out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
}
foreach ($headers as $key => $value)
{
$out .= "$key: $value\r\n";
}
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
$info = stream_get_meta_data($fp);
$this->headers = '';
while (!$info['eof'] && !$info['timed_out'])
{
$this->headers .= fread($fp, 1160);
$info = stream_get_meta_data($fp);
}
if (!$info['timed_out'])
{
$parser = new SimplePie_HTTP_Parser($this->headers);
if ($parser->parse())
{
$this->headers = $parser->headers;
$this->body = $parser->body;
$this->status_code = $parser->status_code;
if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
{
$this->redirects++;
$location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
}
if (isset($this->headers['content-encoding']))
{
// Hey, we act dumb elsewhere, so let's do that here too
switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
{
case 'gzip':
case 'x-gzip':
$decoder = new SimplePie_gzdecode($this->body);
if (!$decoder->parse())
{
$this->error = 'Unable to decode HTTP "gzip" stream';
$this->success = false;
}
else
{
$this->body = $decoder->data;
}
break;
case 'deflate':
if (($decompressed = gzinflate($this->body)) !== false)
{
$this->body = $decompressed;
}
else if (($decompressed = gzuncompress($this->body)) !== false)
{
$this->body = $decompressed;
}
else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
{
$this->body = $decompressed;
}
else
{
$this->error = 'Unable to decode HTTP "deflate" stream';
$this->success = false;
}
break;
default:
$this->error = 'Unknown content coding';
$this->success = false;
}
}
}
}
else
{
$this->error = 'fsocket timed out';
$this->success = false;
}
fclose($fp);
}
}
}
else
{
$this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
if (!$this->body = file_get_contents($url))
{
$this->error = 'file_get_contents could not read the file';
$this->success = false;
}
}
}
}

View File

@ -0,0 +1,500 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* HTTP Response Parser
*
* @package SimplePie
* @subpackage HTTP
*/
class SimplePie_HTTP_Parser
{
/**
* HTTP Version
*
* @var float
*/
public $http_version = 0.0;
/**
* Status code
*
* @var int
*/
public $status_code = 0;
/**
* Reason phrase
*
* @var string
*/
public $reason = '';
/**
* Key/value pairs of the headers
*
* @var array
*/
public $headers = array();
/**
* Body of the response
*
* @var string
*/
public $body = '';
/**
* Current state of the state machine
*
* @var string
*/
protected $state = 'http_version';
/**
* Input data
*
* @var string
*/
protected $data = '';
/**
* Input data length (to avoid calling strlen() everytime this is needed)
*
* @var int
*/
protected $data_length = 0;
/**
* Current position of the pointer
*
* @var int
*/
protected $position = 0;
/**
* Name of the hedaer currently being parsed
*
* @var string
*/
protected $name = '';
/**
* Value of the hedaer currently being parsed
*
* @var string
*/
protected $value = '';
/**
* Create an instance of the class with the input data
*
* @param string $data Input data
*/
public function __construct($data)
{
$this->data = $data;
$this->data_length = strlen($this->data);
}
/**
* Parse the input data
*
* @return bool true on success, false on failure
*/
public function parse()
{
while ($this->state && $this->state !== 'emit' && $this->has_data())
{
$state = $this->state;
$this->$state();
}
$this->data = '';
if ($this->state === 'emit' || $this->state === 'body')
{
return true;
}
else
{
$this->http_version = '';
$this->status_code = '';
$this->reason = '';
$this->headers = array();
$this->body = '';
return false;
}
}
/**
* Check whether there is data beyond the pointer
*
* @return bool true if there is further data, false if not
*/
protected function has_data()
{
return (bool) ($this->position < $this->data_length);
}
/**
* See if the next character is LWS
*
* @return bool true if the next character is LWS, false if not
*/
protected function is_linear_whitespace()
{
return (bool) ($this->data[$this->position] === "\x09"
|| $this->data[$this->position] === "\x20"
|| ($this->data[$this->position] === "\x0A"
&& isset($this->data[$this->position + 1])
&& ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
}
/**
* Parse the HTTP version
*/
protected function http_version()
{
if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
{
$len = strspn($this->data, '0123456789.', 5);
$this->http_version = substr($this->data, 5, $len);
$this->position += 5 + $len;
if (substr_count($this->http_version, '.') <= 1)
{
$this->http_version = (float) $this->http_version;
$this->position += strspn($this->data, "\x09\x20", $this->position);
$this->state = 'status';
}
else
{
$this->state = false;
}
}
else
{
$this->state = false;
}
}
/**
* Parse the status code
*/
protected function status()
{
if ($len = strspn($this->data, '0123456789', $this->position))
{
$this->status_code = (int) substr($this->data, $this->position, $len);
$this->position += $len;
$this->state = 'reason';
}
else
{
$this->state = false;
}
}
/**
* Parse the reason phrase
*/
protected function reason()
{
$len = strcspn($this->data, "\x0A", $this->position);
$this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
$this->position += $len + 1;
$this->state = 'new_line';
}
/**
* Deal with a new line, shifting data around as needed
*/
protected function new_line()
{
$this->value = trim($this->value, "\x0D\x20");
if ($this->name !== '' && $this->value !== '')
{
$this->name = strtolower($this->name);
// We should only use the last Content-Type header. c.f. issue #1
if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
{
$this->headers[$this->name] .= ', ' . $this->value;
}
else
{
$this->headers[$this->name] = $this->value;
}
}
$this->name = '';
$this->value = '';
if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
{
$this->position += 2;
$this->state = 'body';
}
elseif ($this->data[$this->position] === "\x0A")
{
$this->position++;
$this->state = 'body';
}
else
{
$this->state = 'name';
}
}
/**
* Parse a header name
*/
protected function name()
{
$len = strcspn($this->data, "\x0A:", $this->position);
if (isset($this->data[$this->position + $len]))
{
if ($this->data[$this->position + $len] === "\x0A")
{
$this->position += $len;
$this->state = 'new_line';
}
else
{
$this->name = substr($this->data, $this->position, $len);
$this->position += $len + 1;
$this->state = 'value';
}
}
else
{
$this->state = false;
}
}
/**
* Parse LWS, replacing consecutive LWS characters with a single space
*/
protected function linear_whitespace()
{
do
{
if (substr($this->data, $this->position, 2) === "\x0D\x0A")
{
$this->position += 2;
}
elseif ($this->data[$this->position] === "\x0A")
{
$this->position++;
}
$this->position += strspn($this->data, "\x09\x20", $this->position);
} while ($this->has_data() && $this->is_linear_whitespace());
$this->value .= "\x20";
}
/**
* See what state to move to while within non-quoted header values
*/
protected function value()
{
if ($this->is_linear_whitespace())
{
$this->linear_whitespace();
}
else
{
switch ($this->data[$this->position])
{
case '"':
// Workaround for ETags: we have to include the quotes as
// part of the tag.
if (strtolower($this->name) === 'etag')
{
$this->value .= '"';
$this->position++;
$this->state = 'value_char';
break;
}
$this->position++;
$this->state = 'quote';
break;
case "\x0A":
$this->position++;
$this->state = 'new_line';
break;
default:
$this->state = 'value_char';
break;
}
}
}
/**
* Parse a header value while outside quotes
*/
protected function value_char()
{
$len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
$this->value .= substr($this->data, $this->position, $len);
$this->position += $len;
$this->state = 'value';
}
/**
* See what state to move to while within quoted header values
*/
protected function quote()
{
if ($this->is_linear_whitespace())
{
$this->linear_whitespace();
}
else
{
switch ($this->data[$this->position])
{
case '"':
$this->position++;
$this->state = 'value';
break;
case "\x0A":
$this->position++;
$this->state = 'new_line';
break;
case '\\':
$this->position++;
$this->state = 'quote_escaped';
break;
default:
$this->state = 'quote_char';
break;
}
}
}
/**
* Parse a header value while within quotes
*/
protected function quote_char()
{
$len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
$this->value .= substr($this->data, $this->position, $len);
$this->position += $len;
$this->state = 'value';
}
/**
* Parse an escaped character within quotes
*/
protected function quote_escaped()
{
$this->value .= $this->data[$this->position];
$this->position++;
$this->state = 'quote';
}
/**
* Parse the body
*/
protected function body()
{
$this->body = substr($this->data, $this->position);
if (!empty($this->headers['transfer-encoding']))
{
unset($this->headers['transfer-encoding']);
$this->state = 'chunked';
}
else
{
$this->state = 'emit';
}
}
/**
* Parsed a "Transfer-Encoding: chunked" body
*/
protected function chunked()
{
if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
{
$this->state = 'emit';
return;
}
$decoded = '';
$encoded = $this->body;
while (true)
{
$is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
if (!$is_chunked)
{
// Looks like it's not chunked after all
$this->state = 'emit';
return;
}
$length = hexdec(trim($matches[1]));
if ($length === 0)
{
// Ignore trailer headers
$this->state = 'emit';
$this->body = $decoded;
return;
}
$chunk_length = strlen($matches[0]);
$decoded .= $part = substr($encoded, $chunk_length, $length);
$encoded = substr($encoded, $chunk_length + $length + 2);
if (trim($encoded) === '0' || empty($encoded))
{
$this->state = 'emit';
$this->body = $decoded;
return;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,372 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Used for feed auto-discovery
*
*
* This class can be overloaded with {@see SimplePie::set_locator_class()}
*
* @package SimplePie
*/
class SimplePie_Locator
{
var $useragent;
var $timeout;
var $file;
var $local = array();
var $elsewhere = array();
var $cached_entities = array();
var $http_base;
var $base;
var $base_location = 0;
var $checked_feeds = 0;
var $max_checked_feeds = 10;
protected $registry;
public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
{
$this->file = $file;
$this->useragent = $useragent;
$this->timeout = $timeout;
$this->max_checked_feeds = $max_checked_feeds;
if (class_exists('DOMDocument'))
{
$this->dom = new DOMDocument();
set_error_handler(array('SimplePie_Misc', 'silence_errors'));
$this->dom->loadHTML($this->file->body);
restore_error_handler();
}
else
{
$this->dom = null;
}
}
public function set_registry(SimplePie_Registry $registry)
{
$this->registry = $registry;
}
public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
{
if ($this->is_feed($this->file))
{
return $this->file;
}
if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
{
$sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
if ($sniffer->get_type() !== 'text/html')
{
return null;
}
}
if ($type & ~SIMPLEPIE_LOCATOR_NONE)
{
$this->get_base();
}
if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
{
return $working[0];
}
if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
{
if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
{
return $working;
}
if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
{
return $working;
}
if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
{
return $working;
}
if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
{
return $working;
}
}
return null;
}
public function is_feed($file)
{
if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
{
$sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
$sniffed = $sniffer->get_type();
if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
{
return true;
}
else
{
return false;
}
}
elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
{
return true;
}
else
{
return false;
}
}
public function get_base()
{
if ($this->dom === null)
{
throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
}
$this->http_base = $this->file->url;
$this->base = $this->http_base;
$elements = $this->dom->getElementsByTagName('base');
foreach ($elements as $element)
{
if ($element->hasAttribute('href'))
{
$base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
if ($base === false)
{
continue;
}
$this->base = $base;
$this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
break;
}
}
}
public function autodiscovery()
{
$done = array();
$feeds = array();
$feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
$feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
$feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
if (!empty($feeds))
{
return array_values($feeds);
}
else
{
return null;
}
}
protected function search_elements_by_tag($name, &$done, $feeds)
{
if ($this->dom === null)
{
throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
}
$links = $this->dom->getElementsByTagName($name);
foreach ($links as $link)
{
if ($this->checked_feeds === $this->max_checked_feeds)
{
break;
}
if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
{
$rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
$line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
if ($this->base_location < $line)
{
$href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
}
else
{
$href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
}
if ($href === false)
{
continue;
}
if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
{
$this->checked_feeds++;
$headers = array(
'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
);
$feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
{
$feeds[$href] = $feed;
}
}
$done[] = $href;
}
}
return $feeds;
}
public function get_links()
{
if ($this->dom === null)
{
throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
}
$links = $this->dom->getElementsByTagName('a');
foreach ($links as $link)
{
if ($link->hasAttribute('href'))
{
$href = trim($link->getAttribute('href'));
$parsed = $this->registry->call('Misc', 'parse_url', array($href));
if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
{
if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo())
{
$href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
}
else
{
$href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
}
if ($href === false)
{
continue;
}
$current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
{
$this->local[] = $href;
}
else
{
$this->elsewhere[] = $href;
}
}
}
}
$this->local = array_unique($this->local);
$this->elsewhere = array_unique($this->elsewhere);
if (!empty($this->local) || !empty($this->elsewhere))
{
return true;
}
return null;
}
public function extension(&$array)
{
foreach ($array as $key => $value)
{
if ($this->checked_feeds === $this->max_checked_feeds)
{
break;
}
if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
{
$this->checked_feeds++;
$headers = array(
'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
);
$feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
{
return $feed;
}
else
{
unset($array[$key]);
}
}
}
return null;
}
public function body(&$array)
{
foreach ($array as $key => $value)
{
if ($this->checked_feeds === $this->max_checked_feeds)
{
break;
}
if (preg_match('/(rss|rdf|atom|xml)/i', $value))
{
$this->checked_feeds++;
$headers = array(
'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
);
$feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
{
return $feed;
}
else
{
unset($array[$key]);
}
}
}
return null;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,276 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Class to validate and to work with IPv6 addresses.
*
* @package SimplePie
* @subpackage HTTP
* @copyright 2003-2005 The PHP Group
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/package/Net_IPv6
* @author Alexander Merz <alexander.merz@web.de>
* @author elfrink at introweb dot nl
* @author Josh Peck <jmp at joshpeck dot org>
* @author Geoffrey Sneddon <geoffers@gmail.com>
*/
class SimplePie_Net_IPv6
{
/**
* Uncompresses an IPv6 address
*
* RFC 4291 allows you to compress concecutive zero pieces in an address to
* '::'. This method expects a valid IPv6 address and expands the '::' to
* the required number of zero pieces.
*
* Example: FF01::101 -> FF01:0:0:0:0:0:0:101
* ::1 -> 0:0:0:0:0:0:0:1
*
* @author Alexander Merz <alexander.merz@web.de>
* @author elfrink at introweb dot nl
* @author Josh Peck <jmp at joshpeck dot org>
* @copyright 2003-2005 The PHP Group
* @license http://www.opensource.org/licenses/bsd-license.php
* @param string $ip An IPv6 address
* @return string The uncompressed IPv6 address
*/
public static function uncompress($ip)
{
$c1 = -1;
$c2 = -1;
if (substr_count($ip, '::') === 1)
{
list($ip1, $ip2) = explode('::', $ip);
if ($ip1 === '')
{
$c1 = -1;
}
else
{
$c1 = substr_count($ip1, ':');
}
if ($ip2 === '')
{
$c2 = -1;
}
else
{
$c2 = substr_count($ip2, ':');
}
if (strpos($ip2, '.') !== false)
{
$c2++;
}
// ::
if ($c1 === -1 && $c2 === -1)
{
$ip = '0:0:0:0:0:0:0:0';
}
// ::xxx
else if ($c1 === -1)
{
$fill = str_repeat('0:', 7 - $c2);
$ip = str_replace('::', $fill, $ip);
}
// xxx::
else if ($c2 === -1)
{
$fill = str_repeat(':0', 7 - $c1);
$ip = str_replace('::', $fill, $ip);
}
// xxx::xxx
else
{
$fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
$ip = str_replace('::', $fill, $ip);
}
}
return $ip;
}
/**
* Compresses an IPv6 address
*
* RFC 4291 allows you to compress concecutive zero pieces in an address to
* '::'. This method expects a valid IPv6 address and compresses consecutive
* zero pieces to '::'.
*
* Example: FF01:0:0:0:0:0:0:101 -> FF01::101
* 0:0:0:0:0:0:0:1 -> ::1
*
* @see uncompress()
* @param string $ip An IPv6 address
* @return string The compressed IPv6 address
*/
public static function compress($ip)
{
// Prepare the IP to be compressed
$ip = self::uncompress($ip);
$ip_parts = self::split_v6_v4($ip);
// Replace all leading zeros
$ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
// Find bunches of zeros
if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
{
$max = 0;
$pos = null;
foreach ($matches[0] as $match)
{
if (strlen($match[0]) > $max)
{
$max = strlen($match[0]);
$pos = $match[1];
}
}
$ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
}
if ($ip_parts[1] !== '')
{
return implode(':', $ip_parts);
}
else
{
return $ip_parts[0];
}
}
/**
* Splits an IPv6 address into the IPv6 and IPv4 representation parts
*
* RFC 4291 allows you to represent the last two parts of an IPv6 address
* using the standard IPv4 representation
*
* Example: 0:0:0:0:0:0:13.1.68.3
* 0:0:0:0:0:FFFF:129.144.52.38
*
* @param string $ip An IPv6 address
* @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
*/
private static function split_v6_v4($ip)
{
if (strpos($ip, '.') !== false)
{
$pos = strrpos($ip, ':');
$ipv6_part = substr($ip, 0, $pos);
$ipv4_part = substr($ip, $pos + 1);
return array($ipv6_part, $ipv4_part);
}
else
{
return array($ip, '');
}
}
/**
* Checks an IPv6 address
*
* Checks if the given IP is a valid IPv6 address
*
* @param string $ip An IPv6 address
* @return bool true if $ip is a valid IPv6 address
*/
public static function check_ipv6($ip)
{
$ip = self::uncompress($ip);
list($ipv6, $ipv4) = self::split_v6_v4($ip);
$ipv6 = explode(':', $ipv6);
$ipv4 = explode('.', $ipv4);
if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
{
foreach ($ipv6 as $ipv6_part)
{
// The section can't be empty
if ($ipv6_part === '')
return false;
// Nor can it be over four characters
if (strlen($ipv6_part) > 4)
return false;
// Remove leading zeros (this is safe because of the above)
$ipv6_part = ltrim($ipv6_part, '0');
if ($ipv6_part === '')
$ipv6_part = '0';
// Check the value is valid
$value = hexdec($ipv6_part);
if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
return false;
}
if (count($ipv4) === 4)
{
foreach ($ipv4 as $ipv4_part)
{
$value = (int) $ipv4_part;
if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
return false;
}
}
return true;
}
else
{
return false;
}
}
/**
* Checks if the given IP is a valid IPv6 address
*
* @codeCoverageIgnore
* @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
* @see check_ipv6
* @param string $ip An IPv6 address
* @return bool true if $ip is a valid IPv6 address
*/
public static function checkIPv6($ip)
{
return self::check_ipv6($ip);
}
}

View File

@ -0,0 +1,983 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Date Parser
*
* @package SimplePie
* @subpackage Parsing
*/
class SimplePie_Parse_Date
{
/**
* Input data
*
* @access protected
* @var string
*/
var $date;
/**
* List of days, calendar day name => ordinal day number in the week
*
* @access protected
* @var array
*/
var $day = array(
// English
'mon' => 1,
'monday' => 1,
'tue' => 2,
'tuesday' => 2,
'wed' => 3,
'wednesday' => 3,
'thu' => 4,
'thursday' => 4,
'fri' => 5,
'friday' => 5,
'sat' => 6,
'saturday' => 6,
'sun' => 7,
'sunday' => 7,
// Dutch
'maandag' => 1,
'dinsdag' => 2,
'woensdag' => 3,
'donderdag' => 4,
'vrijdag' => 5,
'zaterdag' => 6,
'zondag' => 7,
// French
'lundi' => 1,
'mardi' => 2,
'mercredi' => 3,
'jeudi' => 4,
'vendredi' => 5,
'samedi' => 6,
'dimanche' => 7,
// German
'montag' => 1,
'dienstag' => 2,
'mittwoch' => 3,
'donnerstag' => 4,
'freitag' => 5,
'samstag' => 6,
'sonnabend' => 6,
'sonntag' => 7,
// Italian
'lunedì' => 1,
'martedì' => 2,
'mercoledì' => 3,
'giovedì' => 4,
'venerdì' => 5,
'sabato' => 6,
'domenica' => 7,
// Spanish
'lunes' => 1,
'martes' => 2,
'miércoles' => 3,
'jueves' => 4,
'viernes' => 5,
'sábado' => 6,
'domingo' => 7,
// Finnish
'maanantai' => 1,
'tiistai' => 2,
'keskiviikko' => 3,
'torstai' => 4,
'perjantai' => 5,
'lauantai' => 6,
'sunnuntai' => 7,
// Hungarian
'hétfő' => 1,
'kedd' => 2,
'szerda' => 3,
'csütörtok' => 4,
'péntek' => 5,
'szombat' => 6,
'vasárnap' => 7,
// Greek
'Δευ' => 1,
'Τρι' => 2,
'Τετ' => 3,
'Πεμ' => 4,
'Παρ' => 5,
'Σαβ' => 6,
'Κυρ' => 7,
);
/**
* List of months, calendar month name => calendar month number
*
* @access protected
* @var array
*/
var $month = array(
// English
'jan' => 1,
'january' => 1,
'feb' => 2,
'february' => 2,
'mar' => 3,
'march' => 3,
'apr' => 4,
'april' => 4,
'may' => 5,
// No long form of May
'jun' => 6,
'june' => 6,
'jul' => 7,
'july' => 7,
'aug' => 8,
'august' => 8,
'sep' => 9,
'september' => 8,
'oct' => 10,
'october' => 10,
'nov' => 11,
'november' => 11,
'dec' => 12,
'december' => 12,
// Dutch
'januari' => 1,
'februari' => 2,
'maart' => 3,
'april' => 4,
'mei' => 5,
'juni' => 6,
'juli' => 7,
'augustus' => 8,
'september' => 9,
'oktober' => 10,
'november' => 11,
'december' => 12,
// French
'janvier' => 1,
'février' => 2,
'mars' => 3,
'avril' => 4,
'mai' => 5,
'juin' => 6,
'juillet' => 7,
'août' => 8,
'septembre' => 9,
'octobre' => 10,
'novembre' => 11,
'décembre' => 12,
// German
'januar' => 1,
'februar' => 2,
'märz' => 3,
'april' => 4,
'mai' => 5,
'juni' => 6,
'juli' => 7,
'august' => 8,
'september' => 9,
'oktober' => 10,
'november' => 11,
'dezember' => 12,
// Italian
'gennaio' => 1,
'febbraio' => 2,
'marzo' => 3,
'aprile' => 4,
'maggio' => 5,
'giugno' => 6,
'luglio' => 7,
'agosto' => 8,
'settembre' => 9,
'ottobre' => 10,
'novembre' => 11,
'dicembre' => 12,
// Spanish
'enero' => 1,
'febrero' => 2,
'marzo' => 3,
'abril' => 4,
'mayo' => 5,
'junio' => 6,
'julio' => 7,
'agosto' => 8,
'septiembre' => 9,
'setiembre' => 9,
'octubre' => 10,
'noviembre' => 11,
'diciembre' => 12,
// Finnish
'tammikuu' => 1,
'helmikuu' => 2,
'maaliskuu' => 3,
'huhtikuu' => 4,
'toukokuu' => 5,
'kesäkuu' => 6,
'heinäkuu' => 7,
'elokuu' => 8,
'suuskuu' => 9,
'lokakuu' => 10,
'marras' => 11,
'joulukuu' => 12,
// Hungarian
'január' => 1,
'február' => 2,
'március' => 3,
'április' => 4,
'május' => 5,
'június' => 6,
'július' => 7,
'augusztus' => 8,
'szeptember' => 9,
'október' => 10,
'november' => 11,
'december' => 12,
// Greek
'Ιαν' => 1,
'Φεβ' => 2,
'Μάώ' => 3,
'Μαώ' => 3,
'Απρ' => 4,
'Μάι' => 5,
'Μαϊ' => 5,
'Μαι' => 5,
'Ιούν' => 6,
'Ιον' => 6,
'Ιούλ' => 7,
'Ιολ' => 7,
'Αύγ' => 8,
'Αυγ' => 8,
'Σεπ' => 9,
'Οκτ' => 10,
'Νοέ' => 11,
'Δεκ' => 12,
);
/**
* List of timezones, abbreviation => offset from UTC
*
* @access protected
* @var array
*/
var $timezone = array(
'ACDT' => 37800,
'ACIT' => 28800,
'ACST' => 34200,
'ACT' => -18000,
'ACWDT' => 35100,
'ACWST' => 31500,
'AEDT' => 39600,
'AEST' => 36000,
'AFT' => 16200,
'AKDT' => -28800,
'AKST' => -32400,
'AMDT' => 18000,
'AMT' => -14400,
'ANAST' => 46800,
'ANAT' => 43200,
'ART' => -10800,
'AZOST' => -3600,
'AZST' => 18000,
'AZT' => 14400,
'BIOT' => 21600,
'BIT' => -43200,
'BOT' => -14400,
'BRST' => -7200,
'BRT' => -10800,
'BST' => 3600,
'BTT' => 21600,
'CAST' => 18000,
'CAT' => 7200,
'CCT' => 23400,
'CDT' => -18000,
'CEDT' => 7200,
'CET' => 3600,
'CGST' => -7200,
'CGT' => -10800,
'CHADT' => 49500,
'CHAST' => 45900,
'CIST' => -28800,
'CKT' => -36000,
'CLDT' => -10800,
'CLST' => -14400,
'COT' => -18000,
'CST' => -21600,
'CVT' => -3600,
'CXT' => 25200,
'DAVT' => 25200,
'DTAT' => 36000,
'EADT' => -18000,
'EAST' => -21600,
'EAT' => 10800,
'ECT' => -18000,
'EDT' => -14400,
'EEST' => 10800,
'EET' => 7200,
'EGT' => -3600,
'EKST' => 21600,
'EST' => -18000,
'FJT' => 43200,
'FKDT' => -10800,
'FKST' => -14400,
'FNT' => -7200,
'GALT' => -21600,
'GEDT' => 14400,
'GEST' => 10800,
'GFT' => -10800,
'GILT' => 43200,
'GIT' => -32400,
'GST' => 14400,
'GST' => -7200,
'GYT' => -14400,
'HAA' => -10800,
'HAC' => -18000,
'HADT' => -32400,
'HAE' => -14400,
'HAP' => -25200,
'HAR' => -21600,
'HAST' => -36000,
'HAT' => -9000,
'HAY' => -28800,
'HKST' => 28800,
'HMT' => 18000,
'HNA' => -14400,
'HNC' => -21600,
'HNE' => -18000,
'HNP' => -28800,
'HNR' => -25200,
'HNT' => -12600,
'HNY' => -32400,
'IRDT' => 16200,
'IRKST' => 32400,
'IRKT' => 28800,
'IRST' => 12600,
'JFDT' => -10800,
'JFST' => -14400,
'JST' => 32400,
'KGST' => 21600,
'KGT' => 18000,
'KOST' => 39600,
'KOVST' => 28800,
'KOVT' => 25200,
'KRAST' => 28800,
'KRAT' => 25200,
'KST' => 32400,
'LHDT' => 39600,
'LHST' => 37800,
'LINT' => 50400,
'LKT' => 21600,
'MAGST' => 43200,
'MAGT' => 39600,
'MAWT' => 21600,
'MDT' => -21600,
'MESZ' => 7200,
'MEZ' => 3600,
'MHT' => 43200,
'MIT' => -34200,
'MNST' => 32400,
'MSDT' => 14400,
'MSST' => 10800,
'MST' => -25200,
'MUT' => 14400,
'MVT' => 18000,
'MYT' => 28800,
'NCT' => 39600,
'NDT' => -9000,
'NFT' => 41400,
'NMIT' => 36000,
'NOVST' => 25200,
'NOVT' => 21600,
'NPT' => 20700,
'NRT' => 43200,
'NST' => -12600,
'NUT' => -39600,
'NZDT' => 46800,
'NZST' => 43200,
'OMSST' => 25200,
'OMST' => 21600,
'PDT' => -25200,
'PET' => -18000,
'PETST' => 46800,
'PETT' => 43200,
'PGT' => 36000,
'PHOT' => 46800,
'PHT' => 28800,
'PKT' => 18000,
'PMDT' => -7200,
'PMST' => -10800,
'PONT' => 39600,
'PST' => -28800,
'PWT' => 32400,
'PYST' => -10800,
'PYT' => -14400,
'RET' => 14400,
'ROTT' => -10800,
'SAMST' => 18000,
'SAMT' => 14400,
'SAST' => 7200,
'SBT' => 39600,
'SCDT' => 46800,
'SCST' => 43200,
'SCT' => 14400,
'SEST' => 3600,
'SGT' => 28800,
'SIT' => 28800,
'SRT' => -10800,
'SST' => -39600,
'SYST' => 10800,
'SYT' => 7200,
'TFT' => 18000,
'THAT' => -36000,
'TJT' => 18000,
'TKT' => -36000,
'TMT' => 18000,
'TOT' => 46800,
'TPT' => 32400,
'TRUT' => 36000,
'TVT' => 43200,
'TWT' => 28800,
'UYST' => -7200,
'UYT' => -10800,
'UZT' => 18000,
'VET' => -14400,
'VLAST' => 39600,
'VLAT' => 36000,
'VOST' => 21600,
'VUT' => 39600,
'WAST' => 7200,
'WAT' => 3600,
'WDT' => 32400,
'WEST' => 3600,
'WFT' => 43200,
'WIB' => 25200,
'WIT' => 32400,
'WITA' => 28800,
'WKST' => 18000,
'WST' => 28800,
'YAKST' => 36000,
'YAKT' => 32400,
'YAPT' => 36000,
'YEKST' => 21600,
'YEKT' => 18000,
);
/**
* Cached PCRE for SimplePie_Parse_Date::$day
*
* @access protected
* @var string
*/
var $day_pcre;
/**
* Cached PCRE for SimplePie_Parse_Date::$month
*
* @access protected
* @var string
*/
var $month_pcre;
/**
* Array of user-added callback methods
*
* @access private
* @var array
*/
var $built_in = array();
/**
* Array of user-added callback methods
*
* @access private
* @var array
*/
var $user = array();
/**
* Create new SimplePie_Parse_Date object, and set self::day_pcre,
* self::month_pcre, and self::built_in
*
* @access private
*/
public function __construct()
{
$this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
$this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
static $cache;
if (!isset($cache[get_class($this)]))
{
$all_methods = get_class_methods($this);
foreach ($all_methods as $method)
{
if (strtolower(substr($method, 0, 5)) === 'date_')
{
$cache[get_class($this)][] = $method;
}
}
}
foreach ($cache[get_class($this)] as $method)
{
$this->built_in[] = $method;
}
}
/**
* Get the object
*
* @access public
*/
public static function get()
{
static $object;
if (!$object)
{
$object = new SimplePie_Parse_Date;
}
return $object;
}
/**
* Parse a date
*
* @final
* @access public
* @param string $date Date to parse
* @return int Timestamp corresponding to date string, or false on failure
*/
public function parse($date)
{
foreach ($this->user as $method)
{
if (($returned = call_user_func($method, $date)) !== false)
{
return $returned;
}
}
foreach ($this->built_in as $method)
{
if (($returned = call_user_func(array($this, $method), $date)) !== false)
{
return $returned;
}
}
return false;
}
/**
* Add a callback method to parse a date
*
* @final
* @access public
* @param callback $callback
*/
public function add_callback($callback)
{
if (is_callable($callback))
{
$this->user[] = $callback;
}
else
{
trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
}
}
/**
* Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
* well as allowing any of upper or lower case "T", horizontal tabs, or
* spaces to be used as the time seperator (including more than one))
*
* @access protected
* @return int Timestamp
*/
public function date_w3cdtf($date)
{
static $pcre;
if (!$pcre)
{
$year = '([0-9]{4})';
$month = $day = $hour = $minute = $second = '([0-9]{2})';
$decimal = '([0-9]*)';
$zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
$pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
}
if (preg_match($pcre, $date, $match))
{
/*
Capturing subpatterns:
1: Year
2: Month
3: Day
4: Hour
5: Minute
6: Second
7: Decimal fraction of a second
8: Zulu
9: Timezone ±
10: Timezone hours
11: Timezone minutes
*/
// Fill in empty matches
for ($i = count($match); $i <= 3; $i++)
{
$match[$i] = '1';
}
for ($i = count($match); $i <= 7; $i++)
{
$match[$i] = '0';
}
// Numeric timezone
if (isset($match[9]) && $match[9] !== '')
{
$timezone = $match[10] * 3600;
$timezone += $match[11] * 60;
if ($match[9] === '-')
{
$timezone = 0 - $timezone;
}
}
else
{
$timezone = 0;
}
// Convert the number of seconds to an integer, taking decimals into account
$second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
}
else
{
return false;
}
}
/**
* Remove RFC822 comments
*
* @access protected
* @param string $data Data to strip comments from
* @return string Comment stripped string
*/
public function remove_rfc2822_comments($string)
{
$string = (string) $string;
$position = 0;
$length = strlen($string);
$depth = 0;
$output = '';
while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
{
$output .= substr($string, $position, $pos - $position);
$position = $pos + 1;
if ($string[$pos - 1] !== '\\')
{
$depth++;
while ($depth && $position < $length)
{
$position += strcspn($string, '()', $position);
if ($string[$position - 1] === '\\')
{
$position++;
continue;
}
elseif (isset($string[$position]))
{
switch ($string[$position])
{
case '(':
$depth++;
break;
case ')':
$depth--;
break;
}
$position++;
}
else
{
break;
}
}
}
else
{
$output .= '(';
}
}
$output .= substr($string, $position);
return $output;
}
/**
* Parse RFC2822's date format
*
* @access protected
* @return int Timestamp
*/
public function date_rfc2822($date)
{
static $pcre;
if (!$pcre)
{
$wsp = '[\x09\x20]';
$fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
$optional_fws = $fws . '?';
$day_name = $this->day_pcre;
$month = $this->month_pcre;
$day = '([0-9]{1,2})';
$hour = $minute = $second = '([0-9]{2})';
$year = '([0-9]{2,4})';
$num_zone = '([+\-])([0-9]{2})([0-9]{2})';
$character_zone = '([A-Z]{1,5})';
$zone = '(?:' . $num_zone . '|' . $character_zone . ')';
$pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
}
if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
{
/*
Capturing subpatterns:
1: Day name
2: Day
3: Month
4: Year
5: Hour
6: Minute
7: Second
8: Timezone ±
9: Timezone hours
10: Timezone minutes
11: Alphabetic timezone
*/
// Find the month number
$month = $this->month[strtolower($match[3])];
// Numeric timezone
if ($match[8] !== '')
{
$timezone = $match[9] * 3600;
$timezone += $match[10] * 60;
if ($match[8] === '-')
{
$timezone = 0 - $timezone;
}
}
// Character timezone
elseif (isset($this->timezone[strtoupper($match[11])]))
{
$timezone = $this->timezone[strtoupper($match[11])];
}
// Assume everything else to be -0000
else
{
$timezone = 0;
}
// Deal with 2/3 digit years
if ($match[4] < 50)
{
$match[4] += 2000;
}
elseif ($match[4] < 1000)
{
$match[4] += 1900;
}
// Second is optional, if it is empty set it to zero
if ($match[7] !== '')
{
$second = $match[7];
}
else
{
$second = 0;
}
return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
}
else
{
return false;
}
}
/**
* Parse RFC850's date format
*
* @access protected
* @return int Timestamp
*/
public function date_rfc850($date)
{
static $pcre;
if (!$pcre)
{
$space = '[\x09\x20]+';
$day_name = $this->day_pcre;
$month = $this->month_pcre;
$day = '([0-9]{1,2})';
$year = $hour = $minute = $second = '([0-9]{2})';
$zone = '([A-Z]{1,5})';
$pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
}
if (preg_match($pcre, $date, $match))
{
/*
Capturing subpatterns:
1: Day name
2: Day
3: Month
4: Year
5: Hour
6: Minute
7: Second
8: Timezone
*/
// Month
$month = $this->month[strtolower($match[3])];
// Character timezone
if (isset($this->timezone[strtoupper($match[8])]))
{
$timezone = $this->timezone[strtoupper($match[8])];
}
// Assume everything else to be -0000
else
{
$timezone = 0;
}
// Deal with 2 digit year
if ($match[4] < 50)
{
$match[4] += 2000;
}
else
{
$match[4] += 1900;
}
return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
}
else
{
return false;
}
}
/**
* Parse C99's asctime()'s date format
*
* @access protected
* @return int Timestamp
*/
public function date_asctime($date)
{
static $pcre;
if (!$pcre)
{
$space = '[\x09\x20]+';
$wday_name = $this->day_pcre;
$mon_name = $this->month_pcre;
$day = '([0-9]{1,2})';
$hour = $sec = $min = '([0-9]{2})';
$year = '([0-9]{4})';
$terminator = '\x0A?\x00?';
$pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
}
if (preg_match($pcre, $date, $match))
{
/*
Capturing subpatterns:
1: Day name
2: Month
3: Day
4: Hour
5: Minute
6: Second
7: Year
*/
$month = $this->month[strtolower($match[2])];
return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
}
else
{
return false;
}
}
/**
* Parse dates using strtotime()
*
* @access protected
* @return int Timestamp
*/
public function date_strtotime($date)
{
$strtotime = strtotime($date);
if ($strtotime === -1 || $strtotime === false)
{
return false;
}
else
{
return $strtotime;
}
}
}

View File

@ -0,0 +1,407 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Parses XML into something sane
*
*
* This class can be overloaded with {@see SimplePie::set_parser_class()}
*
* @package SimplePie
* @subpackage Parsing
*/
class SimplePie_Parser
{
var $error_code;
var $error_string;
var $current_line;
var $current_column;
var $current_byte;
var $separator = ' ';
var $namespace = array('');
var $element = array('');
var $xml_base = array('');
var $xml_base_explicit = array(false);
var $xml_lang = array('');
var $data = array();
var $datas = array(array());
var $current_xhtml_construct = -1;
var $encoding;
protected $registry;
public function set_registry(SimplePie_Registry $registry)
{
$this->registry = $registry;
}
public function parse(&$data, $encoding)
{
// Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
if (strtoupper($encoding) === 'US-ASCII')
{
$this->encoding = 'UTF-8';
}
else
{
$this->encoding = $encoding;
}
// Strip BOM:
// UTF-32 Big Endian BOM
if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
{
$data = substr($data, 4);
}
// UTF-32 Little Endian BOM
elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
{
$data = substr($data, 4);
}
// UTF-16 Big Endian BOM
elseif (substr($data, 0, 2) === "\xFE\xFF")
{
$data = substr($data, 2);
}
// UTF-16 Little Endian BOM
elseif (substr($data, 0, 2) === "\xFF\xFE")
{
$data = substr($data, 2);
}
// UTF-8 BOM
elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
{
$data = substr($data, 3);
}
if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
{
$declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
if ($declaration->parse())
{
$data = substr($data, $pos + 2);
$data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
}
else
{
$this->error_string = 'SimplePie bug! Please report this!';
return false;
}
}
$return = true;
static $xml_is_sane = null;
if ($xml_is_sane === null)
{
$parser_check = xml_parser_create();
xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
xml_parser_free($parser_check);
$xml_is_sane = isset($values[0]['value']);
}
// Create the parser
if ($xml_is_sane)
{
$xml = xml_parser_create_ns($this->encoding, $this->separator);
xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
xml_set_object($xml, $this);
xml_set_character_data_handler($xml, 'cdata');
xml_set_element_handler($xml, 'tag_open', 'tag_close');
// Parse!
if (!xml_parse($xml, $data, true))
{
$this->error_code = xml_get_error_code($xml);
$this->error_string = xml_error_string($this->error_code);
$return = false;
}
$this->current_line = xml_get_current_line_number($xml);
$this->current_column = xml_get_current_column_number($xml);
$this->current_byte = xml_get_current_byte_index($xml);
xml_parser_free($xml);
return $return;
}
else
{
libxml_clear_errors();
$xml = new XMLReader();
$xml->xml($data);
while (@$xml->read())
{
switch ($xml->nodeType)
{
case constant('XMLReader::END_ELEMENT'):
if ($xml->namespaceURI !== '')
{
$tagName = $xml->namespaceURI . $this->separator . $xml->localName;
}
else
{
$tagName = $xml->localName;
}
$this->tag_close(null, $tagName);
break;
case constant('XMLReader::ELEMENT'):
$empty = $xml->isEmptyElement;
if ($xml->namespaceURI !== '')
{
$tagName = $xml->namespaceURI . $this->separator . $xml->localName;
}
else
{
$tagName = $xml->localName;
}
$attributes = array();
while ($xml->moveToNextAttribute())
{
if ($xml->namespaceURI !== '')
{
$attrName = $xml->namespaceURI . $this->separator . $xml->localName;
}
else
{
$attrName = $xml->localName;
}
$attributes[$attrName] = $xml->value;
}
$this->tag_open(null, $tagName, $attributes);
if ($empty)
{
$this->tag_close(null, $tagName);
}
break;
case constant('XMLReader::TEXT'):
case constant('XMLReader::CDATA'):
$this->cdata(null, $xml->value);
break;
}
}
if ($error = libxml_get_last_error())
{
$this->error_code = $error->code;
$this->error_string = $error->message;
$this->current_line = $error->line;
$this->current_column = $error->column;
return false;
}
else
{
return true;
}
}
}
public function get_error_code()
{
return $this->error_code;
}
public function get_error_string()
{
return $this->error_string;
}
public function get_current_line()
{
return $this->current_line;
}
public function get_current_column()
{
return $this->current_column;
}
public function get_current_byte()
{
return $this->current_byte;
}
public function get_data()
{
return $this->data;
}
public function tag_open($parser, $tag, $attributes)
{
list($this->namespace[], $this->element[]) = $this->split_ns($tag);
$attribs = array();
foreach ($attributes as $name => $value)
{
list($attrib_namespace, $attribute) = $this->split_ns($name);
$attribs[$attrib_namespace][$attribute] = $value;
}
if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
{
$base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
if ($base !== false)
{
$this->xml_base[] = $base;
$this->xml_base_explicit[] = true;
}
}
else
{
$this->xml_base[] = end($this->xml_base);
$this->xml_base_explicit[] = end($this->xml_base_explicit);
}
if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
{
$this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
}
else
{
$this->xml_lang[] = end($this->xml_lang);
}
if ($this->current_xhtml_construct >= 0)
{
$this->current_xhtml_construct++;
if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
{
$this->data['data'] .= '<' . end($this->element);
if (isset($attribs['']))
{
foreach ($attribs[''] as $name => $value)
{
$this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
}
}
$this->data['data'] .= '>';
}
}
else
{
$this->datas[] =& $this->data;
$this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
$this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml')
|| (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml')
|| (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
|| (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
|| (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
{
$this->current_xhtml_construct = 0;
}
}
}
public function cdata($parser, $cdata)
{
if ($this->current_xhtml_construct >= 0)
{
$this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
}
else
{
$this->data['data'] .= $cdata;
}
}
public function tag_close($parser, $tag)
{
if ($this->current_xhtml_construct >= 0)
{
$this->current_xhtml_construct--;
if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param')))
{
$this->data['data'] .= '</' . end($this->element) . '>';
}
}
if ($this->current_xhtml_construct === -1)
{
$this->data =& $this->datas[count($this->datas) - 1];
array_pop($this->datas);
}
array_pop($this->element);
array_pop($this->namespace);
array_pop($this->xml_base);
array_pop($this->xml_base_explicit);
array_pop($this->xml_lang);
}
public function split_ns($string)
{
static $cache = array();
if (!isset($cache[$string]))
{
if ($pos = strpos($string, $this->separator))
{
static $separator_length;
if (!$separator_length)
{
$separator_length = strlen($this->separator);
}
$namespace = substr($string, 0, $pos);
$local_name = substr($string, $pos + $separator_length);
if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
{
$namespace = SIMPLEPIE_NAMESPACE_ITUNES;
}
// Normalize the Media RSS namespaces
if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
$namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
$namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
$namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
$namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
{
$namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
}
$cache[$string] = array($namespace, $local_name);
}
else
{
$cache[$string] = array('', $string);
}
}
return $cache[$string];
}
}

View File

@ -0,0 +1,129 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
*
* Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
*
* This class can be overloaded with {@see SimplePie::set_rating_class()}
*
* @package SimplePie
* @subpackage API
*/
class SimplePie_Rating
{
/**
* Rating scheme
*
* @var string
* @see get_scheme()
*/
var $scheme;
/**
* Rating value
*
* @var string
* @see get_value()
*/
var $value;
/**
* Constructor, used to input the data
*
* For documentation on all the parameters, see the corresponding
* properties and their accessors
*/
public function __construct($scheme = null, $value = null)
{
$this->scheme = $scheme;
$this->value = $value;
}
/**
* String-ified version
*
* @return string
*/
public function __toString()
{
// There is no $this->data here
return md5(serialize($this));
}
/**
* Get the organizational scheme for the rating
*
* @return string|null
*/
public function get_scheme()
{
if ($this->scheme !== null)
{
return $this->scheme;
}
else
{
return null;
}
}
/**
* Get the value of the rating
*
* @return string|null
*/
public function get_value()
{
if ($this->value !== null)
{
return $this->value;
}
else
{
return null;
}
}
}

View File

@ -0,0 +1,225 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Handles creating objects and calling methods
*
* Access this via {@see SimplePie::get_registry()}
*
* @package SimplePie
*/
class SimplePie_Registry
{
/**
* Default class mapping
*
* Overriding classes *must* subclass these.
*
* @var array
*/
protected $default = array(
'Cache' => 'SimplePie_Cache',
'Locator' => 'SimplePie_Locator',
'Parser' => 'SimplePie_Parser',
'File' => 'SimplePie_File',
'Sanitize' => 'SimplePie_Sanitize',
'Item' => 'SimplePie_Item',
'Author' => 'SimplePie_Author',
'Category' => 'SimplePie_Category',
'Enclosure' => 'SimplePie_Enclosure',
'Caption' => 'SimplePie_Caption',
'Copyright' => 'SimplePie_Copyright',
'Credit' => 'SimplePie_Credit',
'Rating' => 'SimplePie_Rating',
'Restriction' => 'SimplePie_Restriction',
'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
'Source' => 'SimplePie_Source',
'Misc' => 'SimplePie_Misc',
'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
'Parse_Date' => 'SimplePie_Parse_Date',
);
/**
* Class mapping
*
* @see register()
* @var array
*/
protected $classes = array();
/**
* Legacy classes
*
* @see register()
* @var array
*/
protected $legacy = array();
/**
* Constructor
*
* No-op
*/
public function __construct() { }
/**
* Register a class
*
* @param string $type See {@see $default} for names
* @param string $class Class name, must subclass the corresponding default
* @param bool $legacy Whether to enable legacy support for this class
* @return bool Successfulness
*/
public function register($type, $class, $legacy = false)
{
if (!is_subclass_of($class, $this->default[$type]))
{
return false;
}
$this->classes[$type] = $class;
if ($legacy)
{
$this->legacy[] = $class;
}
return true;
}
/**
* Get the class registered for a type
*
* Where possible, use {@see create()} or {@see call()} instead
*
* @param string $type
* @return string|null
*/
public function get_class($type)
{
if (!empty($this->classes[$type]))
{
return $this->classes[$type];
}
if (!empty($this->default[$type]))
{
return $this->default[$type];
}
return null;
}
/**
* Create a new instance of a given type
*
* @param string $type
* @param array $parameters Parameters to pass to the constructor
* @return object Instance of class
*/
public function &create($type, $parameters = array())
{
$class = $this->get_class($type);
if (in_array($class, $this->legacy))
{
switch ($type)
{
case 'locator':
// Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
// Specified: file, timeout, useragent, max_checked_feeds
$replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
array_splice($parameters, 3, 1, $replacement);
break;
}
}
if (!method_exists($class, '__construct'))
{
$instance = new $class;
}
else
{
$reflector = new ReflectionClass($class);
$instance = $reflector->newInstanceArgs($parameters);
}
if (method_exists($instance, 'set_registry'))
{
$instance->set_registry($this);
}
return $instance;
}
/**
* Call a static method for a type
*
* @param string $type
* @param string $method
* @param array $parameters
* @return mixed
*/
public function &call($type, $method, $parameters = array())
{
$class = $this->get_class($type);
if (in_array($class, $this->legacy))
{
switch ($type)
{
case 'Cache':
// For backwards compatibility with old non-static
// Cache::create() methods
if ($method === 'get_handler')
{
$result = @call_user_func_array(array($class, 'create'), $parameters);
return $result;
}
break;
}
}
$result = call_user_func_array(array($class, $method), $parameters);
return $result;
}
}

View File

@ -0,0 +1,155 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Handles `<media:restriction>` as defined in Media RSS
*
* Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
*
* This class can be overloaded with {@see SimplePie::set_restriction_class()}
*
* @package SimplePie
* @subpackage API
*/
class SimplePie_Restriction
{
/**
* Relationship ('allow'/'deny')
*
* @var string
* @see get_relationship()
*/
var $relationship;
/**
* Type of restriction
*
* @var string
* @see get_type()
*/
var $type;
/**
* Restricted values
*
* @var string
* @see get_value()
*/
var $value;
/**
* Constructor, used to input the data
*
* For documentation on all the parameters, see the corresponding
* properties and their accessors
*/
public function __construct($relationship = null, $type = null, $value = null)
{
$this->relationship = $relationship;
$this->type = $type;
$this->value = $value;
}
/**
* String-ified version
*
* @return string
*/
public function __toString()
{
// There is no $this->data here
return md5(serialize($this));
}
/**
* Get the relationship
*
* @return string|null Either 'allow' or 'deny'
*/
public function get_relationship()
{
if ($this->relationship !== null)
{
return $this->relationship;
}
else
{
return null;
}
}
/**
* Get the type
*
* @return string|null
*/
public function get_type()
{
if ($this->type !== null)
{
return $this->type;
}
else
{
return null;
}
}
/**
* Get the list of restricted things
*
* @return string|null
*/
public function get_value()
{
if ($this->value !== null)
{
return $this->value;
}
else
{
return null;
}
}
}

View File

@ -0,0 +1,554 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Used for data cleanup and post-processing
*
*
* This class can be overloaded with {@see SimplePie::set_sanitize_class()}
*
* @package SimplePie
* @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
*/
class SimplePie_Sanitize
{
// Private vars
var $base;
// Options
var $remove_div = true;
var $image_handler = '';
var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
var $encode_instead_of_strip = false;
var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
var $strip_comments = false;
var $output_encoding = 'UTF-8';
var $enable_cache = true;
var $cache_location = './cache';
var $cache_name_function = 'md5';
var $timeout = 10;
var $useragent = '';
var $force_fsockopen = false;
var $replace_url_attributes = null;
public function __construct()
{
// Set defaults
$this->set_url_replacements(null);
}
public function remove_div($enable = true)
{
$this->remove_div = (bool) $enable;
}
public function set_image_handler($page = false)
{
if ($page)
{
$this->image_handler = (string) $page;
}
else
{
$this->image_handler = false;
}
}
public function set_registry(SimplePie_Registry $registry)
{
$this->registry = $registry;
}
public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
{
if (isset($enable_cache))
{
$this->enable_cache = (bool) $enable_cache;
}
if ($cache_location)
{
$this->cache_location = (string) $cache_location;
}
if ($cache_name_function)
{
$this->cache_name_function = (string) $cache_name_function;
}
}
public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
{
if ($timeout)
{
$this->timeout = (string) $timeout;
}
if ($useragent)
{
$this->useragent = (string) $useragent;
}
if ($force_fsockopen)
{
$this->force_fsockopen = (string) $force_fsockopen;
}
}
public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
{
if ($tags)
{
if (is_array($tags))
{
$this->strip_htmltags = $tags;
}
else
{
$this->strip_htmltags = explode(',', $tags);
}
}
else
{
$this->strip_htmltags = false;
}
}
public function encode_instead_of_strip($encode = false)
{
$this->encode_instead_of_strip = (bool) $encode;
}
public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
{
if ($attribs)
{
if (is_array($attribs))
{
$this->strip_attributes = $attribs;
}
else
{
$this->strip_attributes = explode(',', $attribs);
}
}
else
{
$this->strip_attributes = false;
}
}
public function strip_comments($strip = false)
{
$this->strip_comments = (bool) $strip;
}
public function set_output_encoding($encoding = 'UTF-8')
{
$this->output_encoding = (string) $encoding;
}
/**
* Set element/attribute key/value pairs of HTML attributes
* containing URLs that need to be resolved relative to the feed
*
* Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
* |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
* |q|@cite
*
* @since 1.0
* @param array|null $element_attribute Element/attribute key/value pairs, null for default
*/
public function set_url_replacements($element_attribute = null)
{
if ($element_attribute === null)
{
$element_attribute = array(
'a' => 'href',
'area' => 'href',
'blockquote' => 'cite',
'del' => 'cite',
'form' => 'action',
'img' => array(
'longdesc',
'src'
),
'input' => 'src',
'ins' => 'cite',
'q' => 'cite'
);
}
$this->replace_url_attributes = (array) $element_attribute;
}
public function sanitize($data, $type, $base = '')
{
$data = trim($data);
if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
{
if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
{
if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data))
{
$type |= SIMPLEPIE_CONSTRUCT_HTML;
}
else
{
$type |= SIMPLEPIE_CONSTRUCT_TEXT;
}
}
if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
{
$data = base64_decode($data);
}
if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
{
if (!class_exists('DOMDocument'))
{
$this->registry->call('Misc', 'error', array('DOMDocument not found, unable to use sanitizer', E_USER_WARNING, __FILE__, __LINE__));
return '';
}
$document = new DOMDocument();
$document->encoding = 'UTF-8';
$data = $this->preprocess($data, $type);
set_error_handler(array('SimplePie_Misc', 'silence_errors'));
$document->loadHTML($data);
restore_error_handler();
// Strip comments
if ($this->strip_comments)
{
$xpath = new DOMXPath($document);
$comments = $xpath->query('//comment()');
foreach ($comments as $comment)
{
$comment->parentNode->removeChild($comment);
}
}
// Strip out HTML tags and attributes that might cause various security problems.
// Based on recommendations by Mark Pilgrim at:
// http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
if ($this->strip_htmltags)
{
foreach ($this->strip_htmltags as $tag)
{
$this->strip_tag($tag, $document, $type);
}
}
if ($this->strip_attributes)
{
foreach ($this->strip_attributes as $attrib)
{
$this->strip_attr($attrib, $document);
}
}
// Replace relative URLs
$this->base = $base;
foreach ($this->replace_url_attributes as $element => $attributes)
{
$this->replace_urls($document, $element, $attributes);
}
// If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
{
$images = $document->getElementsByTagName('img');
foreach ($images as $img)
{
if ($img->hasAttribute('src'))
{
$image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
$cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi'));
if ($cache->load())
{
$img->setAttribute('src', $this->image_handler . $image_url);
}
else
{
$file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
$headers = $file->headers;
if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
{
if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
{
$img->setAttribute('src', $this->image_handler . $image_url);
}
else
{
trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
}
}
}
}
}
}
// Remove the DOCTYPE
// Seems to cause segfaulting if we don't do this
if ($document->firstChild instanceof DOMDocumentType)
{
$document->removeChild($document->firstChild);
}
// Move everything from the body to the root
$real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
$document->replaceChild($real_body, $document->firstChild);
// Finally, convert to a HTML string
$data = trim($document->saveHTML());
if ($this->remove_div)
{
$data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
$data = preg_replace('/<\/div>$/', '', $data);
}
else
{
$data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
}
}
if ($type & SIMPLEPIE_CONSTRUCT_IRI)
{
$absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
if ($absolute !== false)
{
$data = $absolute;
}
}
if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
{
$data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
}
if ($this->output_encoding !== 'UTF-8')
{
$data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
}
}
return $data;
}
protected function preprocess($html, $type)
{
$ret = '';
if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
{
// Atom XHTML constructs are wrapped with a div by default
// Note: No protection if $html contains a stray </div>!
$html = '<div>' . $html . '</div>';
$ret .= '<!DOCTYPE html>';
$content_type = 'text/html';
}
else
{
$ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
$content_type = 'application/xhtml+xml';
}
$ret .= '<html><head>';
$ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
$ret .= '</head><body>' . $html . '</body></html>';
return $ret;
}
public function replace_urls($document, $tag, $attributes)
{
if (!is_array($attributes))
{
$attributes = array($attributes);
}
if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
{
$elements = $document->getElementsByTagName($tag);
foreach ($elements as $element)
{
foreach ($attributes as $attribute)
{
if ($element->hasAttribute($attribute))
{
$value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
if ($value !== false)
{
$element->setAttribute($attribute, $value);
}
}
}
}
}
}
public function do_strip_htmltags($match)
{
if ($this->encode_instead_of_strip)
{
if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
{
$match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
$match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
}
else
{
return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
}
}
elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
{
return $match[4];
}
else
{
return '';
}
}
protected function strip_tag($tag, $document, $type)
{
$xpath = new DOMXPath($document);
$elements = $xpath->query('body//' . $tag);
if ($this->encode_instead_of_strip)
{
foreach ($elements as $element)
{
$fragment = $document->createDocumentFragment();
// For elements which aren't script or style, include the tag itself
if (!in_array($tag, array('script', 'style')))
{
$text = '<' . $tag;
if ($element->hasAttributes())
{
$attrs = array();
foreach ($element->attributes as $name => $attr)
{
$value = $attr->value;
// In XHTML, empty values should never exist, so we repeat the value
if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
{
$value = $name;
}
// For HTML, empty is fine
elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
{
$attrs[] = $name;
continue;
}
// Standard attribute text
$attrs[] = $name . '="' . $attr->value . '"';
}
$text .= ' ' . implode(' ', $attrs);
}
$text .= '>';
$fragment->appendChild(new DOMText($text));
}
$number = $element->childNodes->length;
for ($i = $number; $i > 0; $i--)
{
$child = $element->childNodes->item(0);
$fragment->appendChild($child);
}
if (!in_array($tag, array('script', 'style')))
{
$fragment->appendChild(new DOMText('</' . $tag . '>'));
}
$element->parentNode->replaceChild($fragment, $element);
}
return;
}
elseif (in_array($tag, array('script', 'style')))
{
foreach ($elements as $element)
{
$element->parentNode->removeChild($element);
}
return;
}
else
{
foreach ($elements as $element)
{
$fragment = $document->createDocumentFragment();
$number = $element->childNodes->length;
for ($i = $number; $i > 0; $i--)
{
$child = $element->childNodes->item(0);
$fragment->appendChild($child);
}
$element->parentNode->replaceChild($fragment, $element);
}
}
}
protected function strip_attr($attrib, $document)
{
$xpath = new DOMXPath($document);
$elements = $xpath->query('//*[@' . $attrib . ']');
foreach ($elements as $element)
{
$element->removeAttribute($attrib);
}
}
}

View File

@ -0,0 +1,611 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Handles `<atom:source>`
*
* Used by {@see SimplePie_Item::get_source()}
*
* This class can be overloaded with {@see SimplePie::set_source_class()}
*
* @package SimplePie
* @subpackage API
*/
class SimplePie_Source
{
var $item;
var $data = array();
protected $registry;
public function __construct($item, $data)
{
$this->item = $item;
$this->data = $data;
}
public function set_registry(SimplePie_Registry $registry)
{
$this->registry = $registry;
}
public function __toString()
{
return md5(serialize($this->data));
}
public function get_source_tags($namespace, $tag)
{
if (isset($this->data['child'][$namespace][$tag]))
{
return $this->data['child'][$namespace][$tag];
}
else
{
return null;
}
}
public function get_base($element = array())
{
return $this->item->get_base($element);
}
public function sanitize($data, $type, $base = '')
{
return $this->item->sanitize($data, $type, $base);
}
public function get_item()
{
return $this->item;
}
public function get_title()
{
if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
{
return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
{
return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
else
{
return null;
}
}
public function get_category($key = 0)
{
$categories = $this->get_categories();
if (isset($categories[$key]))
{
return $categories[$key];
}
else
{
return null;
}
}
public function get_categories()
{
$categories = array();
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
{
$term = null;
$scheme = null;
$label = null;
if (isset($category['attribs']['']['term']))
{
$term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if (isset($category['attribs']['']['scheme']))
{
$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if (isset($category['attribs']['']['label']))
{
$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
}
$categories[] = $this->registry->create('Category', array($term, $scheme, $label));
}
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
{
// This is really the label, but keep this as the term also for BC.
// Label will also work on retrieving because that falls back to term.
$term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
if (isset($category['attribs']['']['domain']))
{
$scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
}
else
{
$scheme = null;
}
$categories[] = $this->registry->create('Category', array($term, $scheme, null));
}
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
{
$categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
{
$categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
if (!empty($categories))
{
return array_unique($categories);
}
else
{
return null;
}
}
public function get_author($key = 0)
{
$authors = $this->get_authors();
if (isset($authors[$key]))
{
return $authors[$key];
}
else
{
return null;
}
}
public function get_authors()
{
$authors = array();
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
{
$name = null;
$uri = null;
$email = null;
if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
{
$name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
{
$uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
}
if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
{
$email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if ($name !== null || $email !== null || $uri !== null)
{
$authors[] = $this->registry->create('Author', array($name, $uri, $email));
}
}
if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
{
$name = null;
$url = null;
$email = null;
if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
{
$name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
{
$url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
}
if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
{
$email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if ($name !== null || $email !== null || $url !== null)
{
$authors[] = $this->registry->create('Author', array($name, $url, $email));
}
}
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
{
$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
{
$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
{
$authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
if (!empty($authors))
{
return array_unique($authors);
}
else
{
return null;
}
}
public function get_contributor($key = 0)
{
$contributors = $this->get_contributors();
if (isset($contributors[$key]))
{
return $contributors[$key];
}
else
{
return null;
}
}
public function get_contributors()
{
$contributors = array();
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
{
$name = null;
$uri = null;
$email = null;
if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
{
$name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
{
$uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
}
if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
{
$email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if ($name !== null || $email !== null || $uri !== null)
{
$contributors[] = $this->registry->create('Author', array($name, $uri, $email));
}
}
foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
{
$name = null;
$url = null;
$email = null;
if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
{
$name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
{
$url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
}
if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
{
$email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
if ($name !== null || $email !== null || $url !== null)
{
$contributors[] = $this->registry->create('Author', array($name, $url, $email));
}
}
if (!empty($contributors))
{
return array_unique($contributors);
}
else
{
return null;
}
}
public function get_link($key = 0, $rel = 'alternate')
{
$links = $this->get_links($rel);
if (isset($links[$key]))
{
return $links[$key];
}
else
{
return null;
}
}
/**
* Added for parity between the parent-level and the item/entry-level.
*/
public function get_permalink()
{
return $this->get_link(0);
}
public function get_links($rel = 'alternate')
{
if (!isset($this->data['links']))
{
$this->data['links'] = array();
if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
{
foreach ($links as $link)
{
if (isset($link['attribs']['']['href']))
{
$link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
$this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
}
}
}
if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
{
foreach ($links as $link)
{
if (isset($link['attribs']['']['href']))
{
$link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
$this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
}
}
}
if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
{
$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
}
if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
{
$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
}
if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
{
$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
}
$keys = array_keys($this->data['links']);
foreach ($keys as $key)
{
if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
{
if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
{
$this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
$this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
}
else
{
$this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
}
}
elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
{
$this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
}
$this->data['links'][$key] = array_unique($this->data['links'][$key]);
}
}
if (isset($this->data['links'][$rel]))
{
return $this->data['links'][$rel];
}
else
{
return null;
}
}
public function get_description()
{
if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
{
return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
{
return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
}
else
{
return null;
}
}
public function get_copyright()
{
if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
{
return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
{
return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
else
{
return null;
}
}
public function get_language()
{
if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
elseif (isset($this->data['xml_lang']))
{
return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
}
else
{
return null;
}
}
public function get_latitude()
{
if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
{
return (float) $return[0]['data'];
}
elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
{
return (float) $match[1];
}
else
{
return null;
}
}
public function get_longitude()
{
if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
{
return (float) $return[0]['data'];
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
{
return (float) $return[0]['data'];
}
elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
{
return (float) $match[2];
}
else
{
return null;
}
}
public function get_image_url()
{
if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
{
return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
}
elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
}
else
{
return null;
}
}
}

View File

@ -0,0 +1,362 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Parses the XML Declaration
*
* @package SimplePie
* @subpackage Parsing
*/
class SimplePie_XML_Declaration_Parser
{
/**
* XML Version
*
* @access public
* @var string
*/
var $version = '1.0';
/**
* Encoding
*
* @access public
* @var string
*/
var $encoding = 'UTF-8';
/**
* Standalone
*
* @access public
* @var bool
*/
var $standalone = false;
/**
* Current state of the state machine
*
* @access private
* @var string
*/
var $state = 'before_version_name';
/**
* Input data
*
* @access private
* @var string
*/
var $data = '';
/**
* Input data length (to avoid calling strlen() everytime this is needed)
*
* @access private
* @var int
*/
var $data_length = 0;
/**
* Current position of the pointer
*
* @var int
* @access private
*/
var $position = 0;
/**
* Create an instance of the class with the input data
*
* @access public
* @param string $data Input data
*/
public function __construct($data)
{
$this->data = $data;
$this->data_length = strlen($this->data);
}
/**
* Parse the input data
*
* @access public
* @return bool true on success, false on failure
*/
public function parse()
{
while ($this->state && $this->state !== 'emit' && $this->has_data())
{
$state = $this->state;
$this->$state();
}
$this->data = '';
if ($this->state === 'emit')
{
return true;
}
else
{
$this->version = '';
$this->encoding = '';
$this->standalone = '';
return false;
}
}
/**
* Check whether there is data beyond the pointer
*
* @access private
* @return bool true if there is further data, false if not
*/
public function has_data()
{
return (bool) ($this->position < $this->data_length);
}
/**
* Advance past any whitespace
*
* @return int Number of whitespace characters passed
*/
public function skip_whitespace()
{
$whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
$this->position += $whitespace;
return $whitespace;
}
/**
* Read value
*/
public function get_value()
{
$quote = substr($this->data, $this->position, 1);
if ($quote === '"' || $quote === "'")
{
$this->position++;
$len = strcspn($this->data, $quote, $this->position);
if ($this->has_data())
{
$value = substr($this->data, $this->position, $len);
$this->position += $len + 1;
return $value;
}
}
return false;
}
public function before_version_name()
{
if ($this->skip_whitespace())
{
$this->state = 'version_name';
}
else
{
$this->state = false;
}
}
public function version_name()
{
if (substr($this->data, $this->position, 7) === 'version')
{
$this->position += 7;
$this->skip_whitespace();
$this->state = 'version_equals';
}
else
{
$this->state = false;
}
}
public function version_equals()
{
if (substr($this->data, $this->position, 1) === '=')
{
$this->position++;
$this->skip_whitespace();
$this->state = 'version_value';
}
else
{
$this->state = false;
}
}
public function version_value()
{
if ($this->version = $this->get_value())
{
$this->skip_whitespace();
if ($this->has_data())
{
$this->state = 'encoding_name';
}
else
{
$this->state = 'emit';
}
}
else
{
$this->state = false;
}
}
public function encoding_name()
{
if (substr($this->data, $this->position, 8) === 'encoding')
{
$this->position += 8;
$this->skip_whitespace();
$this->state = 'encoding_equals';
}
else
{
$this->state = 'standalone_name';
}
}
public function encoding_equals()
{
if (substr($this->data, $this->position, 1) === '=')
{
$this->position++;
$this->skip_whitespace();
$this->state = 'encoding_value';
}
else
{
$this->state = false;
}
}
public function encoding_value()
{
if ($this->encoding = $this->get_value())
{
$this->skip_whitespace();
if ($this->has_data())
{
$this->state = 'standalone_name';
}
else
{
$this->state = 'emit';
}
}
else
{
$this->state = false;
}
}
public function standalone_name()
{
if (substr($this->data, $this->position, 10) === 'standalone')
{
$this->position += 10;
$this->skip_whitespace();
$this->state = 'standalone_equals';
}
else
{
$this->state = false;
}
}
public function standalone_equals()
{
if (substr($this->data, $this->position, 1) === '=')
{
$this->position++;
$this->skip_whitespace();
$this->state = 'standalone_value';
}
else
{
$this->state = false;
}
}
public function standalone_value()
{
if ($standalone = $this->get_value())
{
switch ($standalone)
{
case 'yes':
$this->standalone = true;
break;
case 'no':
$this->standalone = false;
break;
default:
$this->state = false;
return;
}
$this->skip_whitespace();
if ($this->has_data())
{
$this->state = false;
}
else
{
$this->state = 'emit';
}
}
else
{
$this->state = false;
}
}
}

View File

@ -0,0 +1,371 @@
<?php
/**
* SimplePie
*
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
* Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
* @version 1.3.1
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
/**
* Decode 'gzip' encoded HTTP data
*
* @package SimplePie
* @subpackage HTTP
* @link http://www.gzip.org/format.txt
*/
class SimplePie_gzdecode
{
/**
* Compressed data
*
* @access private
* @var string
* @see gzdecode::$data
*/
var $compressed_data;
/**
* Size of compressed data
*
* @access private
* @var int
*/
var $compressed_size;
/**
* Minimum size of a valid gzip string
*
* @access private
* @var int
*/
var $min_compressed_size = 18;
/**
* Current position of pointer
*
* @access private
* @var int
*/
var $position = 0;
/**
* Flags (FLG)
*
* @access private
* @var int
*/
var $flags;
/**
* Uncompressed data
*
* @access public
* @see gzdecode::$compressed_data
* @var string
*/
var $data;
/**
* Modified time
*
* @access public
* @var int
*/
var $MTIME;
/**
* Extra Flags
*
* @access public
* @var int
*/
var $XFL;
/**
* Operating System
*
* @access public
* @var int
*/
var $OS;
/**
* Subfield ID 1
*
* @access public
* @see gzdecode::$extra_field
* @see gzdecode::$SI2
* @var string
*/
var $SI1;
/**
* Subfield ID 2
*
* @access public
* @see gzdecode::$extra_field
* @see gzdecode::$SI1
* @var string
*/
var $SI2;
/**
* Extra field content
*
* @access public
* @see gzdecode::$SI1
* @see gzdecode::$SI2
* @var string
*/
var $extra_field;
/**
* Original filename
*
* @access public
* @var string
*/
var $filename;
/**
* Human readable comment
*
* @access public
* @var string
*/
var $comment;
/**
* Don't allow anything to be set
*
* @param string $name
* @param mixed $value
*/
public function __set($name, $value)
{
trigger_error("Cannot write property $name", E_USER_ERROR);
}
/**
* Set the compressed string and related properties
*
* @param string $data
*/
public function __construct($data)
{
$this->compressed_data = $data;
$this->compressed_size = strlen($data);
}
/**
* Decode the GZIP stream
*
* @return bool Successfulness
*/
public function parse()
{
if ($this->compressed_size >= $this->min_compressed_size)
{
// Check ID1, ID2, and CM
if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
{
return false;
}
// Get the FLG (FLaGs)
$this->flags = ord($this->compressed_data[3]);
// FLG bits above (1 << 4) are reserved
if ($this->flags > 0x1F)
{
return false;
}
// Advance the pointer after the above
$this->position += 4;
// MTIME
$mtime = substr($this->compressed_data, $this->position, 4);
// Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
if (current(unpack('S', "\x00\x01")) === 1)
{
$mtime = strrev($mtime);
}
$this->MTIME = current(unpack('l', $mtime));
$this->position += 4;
// Get the XFL (eXtra FLags)
$this->XFL = ord($this->compressed_data[$this->position++]);
// Get the OS (Operating System)
$this->OS = ord($this->compressed_data[$this->position++]);
// Parse the FEXTRA
if ($this->flags & 4)
{
// Read subfield IDs
$this->SI1 = $this->compressed_data[$this->position++];
$this->SI2 = $this->compressed_data[$this->position++];
// SI2 set to zero is reserved for future use
if ($this->SI2 === "\x00")
{
return false;
}
// Get the length of the extra field
$len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
$this->position += 2;
// Check the length of the string is still valid
$this->min_compressed_size += $len + 4;
if ($this->compressed_size >= $this->min_compressed_size)
{
// Set the extra field to the given data
$this->extra_field = substr($this->compressed_data, $this->position, $len);
$this->position += $len;
}
else
{
return false;
}
}
// Parse the FNAME
if ($this->flags & 8)
{
// Get the length of the filename
$len = strcspn($this->compressed_data, "\x00", $this->position);
// Check the length of the string is still valid
$this->min_compressed_size += $len + 1;
if ($this->compressed_size >= $this->min_compressed_size)
{
// Set the original filename to the given string
$this->filename = substr($this->compressed_data, $this->position, $len);
$this->position += $len + 1;
}
else
{
return false;
}
}
// Parse the FCOMMENT
if ($this->flags & 16)
{
// Get the length of the comment
$len = strcspn($this->compressed_data, "\x00", $this->position);
// Check the length of the string is still valid
$this->min_compressed_size += $len + 1;
if ($this->compressed_size >= $this->min_compressed_size)
{
// Set the original comment to the given string
$this->comment = substr($this->compressed_data, $this->position, $len);
$this->position += $len + 1;
}
else
{
return false;
}
}
// Parse the FHCRC
if ($this->flags & 2)
{
// Check the length of the string is still valid
$this->min_compressed_size += $len + 2;
if ($this->compressed_size >= $this->min_compressed_size)
{
// Read the CRC
$crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
// Check the CRC matches
if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
{
$this->position += 2;
}
else
{
return false;
}
}
else
{
return false;
}
}
// Decompress the actual data
if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
{
return false;
}
else
{
$this->position = $this->compressed_size - 8;
}
// Check CRC of data
$crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
$this->position += 4;
/*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
{
return false;
}*/
// Check ISIZE of data
$isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
$this->position += 4;
if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
{
return false;
}
// Wow, against all odds, we've actually got a valid gzip string
return true;
}
else
{
return false;
}
}
}

450
wp-includes/Text/Diff.php Normal file
View File

@ -0,0 +1,450 @@
<?php
/**
* General API for generating and formatting diffs - the differences between
* two sequences of strings.
*
* The original PHP version of this code was written by Geoffrey T. Dairiki
* <dairiki@dairiki.org>, and is used/adapted with his permission.
*
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
* Copyright 2004-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
*
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*/
class Text_Diff {
/**
* Array of changes.
*
* @var array
*/
var $_edits;
/**
* Computes diffs between sequences of strings.
*
* @param string $engine Name of the diffing engine to use. 'auto'
* will automatically select the best.
* @param array $params Parameters to pass to the diffing engine.
* Normally an array of two arrays, each
* containing the lines from a file.
*/
function Text_Diff($engine, $params)
{
// Backward compatibility workaround.
if (!is_string($engine)) {
$params = array($engine, $params);
$engine = 'auto';
}
if ($engine == 'auto') {
$engine = extension_loaded('xdiff') ? 'xdiff' : 'native';
} else {
$engine = basename($engine);
}
// WP #7391
require_once dirname(__FILE__).'/Diff/Engine/' . $engine . '.php';
$class = 'Text_Diff_Engine_' . $engine;
$diff_engine = new $class();
$this->_edits = call_user_func_array(array($diff_engine, 'diff'), $params);
}
/**
* Returns the array of differences.
*/
function getDiff()
{
return $this->_edits;
}
/**
* returns the number of new (added) lines in a given diff.
*
* @since Text_Diff 1.1.0
*
* @return integer The number of new lines
*/
function countAddedLines()
{
$count = 0;
foreach ($this->_edits as $edit) {
if (is_a($edit, 'Text_Diff_Op_add') ||
is_a($edit, 'Text_Diff_Op_change')) {
$count += $edit->nfinal();
}
}
return $count;
}
/**
* Returns the number of deleted (removed) lines in a given diff.
*
* @since Text_Diff 1.1.0
*
* @return integer The number of deleted lines
*/
function countDeletedLines()
{
$count = 0;
foreach ($this->_edits as $edit) {
if (is_a($edit, 'Text_Diff_Op_delete') ||
is_a($edit, 'Text_Diff_Op_change')) {
$count += $edit->norig();
}
}
return $count;
}
/**
* Computes a reversed diff.
*
* Example:
* <code>
* $diff = new Text_Diff($lines1, $lines2);
* $rev = $diff->reverse();
* </code>
*
* @return Text_Diff A Diff object representing the inverse of the
* original diff. Note that we purposely don't return a
* reference here, since this essentially is a clone()
* method.
*/
function reverse()
{
if (version_compare(zend_version(), '2', '>')) {
$rev = clone($this);
} else {
$rev = $this;
}
$rev->_edits = array();
foreach ($this->_edits as $edit) {
$rev->_edits[] = $edit->reverse();
}
return $rev;
}
/**
* Checks for an empty diff.
*
* @return boolean True if two sequences were identical.
*/
function isEmpty()
{
foreach ($this->_edits as $edit) {
if (!is_a($edit, 'Text_Diff_Op_copy')) {
return false;
}
}
return true;
}
/**
* Computes the length of the Longest Common Subsequence (LCS).
*
* This is mostly for diagnostic purposes.
*
* @return integer The length of the LCS.
*/
function lcs()
{
$lcs = 0;
foreach ($this->_edits as $edit) {
if (is_a($edit, 'Text_Diff_Op_copy')) {
$lcs += count($edit->orig);
}
}
return $lcs;
}
/**
* Gets the original set of lines.
*
* This reconstructs the $from_lines parameter passed to the constructor.
*
* @return array The original sequence of strings.
*/
function getOriginal()
{
$lines = array();
foreach ($this->_edits as $edit) {
if ($edit->orig) {
array_splice($lines, count($lines), 0, $edit->orig);
}
}
return $lines;
}
/**
* Gets the final set of lines.
*
* This reconstructs the $to_lines parameter passed to the constructor.
*
* @return array The sequence of strings.
*/
function getFinal()
{
$lines = array();
foreach ($this->_edits as $edit) {
if ($edit->final) {
array_splice($lines, count($lines), 0, $edit->final);
}
}
return $lines;
}
/**
* Removes trailing newlines from a line of text. This is meant to be used
* with array_walk().
*
* @param string $line The line to trim.
* @param integer $key The index of the line in the array. Not used.
*/
function trimNewlines(&$line, $key)
{
$line = str_replace(array("\n", "\r"), '', $line);
}
/**
* Determines the location of the system temporary directory.
*
* @static
*
* @access protected
*
* @return string A directory name which can be used for temp files.
* Returns false if one could not be found.
*/
function _getTempDir()
{
$tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
'c:\windows\temp', 'c:\winnt\temp');
/* Try PHP's upload_tmp_dir directive. */
$tmp = ini_get('upload_tmp_dir');
/* Otherwise, try to determine the TMPDIR environment variable. */
if (!strlen($tmp)) {
$tmp = getenv('TMPDIR');
}
/* If we still cannot determine a value, then cycle through a list of
* preset possibilities. */
while (!strlen($tmp) && count($tmp_locations)) {
$tmp_check = array_shift($tmp_locations);
if (@is_dir($tmp_check)) {
$tmp = $tmp_check;
}
}
/* If it is still empty, we have failed, so return false; otherwise
* return the directory determined. */
return strlen($tmp) ? $tmp : false;
}
/**
* Checks a diff for validity.
*
* This is here only for debugging purposes.
*/
function _check($from_lines, $to_lines)
{
if (serialize($from_lines) != serialize($this->getOriginal())) {
trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
}
if (serialize($to_lines) != serialize($this->getFinal())) {
trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
}
$rev = $this->reverse();
if (serialize($to_lines) != serialize($rev->getOriginal())) {
trigger_error("Reversed original doesn't match", E_USER_ERROR);
}
if (serialize($from_lines) != serialize($rev->getFinal())) {
trigger_error("Reversed final doesn't match", E_USER_ERROR);
}
$prevtype = null;
foreach ($this->_edits as $edit) {
if ($prevtype == get_class($edit)) {
trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
}
$prevtype = get_class($edit);
}
return true;
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*/
class Text_MappedDiff extends Text_Diff {
/**
* Computes a diff between sequences of strings.
*
* This can be used to compute things like case-insensitve diffs, or diffs
* which ignore changes in white-space.
*
* @param array $from_lines An array of strings.
* @param array $to_lines An array of strings.
* @param array $mapped_from_lines This array should have the same size
* number of elements as $from_lines. The
* elements in $mapped_from_lines and
* $mapped_to_lines are what is actually
* compared when computing the diff.
* @param array $mapped_to_lines This array should have the same number
* of elements as $to_lines.
*/
function Text_MappedDiff($from_lines, $to_lines,
$mapped_from_lines, $mapped_to_lines)
{
assert(count($from_lines) == count($mapped_from_lines));
assert(count($to_lines) == count($mapped_to_lines));
parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
$xi = $yi = 0;
for ($i = 0; $i < count($this->_edits); $i++) {
$orig = &$this->_edits[$i]->orig;
if (is_array($orig)) {
$orig = array_slice($from_lines, $xi, count($orig));
$xi += count($orig);
}
$final = &$this->_edits[$i]->final;
if (is_array($final)) {
$final = array_slice($to_lines, $yi, count($final));
$yi += count($final);
}
}
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op {
var $orig;
var $final;
function &reverse()
{
trigger_error('Abstract method', E_USER_ERROR);
}
function norig()
{
return $this->orig ? count($this->orig) : 0;
}
function nfinal()
{
return $this->final ? count($this->final) : 0;
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op_copy extends Text_Diff_Op {
function Text_Diff_Op_copy($orig, $final = false)
{
if (!is_array($final)) {
$final = $orig;
}
$this->orig = $orig;
$this->final = $final;
}
function &reverse()
{
$reverse = &new Text_Diff_Op_copy($this->final, $this->orig);
return $reverse;
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op_delete extends Text_Diff_Op {
function Text_Diff_Op_delete($lines)
{
$this->orig = $lines;
$this->final = false;
}
function &reverse()
{
$reverse = &new Text_Diff_Op_add($this->orig);
return $reverse;
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op_add extends Text_Diff_Op {
function Text_Diff_Op_add($lines)
{
$this->final = $lines;
$this->orig = false;
}
function &reverse()
{
$reverse = &new Text_Diff_Op_delete($this->final);
return $reverse;
}
}
/**
* @package Text_Diff
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
*
* @access private
*/
class Text_Diff_Op_change extends Text_Diff_Op {
function Text_Diff_Op_change($orig, $final)
{
$this->orig = $orig;
$this->final = $final;
}
function &reverse()
{
$reverse = &new Text_Diff_Op_change($this->final, $this->orig);
return $reverse;
}
}

View File

@ -0,0 +1,436 @@
<?php
/**
* Class used internally by Text_Diff to actually compute the diffs.
*
* This class is implemented using native PHP code.
*
* The algorithm used here is mostly lifted from the perl module
* Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
* http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
*
* More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html
*
* Some ideas (and a bit of code) are taken from analyze.c, of GNU
* diffutils-2.7, which can be found at:
* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
*
* Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
* Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this
* code was written by him, and is used/adapted with his permission.
*
* Copyright 2004-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
*
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
* @package Text_Diff
*/
class Text_Diff_Engine_native {
function diff($from_lines, $to_lines)
{
array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
$n_from = count($from_lines);
$n_to = count($to_lines);
$this->xchanged = $this->ychanged = array();
$this->xv = $this->yv = array();
$this->xind = $this->yind = array();
unset($this->seq);
unset($this->in_seq);
unset($this->lcs);
// Skip leading common lines.
for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
if ($from_lines[$skip] !== $to_lines[$skip]) {
break;
}
$this->xchanged[$skip] = $this->ychanged[$skip] = false;
}
// Skip trailing common lines.
$xi = $n_from; $yi = $n_to;
for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
if ($from_lines[$xi] !== $to_lines[$yi]) {
break;
}
$this->xchanged[$xi] = $this->ychanged[$yi] = false;
}
// Ignore lines which do not exist in both files.
for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
$xhash[$from_lines[$xi]] = 1;
}
for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
$line = $to_lines[$yi];
if (($this->ychanged[$yi] = empty($xhash[$line]))) {
continue;
}
$yhash[$line] = 1;
$this->yv[] = $line;
$this->yind[] = $yi;
}
for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
$line = $from_lines[$xi];
if (($this->xchanged[$xi] = empty($yhash[$line]))) {
continue;
}
$this->xv[] = $line;
$this->xind[] = $xi;
}
// Find the LCS.
$this->_compareseq(0, count($this->xv), 0, count($this->yv));
// Merge edits when possible.
$this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged);
$this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged);
// Compute the edit operations.
$edits = array();
$xi = $yi = 0;
while ($xi < $n_from || $yi < $n_to) {
assert($yi < $n_to || $this->xchanged[$xi]);
assert($xi < $n_from || $this->ychanged[$yi]);
// Skip matching "snake".
$copy = array();
while ($xi < $n_from && $yi < $n_to
&& !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
$copy[] = $from_lines[$xi++];
++$yi;
}
if ($copy) {
$edits[] = &new Text_Diff_Op_copy($copy);
}
// Find deletes & adds.
$delete = array();
while ($xi < $n_from && $this->xchanged[$xi]) {
$delete[] = $from_lines[$xi++];
}
$add = array();
while ($yi < $n_to && $this->ychanged[$yi]) {
$add[] = $to_lines[$yi++];
}
if ($delete && $add) {
$edits[] = &new Text_Diff_Op_change($delete, $add);
} elseif ($delete) {
$edits[] = &new Text_Diff_Op_delete($delete);
} elseif ($add) {
$edits[] = &new Text_Diff_Op_add($add);
}
}
return $edits;
}
/**
* Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
* XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized
* segments.
*
* Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of
* NCHUNKS+1 (X, Y) indexes giving the diving points between sub
* sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1),
* the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) ==
* (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
*
* This function assumes that the first lines of the specified portions of
* the two files do not match, and likewise that the last lines do not
* match. The caller must trim matching lines from the beginning and end
* of the portions it is going to specify.
*/
function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks)
{
$flip = false;
if ($xlim - $xoff > $ylim - $yoff) {
/* Things seems faster (I'm not sure I understand why) when the
* shortest sequence is in X. */
$flip = true;
list ($xoff, $xlim, $yoff, $ylim)
= array($yoff, $ylim, $xoff, $xlim);
}
if ($flip) {
for ($i = $ylim - 1; $i >= $yoff; $i--) {
$ymatches[$this->xv[$i]][] = $i;
}
} else {
for ($i = $ylim - 1; $i >= $yoff; $i--) {
$ymatches[$this->yv[$i]][] = $i;
}
}
$this->lcs = 0;
$this->seq[0]= $yoff - 1;
$this->in_seq = array();
$ymids[0] = array();
$numer = $xlim - $xoff + $nchunks - 1;
$x = $xoff;
for ($chunk = 0; $chunk < $nchunks; $chunk++) {
if ($chunk > 0) {
for ($i = 0; $i <= $this->lcs; $i++) {
$ymids[$i][$chunk - 1] = $this->seq[$i];
}
}
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks);
for (; $x < $x1; $x++) {
$line = $flip ? $this->yv[$x] : $this->xv[$x];
if (empty($ymatches[$line])) {
continue;
}
$matches = $ymatches[$line];
reset($matches);
while (list(, $y) = each($matches)) {
if (empty($this->in_seq[$y])) {
$k = $this->_lcsPos($y);
assert($k > 0);
$ymids[$k] = $ymids[$k - 1];
break;
}
}
while (list(, $y) = each($matches)) {
if ($y > $this->seq[$k - 1]) {
assert($y <= $this->seq[$k]);
/* Optimization: this is a common case: next match is
* just replacing previous match. */
$this->in_seq[$this->seq[$k]] = false;
$this->seq[$k] = $y;
$this->in_seq[$y] = 1;
} elseif (empty($this->in_seq[$y])) {
$k = $this->_lcsPos($y);
assert($k > 0);
$ymids[$k] = $ymids[$k - 1];
}
}
}
}
$seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
$ymid = $ymids[$this->lcs];
for ($n = 0; $n < $nchunks - 1; $n++) {
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
$y1 = $ymid[$n] + 1;
$seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
}
$seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
return array($this->lcs, $seps);
}
function _lcsPos($ypos)
{
$end = $this->lcs;
if ($end == 0 || $ypos > $this->seq[$end]) {
$this->seq[++$this->lcs] = $ypos;
$this->in_seq[$ypos] = 1;
return $this->lcs;
}
$beg = 1;
while ($beg < $end) {
$mid = (int)(($beg + $end) / 2);
if ($ypos > $this->seq[$mid]) {
$beg = $mid + 1;
} else {
$end = $mid;
}
}
assert($ypos != $this->seq[$end]);
$this->in_seq[$this->seq[$end]] = false;
$this->seq[$end] = $ypos;
$this->in_seq[$ypos] = 1;
return $end;
}
/**
* Finds LCS of two sequences.
*
* The results are recorded in the vectors $this->{x,y}changed[], by
* storing a 1 in the element for each line that is an insertion or
* deletion (ie. is not in the LCS).
*
* The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
*
* Note that XLIM, YLIM are exclusive bounds. All line numbers are
* origin-0 and discarded lines are not counted.
*/
function _compareseq ($xoff, $xlim, $yoff, $ylim)
{
/* Slide down the bottom initial diagonal. */
while ($xoff < $xlim && $yoff < $ylim
&& $this->xv[$xoff] == $this->yv[$yoff]) {
++$xoff;
++$yoff;
}
/* Slide up the top initial diagonal. */
while ($xlim > $xoff && $ylim > $yoff
&& $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
--$xlim;
--$ylim;
}
if ($xoff == $xlim || $yoff == $ylim) {
$lcs = 0;
} else {
/* This is ad hoc but seems to work well. $nchunks =
* sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks =
* max(2,min(8,(int)$nchunks)); */
$nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
list($lcs, $seps)
= $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
}
if ($lcs == 0) {
/* X and Y sequences have no common subsequence: mark all
* changed. */
while ($yoff < $ylim) {
$this->ychanged[$this->yind[$yoff++]] = 1;
}
while ($xoff < $xlim) {
$this->xchanged[$this->xind[$xoff++]] = 1;
}
} else {
/* Use the partitions to split this problem into subproblems. */
reset($seps);
$pt1 = $seps[0];
while ($pt2 = next($seps)) {
$this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
$pt1 = $pt2;
}
}
}
/**
* Adjusts inserts/deletes of identical lines to join changes as much as
* possible.
*
* We do something when a run of changed lines include a line at one end
* and has an excluded, identical line at the other. We are free to
* choose which identical line is included. `compareseq' usually chooses
* the one at the beginning, but usually it is cleaner to consider the
* following identical line to be the "change".
*
* This is extracted verbatim from analyze.c (GNU diffutils-2.7).
*/
function _shiftBoundaries($lines, &$changed, $other_changed)
{
$i = 0;
$j = 0;
assert('count($lines) == count($changed)');
$len = count($lines);
$other_len = count($other_changed);
while (1) {
/* Scan forward to find the beginning of another run of
* changes. Also keep track of the corresponding point in the
* other file.
*
* Throughout this code, $i and $j are adjusted together so that
* the first $i elements of $changed and the first $j elements of
* $other_changed both contain the same number of zeros (unchanged
* lines).
*
* Furthermore, $j is always kept so that $j == $other_len or
* $other_changed[$j] == false. */
while ($j < $other_len && $other_changed[$j]) {
$j++;
}
while ($i < $len && ! $changed[$i]) {
assert('$j < $other_len && ! $other_changed[$j]');
$i++; $j++;
while ($j < $other_len && $other_changed[$j]) {
$j++;
}
}
if ($i == $len) {
break;
}
$start = $i;
/* Find the end of this run of changes. */
while (++$i < $len && $changed[$i]) {
continue;
}
do {
/* Record the length of this run of changes, so that we can
* later determine whether the run has grown. */
$runlength = $i - $start;
/* Move the changed region back, so long as the previous
* unchanged line matches the last changed one. This merges
* with previous changed regions. */
while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
$changed[--$start] = 1;
$changed[--$i] = false;
while ($start > 0 && $changed[$start - 1]) {
$start--;
}
assert('$j > 0');
while ($other_changed[--$j]) {
continue;
}
assert('$j >= 0 && !$other_changed[$j]');
}
/* Set CORRESPONDING to the end of the changed run, at the
* last point where it corresponds to a changed run in the
* other file. CORRESPONDING == LEN means no such point has
* been found. */
$corresponding = $j < $other_len ? $i : $len;
/* Move the changed region forward, so long as the first
* changed line matches the following unchanged one. This
* merges with following changed regions. Do this second, so
* that if there are no merges, the changed region is moved
* forward as far as possible. */
while ($i < $len && $lines[$start] == $lines[$i]) {
$changed[$start++] = false;
$changed[$i++] = 1;
while ($i < $len && $changed[$i]) {
$i++;
}
assert('$j < $other_len && ! $other_changed[$j]');
$j++;
if ($j < $other_len && $other_changed[$j]) {
$corresponding = $i;
while ($j < $other_len && $other_changed[$j]) {
$j++;
}
}
}
} while ($runlength != $i - $start);
/* If possible, move the fully-merged run of changes back to a
* corresponding run in the other file. */
while ($corresponding < $i) {
$changed[--$start] = 1;
$changed[--$i] = 0;
assert('$j > 0');
while ($other_changed[--$j]) {
continue;
}
assert('$j >= 0 && !$other_changed[$j]');
}
}
}
}

View File

@ -0,0 +1,162 @@
<?php
/**
* Class used internally by Diff to actually compute the diffs.
*
* This class uses the Unix `diff` program via shell_exec to compute the
* differences between the two input arrays.
*
* Copyright 2007-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
*
* @author Milian Wolff <mail@milianw.de>
* @package Text_Diff
* @since 0.3.0
*/
class Text_Diff_Engine_shell {
/**
* Path to the diff executable
*
* @var string
*/
var $_diffCommand = 'diff';
/**
* Returns the array of differences.
*
* @param array $from_lines lines of text from old file
* @param array $to_lines lines of text from new file
*
* @return array all changes made (array with Text_Diff_Op_* objects)
*/
function diff($from_lines, $to_lines)
{
array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
$temp_dir = Text_Diff::_getTempDir();
// Execute gnu diff or similar to get a standard diff file.
$from_file = tempnam($temp_dir, 'Text_Diff');
$to_file = tempnam($temp_dir, 'Text_Diff');
$fp = fopen($from_file, 'w');
fwrite($fp, implode("\n", $from_lines));
fclose($fp);
$fp = fopen($to_file, 'w');
fwrite($fp, implode("\n", $to_lines));
fclose($fp);
$diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file);
unlink($from_file);
unlink($to_file);
if (is_null($diff)) {
// No changes were made
return array(new Text_Diff_Op_copy($from_lines));
}
$from_line_no = 1;
$to_line_no = 1;
$edits = array();
// Get changed lines by parsing something like:
// 0a1,2
// 1,2c4,6
// 1,5d6
preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff,
$matches, PREG_SET_ORDER);
foreach ($matches as $match) {
if (!isset($match[5])) {
// This paren is not set every time (see regex).
$match[5] = false;
}
if ($match[3] == 'a') {
$from_line_no--;
}
if ($match[3] == 'd') {
$to_line_no--;
}
if ($from_line_no < $match[1] || $to_line_no < $match[4]) {
// copied lines
assert('$match[1] - $from_line_no == $match[4] - $to_line_no');
array_push($edits,
new Text_Diff_Op_copy(
$this->_getLines($from_lines, $from_line_no, $match[1] - 1),
$this->_getLines($to_lines, $to_line_no, $match[4] - 1)));
}
switch ($match[3]) {
case 'd':
// deleted lines
array_push($edits,
new Text_Diff_Op_delete(
$this->_getLines($from_lines, $from_line_no, $match[2])));
$to_line_no++;
break;
case 'c':
// changed lines
array_push($edits,
new Text_Diff_Op_change(
$this->_getLines($from_lines, $from_line_no, $match[2]),
$this->_getLines($to_lines, $to_line_no, $match[5])));
break;
case 'a':
// added lines
array_push($edits,
new Text_Diff_Op_add(
$this->_getLines($to_lines, $to_line_no, $match[5])));
$from_line_no++;
break;
}
}
if (!empty($from_lines)) {
// Some lines might still be pending. Add them as copied
array_push($edits,
new Text_Diff_Op_copy(
$this->_getLines($from_lines, $from_line_no,
$from_line_no + count($from_lines) - 1),
$this->_getLines($to_lines, $to_line_no,
$to_line_no + count($to_lines) - 1)));
}
return $edits;
}
/**
* Get lines from either the old or new text
*
* @access private
*
* @param array &$text_lines Either $from_lines or $to_lines
* @param int &$line_no Current line number
* @param int $end Optional end line, when we want to chop more
* than one line.
*
* @return array The chopped lines
*/
function _getLines(&$text_lines, &$line_no, $end = false)
{
if (!empty($end)) {
$lines = array();
// We can shift even more
while ($line_no <= $end) {
array_push($lines, array_shift($text_lines));
$line_no++;
}
} else {
$lines = array(array_shift($text_lines));
$line_no++;
}
return $lines;
}
}

View File

@ -0,0 +1,248 @@
<?php
/**
* Parses unified or context diffs output from eg. the diff utility.
*
* Example:
* <code>
* $patch = file_get_contents('example.patch');
* $diff = new Text_Diff('string', array($patch));
* $renderer = new Text_Diff_Renderer_inline();
* echo $renderer->render($diff);
* </code>
*
* Copyright 2005 <20>rjan Persson <o@42mm.org>
* Copyright 2005-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
*
* @author <20>rjan Persson <o@42mm.org>
* @package Text_Diff
* @since 0.2.0
*/
class Text_Diff_Engine_string {
/**
* Parses a unified or context diff.
*
* First param contains the whole diff and the second can be used to force
* a specific diff type. If the second parameter is 'autodetect', the
* diff will be examined to find out which type of diff this is.
*
* @param string $diff The diff content.
* @param string $mode The diff mode of the content in $diff. One of
* 'context', 'unified', or 'autodetect'.
*
* @return array List of all diff operations.
*/
function diff($diff, $mode = 'autodetect')
{
// Detect line breaks.
$lnbr = "\n";
if (strpos($diff, "\r\n") !== false) {
$lnbr = "\r\n";
} elseif (strpos($diff, "\r") !== false) {
$lnbr = "\r";
}
// Make sure we have a line break at the EOF.
if (substr($diff, -strlen($lnbr)) != $lnbr) {
$diff .= $lnbr;
}
if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {
return PEAR::raiseError('Type of diff is unsupported');
}
if ($mode == 'autodetect') {
$context = strpos($diff, '***');
$unified = strpos($diff, '---');
if ($context === $unified) {
return PEAR::raiseError('Type of diff could not be detected');
} elseif ($context === false || $unified === false) {
$mode = $context !== false ? 'context' : 'unified';
} else {
$mode = $context < $unified ? 'context' : 'unified';
}
}
// Split by new line and remove the diff header, if there is one.
$diff = explode($lnbr, $diff);
if (($mode == 'context' && strpos($diff[0], '***') === 0) ||
($mode == 'unified' && strpos($diff[0], '---') === 0)) {
array_shift($diff);
array_shift($diff);
}
if ($mode == 'context') {
return $this->parseContextDiff($diff);
} else {
return $this->parseUnifiedDiff($diff);
}
}
/**
* Parses an array containing the unified diff.
*
* @param array $diff Array of lines.
*
* @return array List of all diff operations.
*/
function parseUnifiedDiff($diff)
{
$edits = array();
$end = count($diff) - 1;
for ($i = 0; $i < $end;) {
$diff1 = array();
switch (substr($diff[$i], 0, 1)) {
case ' ':
do {
$diff1[] = substr($diff[$i], 1);
} while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
$edits[] = &new Text_Diff_Op_copy($diff1);
break;
case '+':
// get all new lines
do {
$diff1[] = substr($diff[$i], 1);
} while (++$i < $end && substr($diff[$i], 0, 1) == '+');
$edits[] = &new Text_Diff_Op_add($diff1);
break;
case '-':
// get changed or removed lines
$diff2 = array();
do {
$diff1[] = substr($diff[$i], 1);
} while (++$i < $end && substr($diff[$i], 0, 1) == '-');
while ($i < $end && substr($diff[$i], 0, 1) == '+') {
$diff2[] = substr($diff[$i++], 1);
}
if (count($diff2) == 0) {
$edits[] = &new Text_Diff_Op_delete($diff1);
} else {
$edits[] = &new Text_Diff_Op_change($diff1, $diff2);
}
break;
default:
$i++;
break;
}
}
return $edits;
}
/**
* Parses an array containing the context diff.
*
* @param array $diff Array of lines.
*
* @return array List of all diff operations.
*/
function parseContextDiff(&$diff)
{
$edits = array();
$i = $max_i = $j = $max_j = 0;
$end = count($diff) - 1;
while ($i < $end && $j < $end) {
while ($i >= $max_i && $j >= $max_j) {
// Find the boundaries of the diff output of the two files
for ($i = $j;
$i < $end && substr($diff[$i], 0, 3) == '***';
$i++);
for ($max_i = $i;
$max_i < $end && substr($diff[$max_i], 0, 3) != '---';
$max_i++);
for ($j = $max_i;
$j < $end && substr($diff[$j], 0, 3) == '---';
$j++);
for ($max_j = $j;
$max_j < $end && substr($diff[$max_j], 0, 3) != '***';
$max_j++);
}
// find what hasn't been changed
$array = array();
while ($i < $max_i &&
$j < $max_j &&
strcmp($diff[$i], $diff[$j]) == 0) {
$array[] = substr($diff[$i], 2);
$i++;
$j++;
}
while ($i < $max_i && ($max_j-$j) <= 1) {
if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
break;
}
$array[] = substr($diff[$i++], 2);
}
while ($j < $max_j && ($max_i-$i) <= 1) {
if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
break;
}
$array[] = substr($diff[$j++], 2);
}
if (count($array) > 0) {
$edits[] = &new Text_Diff_Op_copy($array);
}
if ($i < $max_i) {
$diff1 = array();
switch (substr($diff[$i], 0, 1)) {
case '!':
$diff2 = array();
do {
$diff1[] = substr($diff[$i], 2);
if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
$diff2[] = substr($diff[$j++], 2);
}
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
$edits[] = &new Text_Diff_Op_change($diff1, $diff2);
break;
case '+':
do {
$diff1[] = substr($diff[$i], 2);
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
$edits[] = &new Text_Diff_Op_add($diff1);
break;
case '-':
do {
$diff1[] = substr($diff[$i], 2);
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
$edits[] = &new Text_Diff_Op_delete($diff1);
break;
}
}
if ($j < $max_j) {
$diff2 = array();
switch (substr($diff[$j], 0, 1)) {
case '+':
do {
$diff2[] = substr($diff[$j++], 2);
} while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
$edits[] = &new Text_Diff_Op_add($diff2);
break;
case '-':
do {
$diff2[] = substr($diff[$j++], 2);
} while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
$edits[] = &new Text_Diff_Op_delete($diff2);
break;
}
}
}
return $edits;
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
* Class used internally by Diff to actually compute the diffs.
*
* This class uses the xdiff PECL package (http://pecl.php.net/package/xdiff)
* to compute the differences between the two input arrays.
*
* Copyright 2004-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
*
* @author Jon Parise <jon@horde.org>
* @package Text_Diff
*/
class Text_Diff_Engine_xdiff {
/**
*/
function diff($from_lines, $to_lines)
{
array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
/* Convert the two input arrays into strings for xdiff processing. */
$from_string = implode("\n", $from_lines);
$to_string = implode("\n", $to_lines);
/* Diff the two strings and convert the result to an array. */
$diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
$diff = explode("\n", $diff);
/* Walk through the diff one line at a time. We build the $edits
* array of diff operations by reading the first character of the
* xdiff output (which is in the "unified diff" format).
*
* Note that we don't have enough information to detect "changed"
* lines using this approach, so we can't add Text_Diff_Op_changed
* instances to the $edits array. The result is still perfectly
* valid, albeit a little less descriptive and efficient. */
$edits = array();
foreach ($diff as $line) {
if (!strlen($line)) {
continue;
}
switch ($line[0]) {
case ' ':
$edits[] = &new Text_Diff_Op_copy(array(substr($line, 1)));
break;
case '+':
$edits[] = &new Text_Diff_Op_add(array(substr($line, 1)));
break;
case '-':
$edits[] = &new Text_Diff_Op_delete(array(substr($line, 1)));
break;
}
}
return $edits;
}
}

View File

@ -0,0 +1,235 @@
<?php
/**
* A class to render Diffs in different formats.
*
* This class renders the diff in classic diff format. It is intended that
* this class be customized via inheritance, to obtain fancier outputs.
*
* Copyright 2004-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
*
* @package Text_Diff
*/
class Text_Diff_Renderer {
/**
* Number of leading context "lines" to preserve.
*
* This should be left at zero for this class, but subclasses may want to
* set this to other values.
*/
var $_leading_context_lines = 0;
/**
* Number of trailing context "lines" to preserve.
*
* This should be left at zero for this class, but subclasses may want to
* set this to other values.
*/
var $_trailing_context_lines = 0;
/**
* Constructor.
*/
function Text_Diff_Renderer($params = array())
{
foreach ($params as $param => $value) {
$v = '_' . $param;
if (isset($this->$v)) {
$this->$v = $value;
}
}
}
/**
* Get any renderer parameters.
*
* @return array All parameters of this renderer object.
*/
function getParams()
{
$params = array();
foreach (get_object_vars($this) as $k => $v) {
if ($k[0] == '_') {
$params[substr($k, 1)] = $v;
}
}
return $params;
}
/**
* Renders a diff.
*
* @param Text_Diff $diff A Text_Diff object.
*
* @return string The formatted output.
*/
function render($diff)
{
$xi = $yi = 1;
$block = false;
$context = array();
$nlead = $this->_leading_context_lines;
$ntrail = $this->_trailing_context_lines;
$output = $this->_startDiff();
$diffs = $diff->getDiff();
foreach ($diffs as $i => $edit) {
/* If these are unchanged (copied) lines, and we want to keep
* leading or trailing context lines, extract them from the copy
* block. */
if (is_a($edit, 'Text_Diff_Op_copy')) {
/* Do we have any diff blocks yet? */
if (is_array($block)) {
/* How many lines to keep as context from the copy
* block. */
$keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
if (count($edit->orig) <= $keep) {
/* We have less lines in the block than we want for
* context => keep the whole block. */
$block[] = $edit;
} else {
if ($ntrail) {
/* Create a new block with as many lines as we need
* for the trailing context. */
$context = array_slice($edit->orig, 0, $ntrail);
$block[] = &new Text_Diff_Op_copy($context);
}
/* @todo */
$output .= $this->_block($x0, $ntrail + $xi - $x0,
$y0, $ntrail + $yi - $y0,
$block);
$block = false;
}
}
/* Keep the copy block as the context for the next block. */
$context = $edit->orig;
} else {
/* Don't we have any diff blocks yet? */
if (!is_array($block)) {
/* Extract context lines from the preceding copy block. */
$context = array_slice($context, count($context) - $nlead);
$x0 = $xi - count($context);
$y0 = $yi - count($context);
$block = array();
if ($context) {
$block[] = &new Text_Diff_Op_copy($context);
}
}
$block[] = $edit;
}
if ($edit->orig) {
$xi += count($edit->orig);
}
if ($edit->final) {
$yi += count($edit->final);
}
}
if (is_array($block)) {
$output .= $this->_block($x0, $xi - $x0,
$y0, $yi - $y0,
$block);
}
return $output . $this->_endDiff();
}
function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
{
$output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
foreach ($edits as $edit) {
switch (strtolower(get_class($edit))) {
case 'text_diff_op_copy':
$output .= $this->_context($edit->orig);
break;
case 'text_diff_op_add':
$output .= $this->_added($edit->final);
break;
case 'text_diff_op_delete':
$output .= $this->_deleted($edit->orig);
break;
case 'text_diff_op_change':
$output .= $this->_changed($edit->orig, $edit->final);
break;
}
}
return $output . $this->_endBlock();
}
function _startDiff()
{
return '';
}
function _endDiff()
{
return '';
}
function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
{
if ($xlen > 1) {
$xbeg .= ',' . ($xbeg + $xlen - 1);
}
if ($ylen > 1) {
$ybeg .= ',' . ($ybeg + $ylen - 1);
}
// this matches the GNU Diff behaviour
if ($xlen && !$ylen) {
$ybeg--;
} elseif (!$xlen) {
$xbeg--;
}
return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
}
function _startBlock($header)
{
return $header . "\n";
}
function _endBlock()
{
return '';
}
function _lines($lines, $prefix = ' ')
{
return $prefix . implode("\n$prefix", $lines) . "\n";
}
function _context($lines)
{
return $this->_lines($lines, ' ');
}
function _added($lines)
{
return $this->_lines($lines, '> ');
}
function _deleted($lines)
{
return $this->_lines($lines, '< ');
}
function _changed($orig, $final)
{
return $this->_deleted($orig) . "---\n" . $this->_added($final);
}
}

View File

@ -0,0 +1,206 @@
<?php
/**
* "Inline" diff renderer.
*
* Copyright 2004-2010 The Horde Project (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
*
* @author Ciprian Popovici
* @package Text_Diff
*/
/** Text_Diff_Renderer */
// WP #7391
require_once dirname(dirname(__FILE__)) . '/Renderer.php';
/**
* "Inline" diff renderer.
*
* This class renders diffs in the Wiki-style "inline" format.
*
* @author Ciprian Popovici
* @package Text_Diff
*/
class Text_Diff_Renderer_inline extends Text_Diff_Renderer {
/**
* Number of leading context "lines" to preserve.
*
* @var integer
*/
var $_leading_context_lines = 10000;
/**
* Number of trailing context "lines" to preserve.
*
* @var integer
*/
var $_trailing_context_lines = 10000;
/**
* Prefix for inserted text.
*
* @var string
*/
var $_ins_prefix = '<ins>';
/**
* Suffix for inserted text.
*
* @var string
*/
var $_ins_suffix = '</ins>';
/**
* Prefix for deleted text.
*
* @var string
*/
var $_del_prefix = '<del>';
/**
* Suffix for deleted text.
*
* @var string
*/
var $_del_suffix = '</del>';
/**
* Header for each change block.
*
* @var string
*/
var $_block_header = '';
/**
* Whether to split down to character-level.
*
* @var boolean
*/
var $_split_characters = false;
/**
* What are we currently splitting on? Used to recurse to show word-level
* or character-level changes.
*
* @var string
*/
var $_split_level = 'lines';
function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
{
return $this->_block_header;
}
function _startBlock($header)
{
return $header;
}
function _lines($lines, $prefix = ' ', $encode = true)
{
if ($encode) {
array_walk($lines, array(&$this, '_encode'));
}
if ($this->_split_level == 'lines') {
return implode("\n", $lines) . "\n";
} else {
return implode('', $lines);
}
}
function _added($lines)
{
array_walk($lines, array(&$this, '_encode'));
$lines[0] = $this->_ins_prefix . $lines[0];
$lines[count($lines) - 1] .= $this->_ins_suffix;
return $this->_lines($lines, ' ', false);
}
function _deleted($lines, $words = false)
{
array_walk($lines, array(&$this, '_encode'));
$lines[0] = $this->_del_prefix . $lines[0];
$lines[count($lines) - 1] .= $this->_del_suffix;
return $this->_lines($lines, ' ', false);
}
function _changed($orig, $final)
{
/* If we've already split on characters, just display. */
if ($this->_split_level == 'characters') {
return $this->_deleted($orig)
. $this->_added($final);
}
/* If we've already split on words, just display. */
if ($this->_split_level == 'words') {
$prefix = '';
while ($orig[0] !== false && $final[0] !== false &&
substr($orig[0], 0, 1) == ' ' &&
substr($final[0], 0, 1) == ' ') {
$prefix .= substr($orig[0], 0, 1);
$orig[0] = substr($orig[0], 1);
$final[0] = substr($final[0], 1);
}
return $prefix . $this->_deleted($orig) . $this->_added($final);
}
$text1 = implode("\n", $orig);
$text2 = implode("\n", $final);
/* Non-printing newline marker. */
$nl = "\0";
if ($this->_split_characters) {
$diff = new Text_Diff('native',
array(preg_split('//', $text1),
preg_split('//', $text2)));
} else {
/* We want to split on word boundaries, but we need to preserve
* whitespace as well. Therefore we split on words, but include
* all blocks of whitespace in the wordlist. */
$diff = new Text_Diff('native',
array($this->_splitOnWords($text1, $nl),
$this->_splitOnWords($text2, $nl)));
}
/* Get the diff in inline format. */
$renderer = new Text_Diff_Renderer_inline
(array_merge($this->getParams(),
array('split_level' => $this->_split_characters ? 'characters' : 'words')));
/* Run the diff and get the output. */
return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
}
function _splitOnWords($string, $newlineEscape = "\n")
{
// Ignore \0; otherwise the while loop will never finish.
$string = str_replace("\0", '', $string);
$words = array();
$length = strlen($string);
$pos = 0;
while ($pos < $length) {
// Eat a word with any preceding whitespace.
$spaces = strspn(substr($string, $pos), " \n");
$nextpos = strcspn(substr($string, $pos + $spaces), " \n");
$words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos));
$pos += $spaces + $nextpos;
}
return $words;
}
function _encode(&$string)
{
$string = htmlspecialchars($string);
}
}

770
wp-includes/admin-bar.php Normal file
View File

@ -0,0 +1,770 @@
<?php
/**
* Admin Bar
*
* This code handles the building and rendering of the press bar.
*/
/**
* Instantiate the admin bar object and set it up as a global for access elsewhere.
*
* To hide the admin bar, you're looking in the wrong place. Unhooking this function will not
* properly remove the admin bar. For that, use show_admin_bar(false) or the show_admin_bar filter.
*
* @since 3.1.0
* @access private
* @return bool Whether the admin bar was successfully initialized.
*/
function _wp_admin_bar_init() {
global $wp_admin_bar;
if ( ! is_admin_bar_showing() )
return false;
/* Load the admin bar class code ready for instantiation */
require( ABSPATH . WPINC . '/class-wp-admin-bar.php' );
/* Instantiate the admin bar */
$admin_bar_class = apply_filters( 'wp_admin_bar_class', 'WP_Admin_Bar' );
if ( class_exists( $admin_bar_class ) )
$wp_admin_bar = new $admin_bar_class;
else
return false;
$wp_admin_bar->initialize();
$wp_admin_bar->add_menus();
return true;
}
add_action( 'init', '_wp_admin_bar_init' ); // Don't remove. Wrong way to disable.
/**
* Render the admin bar to the page based on the $wp_admin_bar->menu member var.
* This is called very late on the footer actions so that it will render after anything else being
* added to the footer.
*
* It includes the action "admin_bar_menu" which should be used to hook in and
* add new menus to the admin bar. That way you can be sure that you are adding at most optimal point,
* right before the admin bar is rendered. This also gives you access to the $post global, among others.
*
* @since 3.1.0
*/
function wp_admin_bar_render() {
global $wp_admin_bar;
if ( ! is_admin_bar_showing() || ! is_object( $wp_admin_bar ) )
return false;
do_action_ref_array( 'admin_bar_menu', array( &$wp_admin_bar ) );
do_action( 'wp_before_admin_bar_render' );
$wp_admin_bar->render();
do_action( 'wp_after_admin_bar_render' );
}
add_action( 'wp_footer', 'wp_admin_bar_render', 1000 );
add_action( 'in_admin_header', 'wp_admin_bar_render', 0 );
/**
* Add the WordPress logo menu.
*
* @since 3.3.0
*/
function wp_admin_bar_wp_menu( $wp_admin_bar ) {
$wp_admin_bar->add_menu( array(
'id' => 'wp-logo',
'title' => '<span class="ab-icon"></span>',
'href' => self_admin_url( 'about.php' ),
'meta' => array(
'title' => __('About WordPress'),
),
) );
if ( is_user_logged_in() ) {
// Add "About WordPress" link
$wp_admin_bar->add_menu( array(
'parent' => 'wp-logo',
'id' => 'about',
'title' => __('About WordPress'),
'href' => self_admin_url( 'about.php' ),
) );
}
// Add WordPress.org link
$wp_admin_bar->add_menu( array(
'parent' => 'wp-logo-external',
'id' => 'wporg',
'title' => __('WordPress.org'),
'href' => __('http://wordpress.org/'),
) );
// Add codex link
$wp_admin_bar->add_menu( array(
'parent' => 'wp-logo-external',
'id' => 'documentation',
'title' => __('Documentation'),
'href' => __('http://codex.wordpress.org/'),
) );
// Add forums link
$wp_admin_bar->add_menu( array(
'parent' => 'wp-logo-external',
'id' => 'support-forums',
'title' => __('Support Forums'),
'href' => __('http://wordpress.org/support/'),
) );
// Add feedback link
$wp_admin_bar->add_menu( array(
'parent' => 'wp-logo-external',
'id' => 'feedback',
'title' => __('Feedback'),
'href' => __('http://wordpress.org/support/forum/requests-and-feedback'),
) );
}
/**
* Add the "My Account" item.
*
* @since 3.3.0
*/
function wp_admin_bar_my_account_item( $wp_admin_bar ) {
$user_id = get_current_user_id();
$current_user = wp_get_current_user();
$profile_url = get_edit_profile_url( $user_id );
if ( ! $user_id )
return;
$avatar = get_avatar( $user_id, 16 );
$howdy = sprintf( __('Howdy, %1$s'), $current_user->display_name );
$class = empty( $avatar ) ? '' : 'with-avatar';
$wp_admin_bar->add_menu( array(
'id' => 'my-account',
'parent' => 'top-secondary',
'title' => $howdy . $avatar,
'href' => $profile_url,
'meta' => array(
'class' => $class,
'title' => __('My Account'),
),
) );
}
/**
* Add the "My Account" submenu items.
*
* @since 3.1.0
*/
function wp_admin_bar_my_account_menu( $wp_admin_bar ) {
$user_id = get_current_user_id();
$current_user = wp_get_current_user();
$profile_url = get_edit_profile_url( $user_id );
if ( ! $user_id )
return;
$wp_admin_bar->add_group( array(
'parent' => 'my-account',
'id' => 'user-actions',
) );
$user_info = get_avatar( $user_id, 64 );
$user_info .= "<span class='display-name'>{$current_user->display_name}</span>";
if ( $current_user->display_name !== $current_user->user_nicename )
$user_info .= "<span class='username'>{$current_user->user_nicename}</span>";
$wp_admin_bar->add_menu( array(
'parent' => 'user-actions',
'id' => 'user-info',
'title' => $user_info,
'href' => $profile_url,
'meta' => array(
'tabindex' => -1,
),
) );
$wp_admin_bar->add_menu( array(
'parent' => 'user-actions',
'id' => 'edit-profile',
'title' => __( 'Edit My Profile' ),
'href' => $profile_url,
) );
$wp_admin_bar->add_menu( array(
'parent' => 'user-actions',
'id' => 'logout',
'title' => __( 'Log Out' ),
'href' => wp_logout_url(),
) );
}
/**
* Add the "Site Name" menu.
*
* @since 3.3.0
*/
function wp_admin_bar_site_menu( $wp_admin_bar ) {
global $current_site;
// Don't show for logged out users.
if ( ! is_user_logged_in() )
return;
// Show only when the user is a member of this site, or they're a super admin.
if ( ! is_user_member_of_blog() && ! is_super_admin() )
return;
$blogname = get_bloginfo('name');
if ( empty( $blogname ) )
$blogname = preg_replace( '#^(https?://)?(www.)?#', '', get_home_url() );
if ( is_network_admin() ) {
$blogname = sprintf( __('Network Admin: %s'), esc_html( $current_site->site_name ) );
} elseif ( is_user_admin() ) {
$blogname = sprintf( __('Global Dashboard: %s'), esc_html( $current_site->site_name ) );
}
$title = wp_html_excerpt( $blogname, 40 );
if ( $title != $blogname )
$title = trim( $title ) . '&hellip;';
$wp_admin_bar->add_menu( array(
'id' => 'site-name',
'title' => $title,
'href' => is_admin() ? home_url( '/' ) : admin_url(),
) );
// Create submenu items.
if ( is_admin() ) {
// Add an option to visit the site.
$wp_admin_bar->add_menu( array(
'parent' => 'site-name',
'id' => 'view-site',
'title' => __( 'Visit Site' ),
'href' => home_url( '/' ),
) );
if ( is_blog_admin() && is_multisite() && current_user_can( 'manage_sites' ) ) {
$wp_admin_bar->add_menu( array(
'parent' => 'site-name',
'id' => 'edit-site',
'title' => __( 'Edit Site' ),
'href' => network_admin_url( 'site-info.php?id=' . get_current_blog_id() ),
) );
}
} else {
// We're on the front end, link to the Dashboard.
$wp_admin_bar->add_menu( array(
'parent' => 'site-name',
'id' => 'dashboard',
'title' => __( 'Dashboard' ),
'href' => admin_url(),
) );
// Add the appearance submenu items.
wp_admin_bar_appearance_menu( $wp_admin_bar );
}
}
/**
* Add the "My Sites/[Site Name]" menu and all submenus.
*
* @since 3.1.0
*/
function wp_admin_bar_my_sites_menu( $wp_admin_bar ) {
global $wpdb;
// Don't show for logged out users or single site mode.
if ( ! is_user_logged_in() || ! is_multisite() )
return;
// Show only when the user has at least one site, or they're a super admin.
if ( count( $wp_admin_bar->user->blogs ) < 1 && ! is_super_admin() )
return;
$wp_admin_bar->add_menu( array(
'id' => 'my-sites',
'title' => __( 'My Sites' ),
'href' => admin_url( 'my-sites.php' ),
) );
if ( is_super_admin() ) {
$wp_admin_bar->add_group( array(
'parent' => 'my-sites',
'id' => 'my-sites-super-admin',
) );
$wp_admin_bar->add_menu( array(
'parent' => 'my-sites-super-admin',
'id' => 'network-admin',
'title' => __('Network Admin'),
'href' => network_admin_url(),
) );
$wp_admin_bar->add_menu( array(
'parent' => 'network-admin',
'id' => 'network-admin-d',
'title' => __( 'Dashboard' ),
'href' => network_admin_url(),
) );
$wp_admin_bar->add_menu( array(
'parent' => 'network-admin',
'id' => 'network-admin-s',
'title' => __( 'Sites' ),
'href' => network_admin_url( 'sites.php' ),
) );
$wp_admin_bar->add_menu( array(
'parent' => 'network-admin',
'id' => 'network-admin-u',
'title' => __( 'Users' ),
'href' => network_admin_url( 'users.php' ),
) );
$wp_admin_bar->add_menu( array(
'parent' => 'network-admin',
'id' => 'network-admin-v',
'title' => __( 'Visit Network' ),
'href' => network_home_url(),
) );
}
// Add site links
$wp_admin_bar->add_group( array(
'parent' => 'my-sites',
'id' => 'my-sites-list',
'meta' => array(
'class' => is_super_admin() ? 'ab-sub-secondary' : '',
),
) );
foreach ( (array) $wp_admin_bar->user->blogs as $blog ) {
switch_to_blog( $blog->userblog_id );
$blavatar = '<div class="blavatar"></div>';
$blogname = empty( $blog->blogname ) ? $blog->domain : $blog->blogname;
$menu_id = 'blog-' . $blog->userblog_id;
$wp_admin_bar->add_menu( array(
'parent' => 'my-sites-list',
'id' => $menu_id,
'title' => $blavatar . $blogname,
'href' => admin_url(),
) );
$wp_admin_bar->add_menu( array(
'parent' => $menu_id,
'id' => $menu_id . '-d',
'title' => __( 'Dashboard' ),
'href' => admin_url(),
) );
if ( current_user_can( get_post_type_object( 'post' )->cap->create_posts ) ) {
$wp_admin_bar->add_menu( array(
'parent' => $menu_id,
'id' => $menu_id . '-n',
'title' => __( 'New Post' ),
'href' => admin_url( 'post-new.php' ),
) );
}
if ( current_user_can( 'edit_posts' ) ) {
$wp_admin_bar->add_menu( array(
'parent' => $menu_id,
'id' => $menu_id . '-c',
'title' => __( 'Manage Comments' ),
'href' => admin_url( 'edit-comments.php' ),
) );
}
$wp_admin_bar->add_menu( array(
'parent' => $menu_id,
'id' => $menu_id . '-v',
'title' => __( 'Visit Site' ),
'href' => home_url( '/' ),
) );
restore_current_blog();
}
}
/**
* Provide a shortlink.
*
* @since 3.1.0
*/
function wp_admin_bar_shortlink_menu( $wp_admin_bar ) {
$short = wp_get_shortlink( 0, 'query' );
$id = 'get-shortlink';
if ( empty( $short ) )
return;
$html = '<input class="shortlink-input" type="text" readonly="readonly" value="' . esc_attr( $short ) . '" />';
$wp_admin_bar->add_menu( array(
'id' => $id,
'title' => __( 'Shortlink' ),
'href' => $short,
'meta' => array( 'html' => $html ),
) );
}
/**
* Provide an edit link for posts and terms.
*
* @since 3.1.0
*/
function wp_admin_bar_edit_menu( $wp_admin_bar ) {
global $tag, $wp_the_query;
if ( is_admin() ) {
$current_screen = get_current_screen();
$post = get_post();
if ( 'post' == $current_screen->base
&& 'add' != $current_screen->action
&& ( $post_type_object = get_post_type_object( $post->post_type ) )
&& current_user_can( $post_type_object->cap->read_post, $post->ID )
&& ( $post_type_object->public )
&& ( $post_type_object->show_in_admin_bar ) )
{
$wp_admin_bar->add_menu( array(
'id' => 'view',
'title' => $post_type_object->labels->view_item,
'href' => get_permalink( $post->ID )
) );
} elseif ( 'edit-tags' == $current_screen->base
&& isset( $tag ) && is_object( $tag )
&& ( $tax = get_taxonomy( $tag->taxonomy ) )
&& $tax->public )
{
$wp_admin_bar->add_menu( array(
'id' => 'view',
'title' => $tax->labels->view_item,
'href' => get_term_link( $tag )
) );
}
} else {
$current_object = $wp_the_query->get_queried_object();
if ( empty( $current_object ) )
return;
if ( ! empty( $current_object->post_type )
&& ( $post_type_object = get_post_type_object( $current_object->post_type ) )
&& current_user_can( $post_type_object->cap->edit_post, $current_object->ID )
&& $post_type_object->show_ui && $post_type_object->show_in_admin_bar )
{
$wp_admin_bar->add_menu( array(
'id' => 'edit',
'title' => $post_type_object->labels->edit_item,
'href' => get_edit_post_link( $current_object->ID )
) );
} elseif ( ! empty( $current_object->taxonomy )
&& ( $tax = get_taxonomy( $current_object->taxonomy ) )
&& current_user_can( $tax->cap->edit_terms )
&& $tax->show_ui )
{
$wp_admin_bar->add_menu( array(
'id' => 'edit',
'title' => $tax->labels->edit_item,
'href' => get_edit_term_link( $current_object->term_id, $current_object->taxonomy )
) );
}
}
}
/**
* Add "Add New" menu.
*
* @since 3.1.0
*/
function wp_admin_bar_new_content_menu( $wp_admin_bar ) {
$actions = array();
$cpts = (array) get_post_types( array( 'show_in_admin_bar' => true ), 'objects' );
if ( isset( $cpts['post'] ) && current_user_can( $cpts['post']->cap->create_posts ) )
$actions[ 'post-new.php' ] = array( $cpts['post']->labels->name_admin_bar, 'new-post' );
if ( isset( $cpts['attachment'] ) && current_user_can( 'upload_files' ) )
$actions[ 'media-new.php' ] = array( $cpts['attachment']->labels->name_admin_bar, 'new-media' );
if ( current_user_can( 'manage_links' ) )
$actions[ 'link-add.php' ] = array( _x( 'Link', 'add new from admin bar' ), 'new-link' );
if ( isset( $cpts['page'] ) && current_user_can( $cpts['page']->cap->create_posts ) )
$actions[ 'post-new.php?post_type=page' ] = array( $cpts['page']->labels->name_admin_bar, 'new-page' );
unset( $cpts['post'], $cpts['page'], $cpts['attachment'] );
// Add any additional custom post types.
foreach ( $cpts as $cpt ) {
if ( ! current_user_can( $cpt->cap->create_posts ) )
continue;
$key = 'post-new.php?post_type=' . $cpt->name;
$actions[ $key ] = array( $cpt->labels->name_admin_bar, 'new-' . $cpt->name );
}
// Avoid clash with parent node and a 'content' post type.
if ( isset( $actions['post-new.php?post_type=content'] ) )
$actions['post-new.php?post_type=content'][1] = 'add-new-content';
if ( current_user_can( 'create_users' ) || current_user_can( 'promote_users' ) )
$actions[ 'user-new.php' ] = array( _x( 'User', 'add new from admin bar' ), 'new-user' );
if ( ! $actions )
return;
$title = '<span class="ab-icon"></span><span class="ab-label">' . _x( 'New', 'admin bar menu group label' ) . '</span>';
$wp_admin_bar->add_menu( array(
'id' => 'new-content',
'title' => $title,
'href' => admin_url( current( array_keys( $actions ) ) ),
'meta' => array(
'title' => _x( 'Add New', 'admin bar menu group label' ),
),
) );
foreach ( $actions as $link => $action ) {
list( $title, $id ) = $action;
$wp_admin_bar->add_menu( array(
'parent' => 'new-content',
'id' => $id,
'title' => $title,
'href' => admin_url( $link )
) );
}
}
/**
* Add edit comments link with awaiting moderation count bubble.
*
* @since 3.1.0
*/
function wp_admin_bar_comments_menu( $wp_admin_bar ) {
if ( !current_user_can('edit_posts') )
return;
$awaiting_mod = wp_count_comments();
$awaiting_mod = $awaiting_mod->moderated;
$awaiting_title = esc_attr( sprintf( _n( '%s comment awaiting moderation', '%s comments awaiting moderation', $awaiting_mod ), number_format_i18n( $awaiting_mod ) ) );
$icon = '<span class="ab-icon"></span>';
$title = '<span id="ab-awaiting-mod" class="ab-label awaiting-mod pending-count count-' . $awaiting_mod . '">' . number_format_i18n( $awaiting_mod ) . '</span>';
$wp_admin_bar->add_menu( array(
'id' => 'comments',
'title' => $icon . $title,
'href' => admin_url('edit-comments.php'),
'meta' => array( 'title' => $awaiting_title ),
) );
}
/**
* Add appearance submenu items to the "Site Name" menu.
*
* @since 3.1.0
*/
function wp_admin_bar_appearance_menu( $wp_admin_bar ) {
$wp_admin_bar->add_group( array( 'parent' => 'site-name', 'id' => 'appearance' ) );
if ( current_user_can( 'switch_themes' ) || current_user_can( 'edit_theme_options' ) )
$wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'themes', 'title' => __('Themes'), 'href' => admin_url('themes.php') ) );
if ( ! current_user_can( 'edit_theme_options' ) )
return;
$current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$wp_admin_bar->add_menu( array(
'parent' => 'appearance',
'id' => 'customize',
'title' => __('Customize'),
'href' => add_query_arg( 'url', urlencode( $current_url ), wp_customize_url() ),
'meta' => array(
'class' => 'hide-if-no-customize',
),
) );
add_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' );
if ( current_theme_supports( 'widgets' ) )
$wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'widgets', 'title' => __('Widgets'), 'href' => admin_url('widgets.php') ) );
if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) )
$wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'menus', 'title' => __('Menus'), 'href' => admin_url('nav-menus.php') ) );
if ( current_theme_supports( 'custom-background' ) )
$wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'background', 'title' => __('Background'), 'href' => admin_url('themes.php?page=custom-background') ) );
if ( current_theme_supports( 'custom-header' ) )
$wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'header', 'title' => __('Header'), 'href' => admin_url('themes.php?page=custom-header') ) );
}
/**
* Provide an update link if theme/plugin/core updates are available.
*
* @since 3.1.0
*/
function wp_admin_bar_updates_menu( $wp_admin_bar ) {
$update_data = wp_get_update_data();
if ( !$update_data['counts']['total'] )
return;
$title = '<span class="ab-icon"></span><span class="ab-label">' . number_format_i18n( $update_data['counts']['total'] ) . '</span>';
$title .= '<span class="screen-reader-text">' . $update_data['title'] . '</span>';
$wp_admin_bar->add_menu( array(
'id' => 'updates',
'title' => $title,
'href' => network_admin_url( 'update-core.php' ),
'meta' => array(
'title' => $update_data['title'],
),
) );
}
/**
* Add search form.
*
* @since 3.3.0
*/
function wp_admin_bar_search_menu( $wp_admin_bar ) {
if ( is_admin() )
return;
$form = '<form action="' . esc_url( home_url( '/' ) ) . '" method="get" id="adminbarsearch">';
$form .= '<input class="adminbar-input" name="s" id="adminbar-search" type="text" value="" maxlength="150" />';
$form .= '<input type="submit" class="adminbar-button" value="' . __('Search') . '"/>';
$form .= '</form>';
$wp_admin_bar->add_menu( array(
'parent' => 'top-secondary',
'id' => 'search',
'title' => $form,
'meta' => array(
'class' => 'admin-bar-search',
'tabindex' => -1,
)
) );
}
/**
* Add secondary menus.
*
* @since 3.3.0
*/
function wp_admin_bar_add_secondary_groups( $wp_admin_bar ) {
$wp_admin_bar->add_group( array(
'id' => 'top-secondary',
'meta' => array(
'class' => 'ab-top-secondary',
),
) );
$wp_admin_bar->add_group( array(
'parent' => 'wp-logo',
'id' => 'wp-logo-external',
'meta' => array(
'class' => 'ab-sub-secondary',
),
) );
}
/**
* Style and scripts for the admin bar.
*
* @since 3.1.0
*
*/
function wp_admin_bar_header() { ?>
<style type="text/css" media="print">#wpadminbar { display:none; }</style>
<?php
}
/**
* Default admin bar callback.
*
* @since 3.1.0
*
*/
function _admin_bar_bump_cb() { ?>
<style type="text/css" media="screen">
html { margin-top: 28px !important; }
* html body { margin-top: 28px !important; }
</style>
<?php
}
/**
* Set the display status of the admin bar.
*
* This can be called immediately upon plugin load. It does not need to be called from a function hooked to the init action.
*
* @since 3.1.0
*
* @param bool $show Whether to allow the admin bar to show.
* @return void
*/
function show_admin_bar( $show ) {
global $show_admin_bar;
$show_admin_bar = (bool) $show;
}
/**
* Determine whether the admin bar should be showing.
*
* @since 3.1.0
*
* @return bool Whether the admin bar should be showing.
*/
function is_admin_bar_showing() {
global $show_admin_bar, $pagenow;
// For all these types of requests, we never want an admin bar.
if ( defined('XMLRPC_REQUEST') || defined('DOING_AJAX') || defined('IFRAME_REQUEST') )
return false;
// Integrated into the admin.
if ( is_admin() )
return true;
if ( ! isset( $show_admin_bar ) ) {
if ( ! is_user_logged_in() || 'wp-login.php' == $pagenow ) {
$show_admin_bar = false;
} else {
$show_admin_bar = _get_admin_bar_pref();
}
}
$show_admin_bar = apply_filters( 'show_admin_bar', $show_admin_bar );
return $show_admin_bar;
}
/**
* Retrieve the admin bar display preference of a user.
*
* @since 3.1.0
* @access private
*
* @param string $context Context of this preference check. Defaults to 'front'. The 'admin'
* preference is no longer used.
* @param int $user Optional. ID of the user to check, defaults to 0 for current user.
* @return bool Whether the admin bar should be showing for this user.
*/
function _get_admin_bar_pref( $context = 'front', $user = 0 ) {
$pref = get_user_option( "show_admin_bar_{$context}", $user );
if ( false === $pref )
return true;
return 'true' === $pref;
}

352
wp-includes/atomlib.php Normal file
View File

@ -0,0 +1,352 @@
<?php
/**
* Atom Syndication Format PHP Library
*
* @package AtomLib
* @link http://code.google.com/p/phpatomlib/
*
* @author Elias Torres <elias@torrez.us>
* @version 0.4
* @since 2.3
*/
/**
* Structure that store common Atom Feed Properties
*
* @package AtomLib
*/
class AtomFeed {
/**
* Stores Links
* @var array
* @access public
*/
var $links = array();
/**
* Stores Categories
* @var array
* @access public
*/
var $categories = array();
/**
* Stores Entries
*
* @var array
* @access public
*/
var $entries = array();
}
/**
* Structure that store Atom Entry Properties
*
* @package AtomLib
*/
class AtomEntry {
/**
* Stores Links
* @var array
* @access public
*/
var $links = array();
/**
* Stores Categories
* @var array
* @access public
*/
var $categories = array();
}
/**
* AtomLib Atom Parser API
*
* @package AtomLib
*/
class AtomParser {
var $NS = 'http://www.w3.org/2005/Atom';
var $ATOM_CONTENT_ELEMENTS = array('content','summary','title','subtitle','rights');
var $ATOM_SIMPLE_ELEMENTS = array('id','updated','published','draft');
var $debug = false;
var $depth = 0;
var $indent = 2;
var $in_content;
var $ns_contexts = array();
var $ns_decls = array();
var $content_ns_decls = array();
var $content_ns_contexts = array();
var $is_xhtml = false;
var $is_html = false;
var $is_text = true;
var $skipped_div = false;
var $FILE = "php://input";
var $feed;
var $current;
function AtomParser() {
$this->feed = new AtomFeed();
$this->current = null;
$this->map_attrs_func = create_function('$k,$v', 'return "$k=\"$v\"";');
$this->map_xmlns_func = create_function('$p,$n', '$xd = "xmlns"; if(strlen($n[0])>0) $xd .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";');
}
function _p($msg) {
if($this->debug) {
print str_repeat(" ", $this->depth * $this->indent) . $msg ."\n";
}
}
function error_handler($log_level, $log_text, $error_file, $error_line) {
$this->error = $log_text;
}
function parse() {
set_error_handler(array(&$this, 'error_handler'));
array_unshift($this->ns_contexts, array());
$parser = xml_parser_create_ns();
xml_set_object($parser, $this);
xml_set_element_handler($parser, "start_element", "end_element");
xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
xml_set_character_data_handler($parser, "cdata");
xml_set_default_handler($parser, "_default");
xml_set_start_namespace_decl_handler($parser, "start_ns");
xml_set_end_namespace_decl_handler($parser, "end_ns");
$this->content = '';
$ret = true;
$fp = fopen($this->FILE, "r");
while ($data = fread($fp, 4096)) {
if($this->debug) $this->content .= $data;
if(!xml_parse($parser, $data, feof($fp))) {
trigger_error(sprintf(__('XML error: %s at line %d')."\n",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
$ret = false;
break;
}
}
fclose($fp);
xml_parser_free($parser);
restore_error_handler();
return $ret;
}
function start_element($parser, $name, $attrs) {
$tag = array_pop(split(":", $name));
switch($name) {
case $this->NS . ':feed':
$this->current = $this->feed;
break;
case $this->NS . ':entry':
$this->current = new AtomEntry();
break;
};
$this->_p("start_element('$name')");
#$this->_p(print_r($this->ns_contexts,true));
#$this->_p('current(' . $this->current . ')');
array_unshift($this->ns_contexts, $this->ns_decls);
$this->depth++;
if(!empty($this->in_content)) {
$this->content_ns_decls = array();
if($this->is_html || $this->is_text)
trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup.");
$attrs_prefix = array();
// resolve prefixes for attributes
foreach($attrs as $key => $value) {
$with_prefix = $this->ns_to_prefix($key, true);
$attrs_prefix[$with_prefix[1]] = $this->xml_escape($value);
}
$attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
if(strlen($attrs_str) > 0) {
$attrs_str = " " . $attrs_str;
}
$with_prefix = $this->ns_to_prefix($name);
if(!$this->is_declared_content_ns($with_prefix[0])) {
array_push($this->content_ns_decls, $with_prefix[0]);
}
$xmlns_str = '';
if(count($this->content_ns_decls) > 0) {
array_unshift($this->content_ns_contexts, $this->content_ns_decls);
$xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0])));
if(strlen($xmlns_str) > 0) {
$xmlns_str = " " . $xmlns_str;
}
}
array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">"));
} else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
$this->in_content = array();
$this->is_xhtml = $attrs['type'] == 'xhtml';
$this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html';
$this->is_text = !in_array('type',array_keys($attrs)) || $attrs['type'] == 'text';
$type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type']));
if(in_array('src',array_keys($attrs))) {
$this->current->$tag = $attrs;
} else {
array_push($this->in_content, array($tag,$this->depth, $type));
}
} else if($tag == 'link') {
array_push($this->current->links, $attrs);
} else if($tag == 'category') {
array_push($this->current->categories, $attrs);
}
$this->ns_decls = array();
}
function end_element($parser, $name) {
$tag = array_pop(split(":", $name));
$ccount = count($this->in_content);
# if we are *in* content, then let's proceed to serialize it
if(!empty($this->in_content)) {
# if we are ending the original content element
# then let's finalize the content
if($this->in_content[0][0] == $tag &&
$this->in_content[0][1] == $this->depth) {
$origtype = $this->in_content[0][2];
array_shift($this->in_content);
$newcontent = array();
foreach($this->in_content as $c) {
if(count($c) == 3) {
array_push($newcontent, $c[2]);
} else {
if($this->is_xhtml || $this->is_text) {
array_push($newcontent, $this->xml_escape($c));
} else {
array_push($newcontent, $c);
}
}
}
if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS)) {
$this->current->$tag = array($origtype, join('',$newcontent));
} else {
$this->current->$tag = join('',$newcontent);
}
$this->in_content = array();
} else if($this->in_content[$ccount-1][0] == $tag &&
$this->in_content[$ccount-1][1] == $this->depth) {
$this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2],0,-1) . "/>";
} else {
# else, just finalize the current element's content
$endtag = $this->ns_to_prefix($name);
array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>"));
}
}
array_shift($this->ns_contexts);
$this->depth--;
if($name == ($this->NS . ':entry')) {
array_push($this->feed->entries, $this->current);
$this->current = null;
}
$this->_p("end_element('$name')");
}
function start_ns($parser, $prefix, $uri) {
$this->_p("starting: " . $prefix . ":" . $uri);
array_push($this->ns_decls, array($prefix,$uri));
}
function end_ns($parser, $prefix) {
$this->_p("ending: #" . $prefix . "#");
}
function cdata($parser, $data) {
$this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#");
if(!empty($this->in_content)) {
array_push($this->in_content, $data);
}
}
function _default($parser, $data) {
# when does this gets called?
}
function ns_to_prefix($qname, $attr=false) {
# split 'http://www.w3.org/1999/xhtml:div' into ('http','//www.w3.org/1999/xhtml','div')
$components = split(":", $qname);
# grab the last one (e.g 'div')
$name = array_pop($components);
if(!empty($components)) {
# re-join back the namespace component
$ns = join(":",$components);
foreach($this->ns_contexts as $context) {
foreach($context as $mapping) {
if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
return array($mapping, "$mapping[0]:$name");
}
}
}
}
if($attr) {
return array(null, $name);
} else {
foreach($this->ns_contexts as $context) {
foreach($context as $mapping) {
if(strlen($mapping[0]) == 0) {
return array($mapping, $name);
}
}
}
}
}
function is_declared_content_ns($new_mapping) {
foreach($this->content_ns_contexts as $context) {
foreach($context as $mapping) {
if($new_mapping == $mapping) {
return true;
}
}
}
return false;
}
function xml_escape($string)
{
return str_replace(array('&','"',"'",'<','>'),
array('&amp;','&quot;','&apos;','&lt;','&gt;'),
$string );
}
}

View File

@ -0,0 +1,392 @@
<?php
/**
* Author Template functions for use in themes.
*
* These functions must be used within the WordPress Loop.
*
* @link http://codex.wordpress.org/Author_Templates
*
* @package WordPress
* @subpackage Template
*/
/**
* Retrieve the author of the current post.
*
* @since 1.5
* @uses $authordata The current author's DB object.
* @uses apply_filters() Calls 'the_author' hook on the author display name.
*
* @param string $deprecated Deprecated.
* @return string The author's display name.
*/
function get_the_author($deprecated = '') {
global $authordata;
if ( !empty( $deprecated ) )
_deprecated_argument( __FUNCTION__, '2.1' );
return apply_filters('the_author', is_object($authordata) ? $authordata->display_name : null);
}
/**
* Display the name of the author of the current post.
*
* The behavior of this function is based off of old functionality predating
* get_the_author(). This function is not deprecated, but is designed to echo
* the value from get_the_author() and as an result of any old theme that might
* still use the old behavior will also pass the value from get_the_author().
*
* The normal, expected behavior of this function is to echo the author and not
* return it. However, backwards compatibility has to be maintained.
*
* @since 0.71
* @see get_the_author()
* @link http://codex.wordpress.org/Template_Tags/the_author
*
* @param string $deprecated Deprecated.
* @param string $deprecated_echo Deprecated. Use get_the_author(). Echo the string or return it.
* @return string The author's display name, from get_the_author().
*/
function the_author( $deprecated = '', $deprecated_echo = true ) {
if ( !empty( $deprecated ) )
_deprecated_argument( __FUNCTION__, '2.1' );
if ( $deprecated_echo !== true )
_deprecated_argument( __FUNCTION__, '1.5', __('Use <code>get_the_author()</code> instead if you do not want the value echoed.') );
if ( $deprecated_echo )
echo get_the_author();
return get_the_author();
}
/**
* Retrieve the author who last edited the current post.
*
* @since 2.8
* @uses $post The current post's DB object.
* @uses get_post_meta() Retrieves the ID of the author who last edited the current post.
* @uses get_userdata() Retrieves the author's DB object.
* @uses apply_filters() Calls 'the_modified_author' hook on the author display name.
* @return string The author's display name.
*/
function get_the_modified_author() {
if ( $last_id = get_post_meta( get_post()->ID, '_edit_last', true) ) {
$last_user = get_userdata($last_id);
return apply_filters('the_modified_author', $last_user->display_name);
}
}
/**
* Display the name of the author who last edited the current post.
*
* @since 2.8
* @see get_the_author()
* @return string The author's display name, from get_the_modified_author().
*/
function the_modified_author() {
echo get_the_modified_author();
}
/**
* Retrieve the requested data of the author of the current post.
* @link http://codex.wordpress.org/Template_Tags/the_author_meta
* @since 2.8.0
* @uses $authordata The current author's DB object (if $user_id not specified).
* @param string $field selects the field of the users record.
* @param int $user_id Optional. User ID.
* @return string The author's field from the current author's DB object.
*/
function get_the_author_meta( $field = '', $user_id = false ) {
if ( ! $user_id ) {
global $authordata;
$user_id = isset( $authordata->ID ) ? $authordata->ID : 0;
} else {
$authordata = get_userdata( $user_id );
}
if ( in_array( $field, array( 'login', 'pass', 'nicename', 'email', 'url', 'registered', 'activation_key', 'status' ) ) )
$field = 'user_' . $field;
$value = isset( $authordata->$field ) ? $authordata->$field : '';
return apply_filters( 'get_the_author_' . $field, $value, $user_id );
}
/**
* Retrieve the requested data of the author of the current post.
* @link http://codex.wordpress.org/Template_Tags/the_author_meta
* @since 2.8.0
* @param string $field selects the field of the users record.
* @param int $user_id Optional. User ID.
* @echo string The author's field from the current author's DB object.
*/
function the_author_meta($field = '', $user_id = false) {
echo apply_filters('the_author_' . $field, get_the_author_meta($field, $user_id), $user_id);
}
/**
* Retrieve either author's link or author's name.
*
* If the author has a home page set, return an HTML link, otherwise just return the
* author's name.
*
* @uses get_the_author_meta()
* @uses get_the_author()
*/
function get_the_author_link() {
if ( get_the_author_meta('url') ) {
return '<a href="' . get_the_author_meta('url') . '" title="' . esc_attr( sprintf(__("Visit %s&#8217;s website"), get_the_author()) ) . '" rel="author external">' . get_the_author() . '</a>';
} else {
return get_the_author();
}
}
/**
* Display either author's link or author's name.
*
* If the author has a home page set, echo an HTML link, otherwise just echo the
* author's name.
*
* @link http://codex.wordpress.org/Template_Tags/the_author_link
* @since 2.1
* @uses get_the_author_link()
*/
function the_author_link() {
echo get_the_author_link();
}
/**
* Retrieve the number of posts by the author of the current post.
*
* @since 1.5
* @uses $post The current post in the Loop's DB object.
* @uses count_user_posts()
* @return int The number of posts by the author.
*/
function get_the_author_posts() {
return count_user_posts( get_post()->post_author );
}
/**
* Display the number of posts by the author of the current post.
*
* @link http://codex.wordpress.org/Template_Tags/the_author_posts
* @since 0.71
* @uses get_the_author_posts() Echoes returned value from function.
*/
function the_author_posts() {
echo get_the_author_posts();
}
/**
* Display an HTML link to the author page of the author of the current post.
*
* Does just echo get_author_posts_url() function, like the others do. The
* reason for this, is that another function is used to help in printing the
* link to the author's posts.
*
* @link http://codex.wordpress.org/Template_Tags/the_author_posts_link
* @since 1.2.0
* @uses $authordata The current author's DB object.
* @uses get_author_posts_url()
* @uses get_the_author()
* @param string $deprecated Deprecated.
*/
function the_author_posts_link($deprecated = '') {
if ( !empty( $deprecated ) )
_deprecated_argument( __FUNCTION__, '2.1' );
global $authordata;
if ( !is_object( $authordata ) )
return false;
$link = sprintf(
'<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
get_author_posts_url( $authordata->ID, $authordata->user_nicename ),
esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ),
get_the_author()
);
echo apply_filters( 'the_author_posts_link', $link );
}
/**
* Retrieve the URL to the author page for the user with the ID provided.
*
* @since 2.1.0
* @uses $wp_rewrite WP_Rewrite
* @return string The URL to the author's page.
*/
function get_author_posts_url($author_id, $author_nicename = '') {
global $wp_rewrite;
$auth_ID = (int) $author_id;
$link = $wp_rewrite->get_author_permastruct();
if ( empty($link) ) {
$file = home_url( '/' );
$link = $file . '?author=' . $auth_ID;
} else {
if ( '' == $author_nicename ) {
$user = get_userdata($author_id);
if ( !empty($user->user_nicename) )
$author_nicename = $user->user_nicename;
}
$link = str_replace('%author%', $author_nicename, $link);
$link = home_url( user_trailingslashit( $link ) );
}
$link = apply_filters('author_link', $link, $author_id, $author_nicename);
return $link;
}
/**
* List all the authors of the blog, with several options available.
*
* <ul>
* <li>optioncount (boolean) (false): Show the count in parenthesis next to the
* author's name.</li>
* <li>exclude_admin (boolean) (true): Exclude the 'admin' user that is
* installed bydefault.</li>
* <li>show_fullname (boolean) (false): Show their full names.</li>
* <li>hide_empty (boolean) (true): Don't show authors without any posts.</li>
* <li>feed (string) (''): If isn't empty, show links to author's feeds.</li>
* <li>feed_image (string) (''): If isn't empty, use this image to link to
* feeds.</li>
* <li>echo (boolean) (true): Set to false to return the output, instead of
* echoing.</li>
* <li>style (string) ('list'): Whether to display list of authors in list form
* or as a string.</li>
* <li>html (bool) (true): Whether to list the items in html form or plaintext.
* </li>
* </ul>
*
* @link http://codex.wordpress.org/Template_Tags/wp_list_authors
* @since 1.2.0
* @param array $args The argument array.
* @return null|string The output, if echo is set to false.
*/
function wp_list_authors($args = '') {
global $wpdb;
$defaults = array(
'orderby' => 'name', 'order' => 'ASC', 'number' => '',
'optioncount' => false, 'exclude_admin' => true,
'show_fullname' => false, 'hide_empty' => true,
'feed' => '', 'feed_image' => '', 'feed_type' => '', 'echo' => true,
'style' => 'list', 'html' => true
);
$args = wp_parse_args( $args, $defaults );
extract( $args, EXTR_SKIP );
$return = '';
$query_args = wp_array_slice_assoc( $args, array( 'orderby', 'order', 'number' ) );
$query_args['fields'] = 'ids';
$authors = get_users( $query_args );
$author_count = array();
foreach ( (array) $wpdb->get_results("SELECT DISTINCT post_author, COUNT(ID) AS count FROM $wpdb->posts WHERE post_type = 'post' AND " . get_private_posts_cap_sql( 'post' ) . " GROUP BY post_author") as $row )
$author_count[$row->post_author] = $row->count;
foreach ( $authors as $author_id ) {
$author = get_userdata( $author_id );
if ( $exclude_admin && 'admin' == $author->display_name )
continue;
$posts = isset( $author_count[$author->ID] ) ? $author_count[$author->ID] : 0;
if ( !$posts && $hide_empty )
continue;
$link = '';
if ( $show_fullname && $author->first_name && $author->last_name )
$name = "$author->first_name $author->last_name";
else
$name = $author->display_name;
if ( !$html ) {
$return .= $name . ', ';
continue; // No need to go further to process HTML.
}
if ( 'list' == $style ) {
$return .= '<li>';
}
$link = '<a href="' . get_author_posts_url( $author->ID, $author->user_nicename ) . '" title="' . esc_attr( sprintf(__("Posts by %s"), $author->display_name) ) . '">' . $name . '</a>';
if ( !empty( $feed_image ) || !empty( $feed ) ) {
$link .= ' ';
if ( empty( $feed_image ) ) {
$link .= '(';
}
$link .= '<a href="' . get_author_feed_link( $author->ID ) . '"';
$alt = $title = '';
if ( !empty( $feed ) ) {
$title = ' title="' . esc_attr( $feed ) . '"';
$alt = ' alt="' . esc_attr( $feed ) . '"';
$name = $feed;
$link .= $title;
}
$link .= '>';
if ( !empty( $feed_image ) )
$link .= '<img src="' . esc_url( $feed_image ) . '" style="border: none;"' . $alt . $title . ' />';
else
$link .= $name;
$link .= '</a>';
if ( empty( $feed_image ) )
$link .= ')';
}
if ( $optioncount )
$link .= ' ('. $posts . ')';
$return .= $link;
$return .= ( 'list' == $style ) ? '</li>' : ', ';
}
$return = rtrim($return, ', ');
if ( !$echo )
return $return;
echo $return;
}
/**
* Does this site have more than one author
*
* Checks to see if more than one author has published posts.
*
* @since 3.2.0
* @return bool Whether or not we have more than one author
*/
function is_multi_author() {
global $wpdb;
if ( false === ( $is_multi_author = wp_cache_get('is_multi_author', 'posts') ) ) {
$rows = (array) $wpdb->get_col("SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' LIMIT 2");
$is_multi_author = 1 < count( $rows ) ? 1 : 0;
wp_cache_set('is_multi_author', $is_multi_author, 'posts');
}
return apply_filters( 'is_multi_author', (bool) $is_multi_author );
}
/**
* Helper function to clear the cache for number of authors.
*
* @private
*/
function __clear_multi_author_cache() {
wp_cache_delete('is_multi_author', 'posts');
}
add_action('transition_post_status', '__clear_multi_author_cache');

View File

@ -0,0 +1,257 @@
<?php
/**
* Bookmark Template Functions for usage in Themes
*
* @package WordPress
* @subpackage Template
*/
/**
* The formatted output of a list of bookmarks.
*
* The $bookmarks array must contain bookmark objects and will be iterated over
* to retrieve the bookmark to be used in the output.
*
* The output is formatted as HTML with no way to change that format. However,
* what is between, before, and after can be changed. The link itself will be
* HTML.
*
* This function is used internally by wp_list_bookmarks() and should not be
* used by themes.
*
* The defaults for overwriting are:
* 'show_updated' - Default is 0 (integer). Will show the time of when the
* bookmark was last updated.
* 'show_description' - Default is 0 (integer). Whether to show the description
* of the bookmark.
* 'show_images' - Default is 1 (integer). Whether to show link image if
* available.
* 'show_name' - Default is 0 (integer). Whether to show link name if
* available.
* 'before' - Default is '<li>' (string). The html or text to prepend to each
* bookmarks.
* 'after' - Default is '</li>' (string). The html or text to append to each
* bookmarks.
* 'link_before' - Default is '' (string). The html or text to prepend to each
* bookmarks inside the <a> tag.
* 'link_after' - Default is '' (string). The html or text to append to each
* bookmarks inside the <a> tag.
* 'between' - Default is '\n' (string). The string for use in between the link,
* description, and image.
* 'show_rating' - Default is 0 (integer). Whether to show the link rating.
*
* @since 2.1.0
* @access private
*
* @param array $bookmarks List of bookmarks to traverse
* @param string|array $args Optional. Overwrite the defaults.
* @return string Formatted output in HTML
*/
function _walk_bookmarks($bookmarks, $args = '' ) {
$defaults = array(
'show_updated' => 0, 'show_description' => 0,
'show_images' => 1, 'show_name' => 0,
'before' => '<li>', 'after' => '</li>', 'between' => "\n",
'show_rating' => 0, 'link_before' => '', 'link_after' => ''
);
$r = wp_parse_args( $args, $defaults );
extract( $r, EXTR_SKIP );
$output = ''; // Blank string to start with.
foreach ( (array) $bookmarks as $bookmark ) {
if ( !isset($bookmark->recently_updated) )
$bookmark->recently_updated = false;
$output .= $before;
if ( $show_updated && $bookmark->recently_updated )
$output .= get_option('links_recently_updated_prepend');
$the_link = '#';
if ( !empty($bookmark->link_url) )
$the_link = esc_url($bookmark->link_url);
$desc = esc_attr(sanitize_bookmark_field('link_description', $bookmark->link_description, $bookmark->link_id, 'display'));
$name = esc_attr(sanitize_bookmark_field('link_name', $bookmark->link_name, $bookmark->link_id, 'display'));
$title = $desc;
if ( $show_updated )
if ( '00' != substr($bookmark->link_updated_f, 0, 2) ) {
$title .= ' (';
$title .= sprintf(__('Last updated: %s'), date(get_option('links_updated_date_format'), $bookmark->link_updated_f + (get_option('gmt_offset') * HOUR_IN_SECONDS)));
$title .= ')';
}
$alt = ' alt="' . $name . ( $show_description ? ' ' . $title : '' ) . '"';
if ( '' != $title )
$title = ' title="' . $title . '"';
$rel = $bookmark->link_rel;
if ( '' != $rel )
$rel = ' rel="' . esc_attr($rel) . '"';
$target = $bookmark->link_target;
if ( '' != $target )
$target = ' target="' . $target . '"';
$output .= '<a href="' . $the_link . '"' . $rel . $title . $target . '>';
$output .= $link_before;
if ( $bookmark->link_image != null && $show_images ) {
if ( strpos($bookmark->link_image, 'http') === 0 )
$output .= "<img src=\"$bookmark->link_image\" $alt $title />";
else // If it's a relative path
$output .= "<img src=\"" . get_option('siteurl') . "$bookmark->link_image\" $alt $title />";
if ( $show_name )
$output .= " $name";
} else {
$output .= $name;
}
$output .= $link_after;
$output .= '</a>';
if ( $show_updated && $bookmark->recently_updated )
$output .= get_option('links_recently_updated_append');
if ( $show_description && '' != $desc )
$output .= $between . $desc;
if ( $show_rating )
$output .= $between . sanitize_bookmark_field('link_rating', $bookmark->link_rating, $bookmark->link_id, 'display');
$output .= "$after\n";
} // end while
return $output;
}
/**
* Retrieve or echo all of the bookmarks.
*
* List of default arguments are as follows:
* 'orderby' - Default is 'name' (string). How to order the links by. String is
* based off of the bookmark scheme.
* 'order' - Default is 'ASC' (string). Either 'ASC' or 'DESC'. Orders in either
* ascending or descending order.
* 'limit' - Default is -1 (integer) or show all. The amount of bookmarks to
* display.
* 'category' - Default is empty string (string). Include the links in what
* category ID(s).
* 'category_name' - Default is empty string (string). Get links by category
* name.
* 'hide_invisible' - Default is 1 (integer). Whether to show (default) or hide
* links marked as 'invisible'.
* 'show_updated' - Default is 0 (integer). Will show the time of when the
* bookmark was last updated.
* 'echo' - Default is 1 (integer). Whether to echo (default) or return the
* formatted bookmarks.
* 'categorize' - Default is 1 (integer). Whether to show links listed by
* category (default) or show links in one column.
* 'show_description' - Default is 0 (integer). Whether to show the description
* of the bookmark.
*
* These options define how the Category name will appear before the category
* links are displayed, if 'categorize' is 1. If 'categorize' is 0, then it will
* display for only the 'title_li' string and only if 'title_li' is not empty.
* 'title_li' - Default is 'Bookmarks' (translatable string). What to show
* before the links appear.
* 'title_before' - Default is '<h2>' (string). The HTML or text to show before
* the 'title_li' string.
* 'title_after' - Default is '</h2>' (string). The HTML or text to show after
* the 'title_li' string.
* 'class' - Default is 'linkcat' (string). The CSS class to use for the
* 'title_li'.
*
* 'category_before' - Default is '<li id="%id" class="%class">'. String must
* contain '%id' and '%class' to get
* the id of the category and the 'class' argument. These are used for
* formatting in themes.
* Argument will be displayed before the 'title_before' argument.
* 'category_after' - Default is '</li>' (string). The HTML or text that will
* appear after the list of links.
*
* These are only used if 'categorize' is set to 1 or true.
* 'category_orderby' - Default is 'name'. How to order the bookmark category
* based on term scheme.
* 'category_order' - Default is 'ASC'. Set the order by either ASC (ascending)
* or DESC (descending).
*
* @see _walk_bookmarks() For other arguments that can be set in this function
* and passed to _walk_bookmarks().
* @see get_bookmarks() For other arguments that can be set in this function and
* passed to get_bookmarks().
* @link http://codex.wordpress.org/Template_Tags/wp_list_bookmarks
*
* @since 2.1.0
* @uses _walk_bookmarks() Used to iterate over all of the bookmarks and return
* the html
* @uses get_terms() Gets all of the categories that are for links.
*
* @param string|array $args Optional. Overwrite the defaults of the function
* @return string|null Will only return if echo option is set to not echo.
* Default is not return anything.
*/
function wp_list_bookmarks($args = '') {
$defaults = array(
'orderby' => 'name', 'order' => 'ASC',
'limit' => -1, 'category' => '', 'exclude_category' => '',
'category_name' => '', 'hide_invisible' => 1,
'show_updated' => 0, 'echo' => 1,
'categorize' => 1, 'title_li' => __('Bookmarks'),
'title_before' => '<h2>', 'title_after' => '</h2>',
'category_orderby' => 'name', 'category_order' => 'ASC',
'class' => 'linkcat', 'category_before' => '<li id="%id" class="%class">',
'category_after' => '</li>'
);
$r = wp_parse_args( $args, $defaults );
extract( $r, EXTR_SKIP );
$output = '';
if ( $categorize ) {
$cats = get_terms( 'link_category', array( 'name__like' => $category_name, 'include' => $category, 'exclude' => $exclude_category, 'orderby' => $category_orderby, 'order' => $category_order, 'hierarchical' => 0 ) );
if ( empty( $cats ) )
$categorize = false;
}
if ( $categorize ) {
// Split the bookmarks into ul's for each category
foreach ( (array) $cats as $cat ) {
$params = array_merge($r, array('category'=>$cat->term_id));
$bookmarks = get_bookmarks($params);
if ( empty($bookmarks) )
continue;
$output .= str_replace(array('%id', '%class'), array("linkcat-$cat->term_id", $class), $category_before);
$catname = apply_filters( "link_category", $cat->name );
$output .= "$title_before$catname$title_after\n\t<ul class='xoxo blogroll'>\n";
$output .= _walk_bookmarks($bookmarks, $r);
$output .= "\n\t</ul>\n$category_after\n";
}
} else {
//output one single list using title_li for the title
$bookmarks = get_bookmarks($r);
if ( !empty($bookmarks) ) {
if ( !empty( $title_li ) ){
$output .= str_replace(array('%id', '%class'), array("linkcat-$category", $class), $category_before);
$output .= "$title_before$title_li$title_after\n\t<ul class='xoxo blogroll'>\n";
$output .= _walk_bookmarks($bookmarks, $r);
$output .= "\n\t</ul>\n$category_after\n";
} else {
$output .= _walk_bookmarks($bookmarks, $r);
}
}
}
$output = apply_filters( 'wp_list_bookmarks', $output );
if ( !$echo )
return $output;
echo $output;
}

387
wp-includes/bookmark.php Normal file
View File

@ -0,0 +1,387 @@
<?php
/**
* Link/Bookmark API
*
* @package WordPress
* @subpackage Bookmark
*/
/**
* Retrieve Bookmark data
*
* @since 2.1.0
* @uses $wpdb Database Object
*
* @param mixed $bookmark
* @param string $output Optional. Either OBJECT, ARRAY_N, or ARRAY_A constant
* @param string $filter Optional, default is 'raw'.
* @return array|object Type returned depends on $output value.
*/
function get_bookmark($bookmark, $output = OBJECT, $filter = 'raw') {
global $wpdb;
if ( empty($bookmark) ) {
if ( isset($GLOBALS['link']) )
$_bookmark = & $GLOBALS['link'];
else
$_bookmark = null;
} elseif ( is_object($bookmark) ) {
wp_cache_add($bookmark->link_id, $bookmark, 'bookmark');
$_bookmark = $bookmark;
} else {
if ( isset($GLOBALS['link']) && ($GLOBALS['link']->link_id == $bookmark) ) {
$_bookmark = & $GLOBALS['link'];
} elseif ( ! $_bookmark = wp_cache_get($bookmark, 'bookmark') ) {
$_bookmark = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->links WHERE link_id = %d LIMIT 1", $bookmark));
if ( $_bookmark ) {
$_bookmark->link_category = array_unique( wp_get_object_terms( $_bookmark->link_id, 'link_category', array( 'fields' => 'ids' ) ) );
wp_cache_add( $_bookmark->link_id, $_bookmark, 'bookmark' );
}
}
}
if ( ! $_bookmark )
return $_bookmark;
$_bookmark = sanitize_bookmark($_bookmark, $filter);
if ( $output == OBJECT ) {
return $_bookmark;
} elseif ( $output == ARRAY_A ) {
return get_object_vars($_bookmark);
} elseif ( $output == ARRAY_N ) {
return array_values(get_object_vars($_bookmark));
} else {
return $_bookmark;
}
}
/**
* Retrieve single bookmark data item or field.
*
* @since 2.3.0
* @uses get_bookmark() Gets bookmark object using $bookmark as ID
* @uses sanitize_bookmark_field() Sanitizes Bookmark field based on $context.
*
* @param string $field The name of the data field to return
* @param int $bookmark The bookmark ID to get field
* @param string $context Optional. The context of how the field will be used.
* @return string
*/
function get_bookmark_field( $field, $bookmark, $context = 'display' ) {
$bookmark = (int) $bookmark;
$bookmark = get_bookmark( $bookmark );
if ( is_wp_error($bookmark) )
return $bookmark;
if ( !is_object($bookmark) )
return '';
if ( !isset($bookmark->$field) )
return '';
return sanitize_bookmark_field($field, $bookmark->$field, $bookmark->link_id, $context);
}
/**
* Retrieves the list of bookmarks
*
* Attempts to retrieve from the cache first based on MD5 hash of arguments. If
* that fails, then the query will be built from the arguments and executed. The
* results will be stored to the cache.
*
* List of default arguments are as follows:
* 'orderby' - Default is 'name' (string). How to order the links by. String is
* based off of the bookmark scheme.
* 'order' - Default is 'ASC' (string). Either 'ASC' or 'DESC'. Orders in either
* ascending or descending order.
* 'limit' - Default is -1 (integer) or show all. The amount of bookmarks to
* display.
* 'category' - Default is empty string (string). Include the links in what
* category ID(s).
* 'category_name' - Default is empty string (string). Get links by category
* name.
* 'hide_invisible' - Default is 1 (integer). Whether to show (default) or hide
* links marked as 'invisible'.
* 'show_updated' - Default is 0 (integer). Will show the time of when the
* bookmark was last updated.
* 'include' - Default is empty string (string). Include bookmark ID(s)
* separated by commas.
* 'exclude' - Default is empty string (string). Exclude bookmark ID(s)
* separated by commas.
*
* @since 2.1.0
* @uses $wpdb Database Object
* @link http://codex.wordpress.org/Template_Tags/get_bookmarks
*
* @param string|array $args List of arguments to overwrite the defaults
* @return array List of bookmark row objects
*/
function get_bookmarks($args = '') {
global $wpdb;
$defaults = array(
'orderby' => 'name', 'order' => 'ASC',
'limit' => -1, 'category' => '',
'category_name' => '', 'hide_invisible' => 1,
'show_updated' => 0, 'include' => '',
'exclude' => '', 'search' => ''
);
$r = wp_parse_args( $args, $defaults );
extract( $r, EXTR_SKIP );
$cache = array();
$key = md5( serialize( $r ) );
if ( $cache = wp_cache_get( 'get_bookmarks', 'bookmark' ) ) {
if ( is_array($cache) && isset( $cache[ $key ] ) )
return apply_filters('get_bookmarks', $cache[ $key ], $r );
}
if ( !is_array($cache) )
$cache = array();
$inclusions = '';
if ( !empty($include) ) {
$exclude = ''; //ignore exclude, category, and category_name params if using include
$category = '';
$category_name = '';
$inclinks = preg_split('/[\s,]+/',$include);
if ( count($inclinks) ) {
foreach ( $inclinks as $inclink ) {
if (empty($inclusions))
$inclusions = ' AND ( link_id = ' . intval($inclink) . ' ';
else
$inclusions .= ' OR link_id = ' . intval($inclink) . ' ';
}
}
}
if (!empty($inclusions))
$inclusions .= ')';
$exclusions = '';
if ( !empty($exclude) ) {
$exlinks = preg_split('/[\s,]+/',$exclude);
if ( count($exlinks) ) {
foreach ( $exlinks as $exlink ) {
if (empty($exclusions))
$exclusions = ' AND ( link_id <> ' . intval($exlink) . ' ';
else
$exclusions .= ' AND link_id <> ' . intval($exlink) . ' ';
}
}
}
if (!empty($exclusions))
$exclusions .= ')';
if ( !empty($category_name) ) {
if ( $category = get_term_by('name', $category_name, 'link_category') ) {
$category = $category->term_id;
} else {
$cache[ $key ] = array();
wp_cache_set( 'get_bookmarks', $cache, 'bookmark' );
return apply_filters( 'get_bookmarks', array(), $r );
}
}
if ( ! empty($search) ) {
$search = like_escape($search);
$search = " AND ( (link_url LIKE '%$search%') OR (link_name LIKE '%$search%') OR (link_description LIKE '%$search%') ) ";
}
$category_query = '';
$join = '';
if ( !empty($category) ) {
$incategories = preg_split('/[\s,]+/',$category);
if ( count($incategories) ) {
foreach ( $incategories as $incat ) {
if (empty($category_query))
$category_query = ' AND ( tt.term_id = ' . intval($incat) . ' ';
else
$category_query .= ' OR tt.term_id = ' . intval($incat) . ' ';
}
}
}
if (!empty($category_query)) {
$category_query .= ") AND taxonomy = 'link_category'";
$join = " INNER JOIN $wpdb->term_relationships AS tr ON ($wpdb->links.link_id = tr.object_id) INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_taxonomy_id = tr.term_taxonomy_id";
}
if ( $show_updated && get_option('links_recently_updated_time') ) {
$recently_updated_test = ", IF (DATE_ADD(link_updated, INTERVAL " . get_option('links_recently_updated_time') . " MINUTE) >= NOW(), 1,0) as recently_updated ";
} else {
$recently_updated_test = '';
}
$get_updated = ( $show_updated ) ? ', UNIX_TIMESTAMP(link_updated) AS link_updated_f ' : '';
$orderby = strtolower($orderby);
$length = '';
switch ( $orderby ) {
case 'length':
$length = ", CHAR_LENGTH(link_name) AS length";
break;
case 'rand':
$orderby = 'rand()';
break;
case 'link_id':
$orderby = "$wpdb->links.link_id";
break;
default:
$orderparams = array();
foreach ( explode(',', $orderby) as $ordparam ) {
$ordparam = trim($ordparam);
$keys = array( 'link_id', 'link_name', 'link_url', 'link_visible', 'link_rating', 'link_owner', 'link_updated', 'link_notes' );
if ( in_array( 'link_' . $ordparam, $keys ) )
$orderparams[] = 'link_' . $ordparam;
elseif ( in_array( $ordparam, $keys ) )
$orderparams[] = $ordparam;
}
$orderby = implode(',', $orderparams);
}
if ( empty( $orderby ) )
$orderby = 'link_name';
$order = strtoupper( $order );
if ( '' !== $order && !in_array( $order, array( 'ASC', 'DESC' ) ) )
$order = 'ASC';
$visible = '';
if ( $hide_invisible )
$visible = "AND link_visible = 'Y'";
$query = "SELECT * $length $recently_updated_test $get_updated FROM $wpdb->links $join WHERE 1=1 $visible $category_query";
$query .= " $exclusions $inclusions $search";
$query .= " ORDER BY $orderby $order";
if ($limit != -1)
$query .= " LIMIT $limit";
$results = $wpdb->get_results($query);
$cache[ $key ] = $results;
wp_cache_set( 'get_bookmarks', $cache, 'bookmark' );
return apply_filters('get_bookmarks', $results, $r);
}
/**
* Sanitizes all bookmark fields
*
* @since 2.3.0
*
* @param object|array $bookmark Bookmark row
* @param string $context Optional, default is 'display'. How to filter the
* fields
* @return object|array Same type as $bookmark but with fields sanitized.
*/
function sanitize_bookmark($bookmark, $context = 'display') {
$fields = array('link_id', 'link_url', 'link_name', 'link_image', 'link_target', 'link_category',
'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_updated',
'link_rel', 'link_notes', 'link_rss', );
if ( is_object($bookmark) ) {
$do_object = true;
$link_id = $bookmark->link_id;
} else {
$do_object = false;
$link_id = $bookmark['link_id'];
}
foreach ( $fields as $field ) {
if ( $do_object ) {
if ( isset($bookmark->$field) )
$bookmark->$field = sanitize_bookmark_field($field, $bookmark->$field, $link_id, $context);
} else {
if ( isset($bookmark[$field]) )
$bookmark[$field] = sanitize_bookmark_field($field, $bookmark[$field], $link_id, $context);
}
}
return $bookmark;
}
/**
* Sanitizes a bookmark field
*
* Sanitizes the bookmark fields based on what the field name is. If the field
* has a strict value set, then it will be tested for that, else a more generic
* filtering is applied. After the more strict filter is applied, if the
* $context is 'raw' then the value is immediately return.
*
* Hooks exist for the more generic cases. With the 'edit' context, the
* 'edit_$field' filter will be called and passed the $value and $bookmark_id
* respectively. With the 'db' context, the 'pre_$field' filter is called and
* passed the value. The 'display' context is the final context and has the
* $field has the filter name and is passed the $value, $bookmark_id, and
* $context respectively.
*
* @since 2.3.0
*
* @param string $field The bookmark field
* @param mixed $value The bookmark field value
* @param int $bookmark_id Bookmark ID
* @param string $context How to filter the field value. Either 'raw', 'edit',
* 'attribute', 'js', 'db', or 'display'
* @return mixed The filtered value
*/
function sanitize_bookmark_field($field, $value, $bookmark_id, $context) {
switch ( $field ) {
case 'link_id' : // ints
case 'link_rating' :
$value = (int) $value;
break;
case 'link_category' : // array( ints )
$value = array_map('absint', (array) $value);
// We return here so that the categories aren't filtered.
// The 'link_category' filter is for the name of a link category, not an array of a link's link categories
return $value;
break;
case 'link_visible' : // bool stored as Y|N
$value = preg_replace('/[^YNyn]/', '', $value);
break;
case 'link_target' : // "enum"
$targets = array('_top', '_blank');
if ( ! in_array($value, $targets) )
$value = '';
break;
}
if ( 'raw' == $context )
return $value;
if ( 'edit' == $context ) {
$value = apply_filters("edit_$field", $value, $bookmark_id);
if ( 'link_notes' == $field ) {
$value = esc_html( $value ); // textarea_escaped
} else {
$value = esc_attr($value);
}
} else if ( 'db' == $context ) {
$value = apply_filters("pre_$field", $value);
} else {
// Use display filters by default.
$value = apply_filters($field, $value, $bookmark_id, $context);
if ( 'attribute' == $context )
$value = esc_attr($value);
else if ( 'js' == $context )
$value = esc_js($value);
}
return $value;
}
/**
* Deletes bookmark cache
*
* @since 2.7.0
* @uses wp_cache_delete() Deletes the contents of 'get_bookmarks'
*/
function clean_bookmark_cache( $bookmark_id ) {
wp_cache_delete( $bookmark_id, 'bookmark' );
wp_cache_delete( 'get_bookmarks', 'bookmark' );
clean_object_term_cache( $bookmark_id, 'link');
}

653
wp-includes/cache.php Normal file
View File

@ -0,0 +1,653 @@
<?php
/**
* Object Cache API
*
* @link http://codex.wordpress.org/Function_Reference/WP_Cache
*
* @package WordPress
* @subpackage Cache
*/
/**
* Adds data to the cache, if the cache key doesn't already exist.
*
* @since 2.0.0
* @uses $wp_object_cache Object Cache Class
* @see WP_Object_Cache::add()
*
* @param int|string $key The cache key to use for retrieval later
* @param mixed $data The data to add to the cache store
* @param string $group The group to add the cache to
* @param int $expire When the cache data should be expired
* @return unknown
*/
function wp_cache_add($key, $data, $group = '', $expire = 0) {
global $wp_object_cache;
return $wp_object_cache->add($key, $data, $group, $expire);
}
/**
* Closes the cache.
*
* This function has ceased to do anything since WordPress 2.5. The
* functionality was removed along with the rest of the persistent cache. This
* does not mean that plugins can't implement this function when they need to
* make sure that the cache is cleaned up after WordPress no longer needs it.
*
* @since 2.0.0
*
* @return bool Always returns True
*/
function wp_cache_close() {
return true;
}
/**
* Decrement numeric cache item's value
*
* @since 3.3.0
* @uses $wp_object_cache Object Cache Class
* @see WP_Object_Cache::decr()
*
* @param int|string $key The cache key to increment
* @param int $offset The amount by which to decrement the item's value. Default is 1.
* @param string $group The group the key is in.
* @return false|int False on failure, the item's new value on success.
*/
function wp_cache_decr( $key, $offset = 1, $group = '' ) {
global $wp_object_cache;
return $wp_object_cache->decr( $key, $offset, $group );
}
/**
* Removes the cache contents matching key and group.
*
* @since 2.0.0
* @uses $wp_object_cache Object Cache Class
* @see WP_Object_Cache::delete()
*
* @param int|string $key What the contents in the cache are called
* @param string $group Where the cache contents are grouped
* @return bool True on successful removal, false on failure
*/
function wp_cache_delete($key, $group = '') {
global $wp_object_cache;
return $wp_object_cache->delete($key, $group);
}
/**
* Removes all cache items.
*
* @since 2.0.0
* @uses $wp_object_cache Object Cache Class
* @see WP_Object_Cache::flush()
*
* @return bool Always returns true
*/
function wp_cache_flush() {
global $wp_object_cache;
return $wp_object_cache->flush();
}
/**
* Retrieves the cache contents from the cache by key and group.
*
* @since 2.0.0
* @uses $wp_object_cache Object Cache Class
* @see WP_Object_Cache::get()
*
* @param int|string $key What the contents in the cache are called
* @param string $group Where the cache contents are grouped
* @param bool $force Whether to force an update of the local cache from the persistent cache (default is false)
* @param &bool $found Whether key was found in the cache. Disambiguates a return of false, a storable value.
* @return bool|mixed False on failure to retrieve contents or the cache
* contents on success
*/
function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
global $wp_object_cache;
return $wp_object_cache->get( $key, $group, $force, $found );
}
/**
* Increment numeric cache item's value
*
* @since 3.3.0
* @uses $wp_object_cache Object Cache Class
* @see WP_Object_Cache::incr()
*
* @param int|string $key The cache key to increment
* @param int $offset The amount by which to increment the item's value. Default is 1.
* @param string $group The group the key is in.
* @return false|int False on failure, the item's new value on success.
*/
function wp_cache_incr( $key, $offset = 1, $group = '' ) {
global $wp_object_cache;
return $wp_object_cache->incr( $key, $offset, $group );
}
/**
* Sets up Object Cache Global and assigns it.
*
* @since 2.0.0
* @global WP_Object_Cache $wp_object_cache WordPress Object Cache
*/
function wp_cache_init() {
$GLOBALS['wp_object_cache'] = new WP_Object_Cache();
}
/**
* Replaces the contents of the cache with new data.
*
* @since 2.0.0
* @uses $wp_object_cache Object Cache Class
* @see WP_Object_Cache::replace()
*
* @param int|string $key What to call the contents in the cache
* @param mixed $data The contents to store in the cache
* @param string $group Where to group the cache contents
* @param int $expire When to expire the cache contents
* @return bool False if cache key and group already exist, true on success
*/
function wp_cache_replace($key, $data, $group = '', $expire = 0) {
global $wp_object_cache;
return $wp_object_cache->replace($key, $data, $group, $expire);
}
/**
* Saves the data to the cache.
*
* @since 2.0
* @uses $wp_object_cache Object Cache Class
* @see WP_Object_Cache::set()
*
* @param int|string $key What to call the contents in the cache
* @param mixed $data The contents to store in the cache
* @param string $group Where to group the cache contents
* @param int $expire When to expire the cache contents
* @return bool False if cache key and group already exist, true on success
*/
function wp_cache_set($key, $data, $group = '', $expire = 0) {
global $wp_object_cache;
return $wp_object_cache->set($key, $data, $group, $expire);
}
/**
* Switch the interal blog id.
*
* This changes the blog id used to create keys in blog specific groups.
*
* @since 3.5.0
*
* @param int $blog_id Blog ID
*/
function wp_cache_switch_to_blog( $blog_id ) {
global $wp_object_cache;
return $wp_object_cache->switch_to_blog( $blog_id );
}
/**
* Adds a group or set of groups to the list of global groups.
*
* @since 2.6.0
*
* @param string|array $groups A group or an array of groups to add
*/
function wp_cache_add_global_groups( $groups ) {
global $wp_object_cache;
return $wp_object_cache->add_global_groups( $groups );
}
/**
* Adds a group or set of groups to the list of non-persistent groups.
*
* @since 2.6.0
*
* @param string|array $groups A group or an array of groups to add
*/
function wp_cache_add_non_persistent_groups( $groups ) {
// Default cache doesn't persist so nothing to do here.
return;
}
/**
* Reset internal cache keys and structures. If the cache backend uses global
* blog or site IDs as part of its cache keys, this function instructs the
* backend to reset those keys and perform any cleanup since blog or site IDs
* have changed since cache init.
*
* This function is deprecated. Use wp_cache_switch_to_blog() instead of this
* function when preparing the cache for a blog switch. For clearing the cache
* during unit tests, consider using wp_cache_init(). wp_cache_init() is not
* recommended outside of unit tests as the performance penality for using it is
* high.
*
* @since 2.6.0
* @deprecated 3.5.0
*/
function wp_cache_reset() {
_deprecated_function( __FUNCTION__, '3.5' );
global $wp_object_cache;
return $wp_object_cache->reset();
}
/**
* WordPress Object Cache
*
* The WordPress Object Cache is used to save on trips to the database. The
* Object Cache stores all of the cache data to memory and makes the cache
* contents available by using a key, which is used to name and later retrieve
* the cache contents.
*
* The Object Cache can be replaced by other caching mechanisms by placing files
* in the wp-content folder which is looked at in wp-settings. If that file
* exists, then this file will not be included.
*
* @package WordPress
* @subpackage Cache
* @since 2.0
*/
class WP_Object_Cache {
/**
* Holds the cached objects
*
* @var array
* @access private
* @since 2.0.0
*/
var $cache = array ();
/**
* The amount of times the cache data was already stored in the cache.
*
* @since 2.5.0
* @access private
* @var int
*/
var $cache_hits = 0;
/**
* Amount of times the cache did not have the request in cache
*
* @var int
* @access public
* @since 2.0.0
*/
var $cache_misses = 0;
/**
* List of global groups
*
* @var array
* @access protected
* @since 3.0.0
*/
var $global_groups = array();
/**
* The blog prefix to prepend to keys in non-global groups.
*
* @var int
* @access private
* @since 3.5.0
*/
var $blog_prefix;
/**
* Adds data to the cache if it doesn't already exist.
*
* @uses WP_Object_Cache::_exists Checks to see if the cache already has data.
* @uses WP_Object_Cache::set Sets the data after the checking the cache
* contents existence.
*
* @since 2.0.0
*
* @param int|string $key What to call the contents in the cache
* @param mixed $data The contents to store in the cache
* @param string $group Where to group the cache contents
* @param int $expire When to expire the cache contents
* @return bool False if cache key and group already exist, true on success
*/
function add( $key, $data, $group = 'default', $expire = '' ) {
if ( wp_suspend_cache_addition() )
return false;
if ( empty( $group ) )
$group = 'default';
$id = $key;
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
$id = $this->blog_prefix . $key;
if ( $this->_exists( $id, $group ) )
return false;
return $this->set($key, $data, $group, $expire);
}
/**
* Sets the list of global groups.
*
* @since 3.0.0
*
* @param array $groups List of groups that are global.
*/
function add_global_groups( $groups ) {
$groups = (array) $groups;
$groups = array_fill_keys( $groups, true );
$this->global_groups = array_merge( $this->global_groups, $groups );
}
/**
* Decrement numeric cache item's value
*
* @since 3.3.0
*
* @param int|string $key The cache key to increment
* @param int $offset The amount by which to decrement the item's value. Default is 1.
* @param string $group The group the key is in.
* @return false|int False on failure, the item's new value on success.
*/
function decr( $key, $offset = 1, $group = 'default' ) {
if ( empty( $group ) )
$group = 'default';
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
$key = $this->blog_prefix . $key;
if ( ! $this->_exists( $key, $group ) )
return false;
if ( ! is_numeric( $this->cache[ $group ][ $key ] ) )
$this->cache[ $group ][ $key ] = 0;
$offset = (int) $offset;
$this->cache[ $group ][ $key ] -= $offset;
if ( $this->cache[ $group ][ $key ] < 0 )
$this->cache[ $group ][ $key ] = 0;
return $this->cache[ $group ][ $key ];
}
/**
* Remove the contents of the cache key in the group
*
* If the cache key does not exist in the group and $force parameter is set
* to false, then nothing will happen. The $force parameter is set to false
* by default.
*
* @since 2.0.0
*
* @param int|string $key What the contents in the cache are called
* @param string $group Where the cache contents are grouped
* @param bool $force Optional. Whether to force the unsetting of the cache
* key in the group
* @return bool False if the contents weren't deleted and true on success
*/
function delete($key, $group = 'default', $force = false) {
if ( empty( $group ) )
$group = 'default';
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
$key = $this->blog_prefix . $key;
if ( ! $force && ! $this->_exists( $key, $group ) )
return false;
unset( $this->cache[$group][$key] );
return true;
}
/**
* Clears the object cache of all data
*
* @since 2.0.0
*
* @return bool Always returns true
*/
function flush() {
$this->cache = array ();
return true;
}
/**
* Retrieves the cache contents, if it exists
*
* The contents will be first attempted to be retrieved by searching by the
* key in the cache group. If the cache is hit (success) then the contents
* are returned.
*
* On failure, the number of cache misses will be incremented.
*
* @since 2.0.0
*
* @param int|string $key What the contents in the cache are called
* @param string $group Where the cache contents are grouped
* @param string $force Whether to force a refetch rather than relying on the local cache (default is false)
* @return bool|mixed False on failure to retrieve contents or the cache
* contents on success
*/
function get( $key, $group = 'default', $force = false, &$found = null ) {
if ( empty( $group ) )
$group = 'default';
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
$key = $this->blog_prefix . $key;
if ( $this->_exists( $key, $group ) ) {
$found = true;
$this->cache_hits += 1;
if ( is_object($this->cache[$group][$key]) )
return clone $this->cache[$group][$key];
else
return $this->cache[$group][$key];
}
$found = false;
$this->cache_misses += 1;
return false;
}
/**
* Increment numeric cache item's value
*
* @since 3.3.0
*
* @param int|string $key The cache key to increment
* @param int $offset The amount by which to increment the item's value. Default is 1.
* @param string $group The group the key is in.
* @return false|int False on failure, the item's new value on success.
*/
function incr( $key, $offset = 1, $group = 'default' ) {
if ( empty( $group ) )
$group = 'default';
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
$key = $this->blog_prefix . $key;
if ( ! $this->_exists( $key, $group ) )
return false;
if ( ! is_numeric( $this->cache[ $group ][ $key ] ) )
$this->cache[ $group ][ $key ] = 0;
$offset = (int) $offset;
$this->cache[ $group ][ $key ] += $offset;
if ( $this->cache[ $group ][ $key ] < 0 )
$this->cache[ $group ][ $key ] = 0;
return $this->cache[ $group ][ $key ];
}
/**
* Replace the contents in the cache, if contents already exist
*
* @since 2.0.0
* @see WP_Object_Cache::set()
*
* @param int|string $key What to call the contents in the cache
* @param mixed $data The contents to store in the cache
* @param string $group Where to group the cache contents
* @param int $expire When to expire the cache contents
* @return bool False if not exists, true if contents were replaced
*/
function replace( $key, $data, $group = 'default', $expire = '' ) {
if ( empty( $group ) )
$group = 'default';
$id = $key;
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
$id = $this->blog_prefix . $key;
if ( ! $this->_exists( $id, $group ) )
return false;
return $this->set( $key, $data, $group, $expire );
}
/**
* Reset keys
*
* @since 3.0.0
* @deprecated 3.5.0
*/
function reset() {
_deprecated_function( __FUNCTION__, '3.5', 'switch_to_blog()' );
// Clear out non-global caches since the blog ID has changed.
foreach ( array_keys( $this->cache ) as $group ) {
if ( ! isset( $this->global_groups[ $group ] ) )
unset( $this->cache[ $group ] );
}
}
/**
* Sets the data contents into the cache
*
* The cache contents is grouped by the $group parameter followed by the
* $key. This allows for duplicate ids in unique groups. Therefore, naming of
* the group should be used with care and should follow normal function
* naming guidelines outside of core WordPress usage.
*
* The $expire parameter is not used, because the cache will automatically
* expire for each time a page is accessed and PHP finishes. The method is
* more for cache plugins which use files.
*
* @since 2.0.0
*
* @param int|string $key What to call the contents in the cache
* @param mixed $data The contents to store in the cache
* @param string $group Where to group the cache contents
* @param int $expire Not Used
* @return bool Always returns true
*/
function set($key, $data, $group = 'default', $expire = '') {
if ( empty( $group ) )
$group = 'default';
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
$key = $this->blog_prefix . $key;
if ( is_object( $data ) )
$data = clone $data;
$this->cache[$group][$key] = $data;
return true;
}
/**
* Echoes the stats of the caching.
*
* Gives the cache hits, and cache misses. Also prints every cached group,
* key and the data.
*
* @since 2.0.0
*/
function stats() {
echo "<p>";
echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
echo "</p>";
echo '<ul>';
foreach ($this->cache as $group => $cache) {
echo "<li><strong>Group:</strong> $group - ( " . number_format( strlen( serialize( $cache ) ) / 1024, 2 ) . 'k )</li>';
}
echo '</ul>';
}
/**
* Switch the interal blog id.
*
* This changes the blog id used to create keys in blog specific groups.
*
* @since 3.5.0
*
* @param int $blog_id Blog ID
*/
function switch_to_blog( $blog_id ) {
$blog_id = (int) $blog_id;
$this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
}
/**
* Utility function to determine whether a key exists in the cache.
*
* @since 3.4.0
*
* @access protected
*/
protected function _exists( $key, $group ) {
return isset( $this->cache[ $group ] ) && ( isset( $this->cache[ $group ][ $key ] ) || array_key_exists( $key, $this->cache[ $group ] ) );
}
/**
* Sets up object properties; PHP 5 style constructor
*
* @since 2.0.8
* @return null|WP_Object_Cache If cache is disabled, returns null.
*/
function __construct() {
global $blog_id;
$this->multisite = is_multisite();
$this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
/**
* @todo This should be moved to the PHP4 style constructor, PHP5
* already calls __destruct()
*/
register_shutdown_function( array( $this, '__destruct' ) );
}
/**
* Will save the object cache before object is completely destroyed.
*
* Called upon object destruction, which should be when PHP ends.
*
* @since 2.0.8
*
* @return bool True value. Won't be used by PHP
*/
function __destruct() {
return true;
}
}

536
wp-includes/canonical.php Normal file
View File

@ -0,0 +1,536 @@
<?php
/**
* Canonical API to handle WordPress Redirecting
*
* Based on "Permalink Redirect" from Scott Yang and "Enforce www. Preference"
* by Mark Jaquith
*
* @package WordPress
* @since 2.3.0
*/
/**
* Redirects incoming links to the proper URL based on the site url.
*
* Search engines consider www.somedomain.com and somedomain.com to be two
* different URLs when they both go to the same location. This SEO enhancement
* prevents penalty for duplicate content by redirecting all incoming links to
* one or the other.
*
* Prevents redirection for feeds, trackbacks, searches, comment popup, and
* admin URLs. Does not redirect on non-pretty-permalink-supporting IIS 7,
* page/post previews, WP admin, Trackbacks, robots.txt, searches, or on POST
* requests.
*
* Will also attempt to find the correct link when a user enters a URL that does
* not exist based on exact WordPress query. Will instead try to parse the URL
* or query in an attempt to figure the correct page to go to.
*
* @since 2.3.0
* @uses $wp_rewrite
* @uses $is_IIS
*
* @param string $requested_url Optional. The URL that was requested, used to
* figure if redirect is needed.
* @param bool $do_redirect Optional. Redirect to the new URL.
* @return null|false|string Null, if redirect not needed. False, if redirect
* not needed or the string of the URL
*/
function redirect_canonical( $requested_url = null, $do_redirect = true ) {
global $wp_rewrite, $is_IIS, $wp_query, $wpdb;
if ( is_trackback() || is_search() || is_comments_popup() || is_admin() || !empty($_POST) || is_preview() || is_robots() || ( $is_IIS && !iis7_supports_permalinks() ) )
return;
if ( !$requested_url ) {
// build the URL in the address bar
$requested_url = is_ssl() ? 'https://' : 'http://';
$requested_url .= $_SERVER['HTTP_HOST'];
$requested_url .= $_SERVER['REQUEST_URI'];
}
$original = @parse_url($requested_url);
if ( false === $original )
return;
// Some PHP setups turn requests for / into /index.php in REQUEST_URI
// See: http://trac.wordpress.org/ticket/5017
// See: http://trac.wordpress.org/ticket/7173
// Disabled, for now:
// $original['path'] = preg_replace('|/index\.php$|', '/', $original['path']);
$redirect = $original;
$redirect_url = false;
// Notice fixing
if ( !isset($redirect['path']) )
$redirect['path'] = '';
if ( !isset($redirect['query']) )
$redirect['query'] = '';
if ( is_feed() && ( $id = get_query_var( 'p' ) ) ) {
if ( $redirect_url = get_post_comments_feed_link( $id, get_query_var( 'feed' ) ) ) {
$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type', 'feed'), $redirect_url );
$redirect['path'] = parse_url( $redirect_url, PHP_URL_PATH );
}
}
if ( is_singular() && 1 > $wp_query->post_count && ($id = get_query_var('p')) ) {
$vars = $wpdb->get_results( $wpdb->prepare("SELECT post_type, post_parent FROM $wpdb->posts WHERE ID = %d", $id) );
if ( isset($vars[0]) && $vars = $vars[0] ) {
if ( 'revision' == $vars->post_type && $vars->post_parent > 0 )
$id = $vars->post_parent;
if ( $redirect_url = get_permalink($id) )
$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
}
}
// These tests give us a WP-generated permalink
if ( is_404() ) {
// Redirect ?page_id, ?p=, ?attachment_id= to their respective url's
$id = max( get_query_var('p'), get_query_var('page_id'), get_query_var('attachment_id') );
if ( $id && $redirect_post = get_post($id) ) {
$post_type_obj = get_post_type_object($redirect_post->post_type);
if ( $post_type_obj->public ) {
$redirect_url = get_permalink($redirect_post);
$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
}
}
if ( ! $redirect_url ) {
if ( $redirect_url = redirect_guess_404_permalink() ) {
$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'page', 'feed', 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
}
}
} elseif ( is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ) {
// rewriting of old ?p=X, ?m=2004, ?m=200401, ?m=20040101
if ( is_attachment() && !empty($_GET['attachment_id']) && ! $redirect_url ) {
if ( $redirect_url = get_attachment_link(get_query_var('attachment_id')) )
$redirect['query'] = remove_query_arg('attachment_id', $redirect['query']);
} elseif ( is_single() && !empty($_GET['p']) && ! $redirect_url ) {
if ( $redirect_url = get_permalink(get_query_var('p')) )
$redirect['query'] = remove_query_arg(array('p', 'post_type'), $redirect['query']);
} elseif ( is_single() && !empty($_GET['name']) && ! $redirect_url ) {
if ( $redirect_url = get_permalink( $wp_query->get_queried_object_id() ) )
$redirect['query'] = remove_query_arg('name', $redirect['query']);
} elseif ( is_page() && !empty($_GET['page_id']) && ! $redirect_url ) {
if ( $redirect_url = get_permalink(get_query_var('page_id')) )
$redirect['query'] = remove_query_arg('page_id', $redirect['query']);
} elseif ( is_page() && !is_feed() && isset($wp_query->queried_object) && 'page' == get_option('show_on_front') && $wp_query->queried_object->ID == get_option('page_on_front') && ! $redirect_url ) {
$redirect_url = home_url('/');
} elseif ( is_home() && !empty($_GET['page_id']) && 'page' == get_option('show_on_front') && get_query_var('page_id') == get_option('page_for_posts') && ! $redirect_url ) {
if ( $redirect_url = get_permalink(get_option('page_for_posts')) )
$redirect['query'] = remove_query_arg('page_id', $redirect['query']);
} elseif ( !empty($_GET['m']) && ( is_year() || is_month() || is_day() ) ) {
$m = get_query_var('m');
switch ( strlen($m) ) {
case 4: // Yearly
$redirect_url = get_year_link($m);
break;
case 6: // Monthly
$redirect_url = get_month_link( substr($m, 0, 4), substr($m, 4, 2) );
break;
case 8: // Daily
$redirect_url = get_day_link(substr($m, 0, 4), substr($m, 4, 2), substr($m, 6, 2));
break;
}
if ( $redirect_url )
$redirect['query'] = remove_query_arg('m', $redirect['query']);
// now moving on to non ?m=X year/month/day links
} elseif ( is_day() && get_query_var('year') && get_query_var('monthnum') && !empty($_GET['day']) ) {
if ( $redirect_url = get_day_link(get_query_var('year'), get_query_var('monthnum'), get_query_var('day')) )
$redirect['query'] = remove_query_arg(array('year', 'monthnum', 'day'), $redirect['query']);
} elseif ( is_month() && get_query_var('year') && !empty($_GET['monthnum']) ) {
if ( $redirect_url = get_month_link(get_query_var('year'), get_query_var('monthnum')) )
$redirect['query'] = remove_query_arg(array('year', 'monthnum'), $redirect['query']);
} elseif ( is_year() && !empty($_GET['year']) ) {
if ( $redirect_url = get_year_link(get_query_var('year')) )
$redirect['query'] = remove_query_arg('year', $redirect['query']);
} elseif ( is_author() && !empty($_GET['author']) && preg_match( '|^[0-9]+$|', $_GET['author'] ) ) {
$author = get_userdata(get_query_var('author'));
if ( ( false !== $author ) && $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE $wpdb->posts.post_author = %d AND $wpdb->posts.post_status = 'publish' LIMIT 1", $author->ID ) ) ) {
if ( $redirect_url = get_author_posts_url($author->ID, $author->user_nicename) )
$redirect['query'] = remove_query_arg('author', $redirect['query']);
}
} elseif ( is_category() || is_tag() || is_tax() ) { // Terms (Tags/categories)
$term_count = 0;
foreach ( $wp_query->tax_query->queries as $tax_query )
$term_count += count( $tax_query['terms'] );
$obj = $wp_query->get_queried_object();
if ( $term_count <= 1 && !empty($obj->term_id) && ( $tax_url = get_term_link((int)$obj->term_id, $obj->taxonomy) ) && !is_wp_error($tax_url) ) {
if ( !empty($redirect['query']) ) {
// Strip taxonomy query vars off the url.
$qv_remove = array( 'term', 'taxonomy');
if ( is_category() ) {
$qv_remove[] = 'category_name';
$qv_remove[] = 'cat';
} elseif ( is_tag() ) {
$qv_remove[] = 'tag';
$qv_remove[] = 'tag_id';
} else { // Custom taxonomies will have a custom query var, remove those too:
$tax_obj = get_taxonomy( $obj->taxonomy );
if ( false !== $tax_obj->query_var )
$qv_remove[] = $tax_obj->query_var;
}
$rewrite_vars = array_diff( array_keys($wp_query->query), array_keys($_GET) );
if ( !array_diff($rewrite_vars, array_keys($_GET)) ) { // Check to see if all the Query vars are coming from the rewrite, none are set via $_GET
$redirect['query'] = remove_query_arg($qv_remove, $redirect['query']); //Remove all of the per-tax qv's
// Create the destination url for this taxonomy
$tax_url = parse_url($tax_url);
if ( ! empty($tax_url['query']) ) { // Taxonomy accessible via ?taxonomy=..&term=.. or any custom qv..
parse_str($tax_url['query'], $query_vars);
$redirect['query'] = add_query_arg($query_vars, $redirect['query']);
} else { // Taxonomy is accessible via a "pretty-URL"
$redirect['path'] = $tax_url['path'];
}
} else { // Some query vars are set via $_GET. Unset those from $_GET that exist via the rewrite
foreach ( $qv_remove as $_qv ) {
if ( isset($rewrite_vars[$_qv]) )
$redirect['query'] = remove_query_arg($_qv, $redirect['query']);
}
}
}
}
} elseif ( is_single() && strpos($wp_rewrite->permalink_structure, '%category%') !== false && $cat = get_query_var( 'category_name' ) ) {
$category = get_category_by_path( $cat );
$post_terms = wp_get_object_terms($wp_query->get_queried_object_id(), 'category', array('fields' => 'tt_ids'));
if ( (!$category || is_wp_error($category)) || ( !is_wp_error($post_terms) && !empty($post_terms) && !in_array($category->term_taxonomy_id, $post_terms) ) )
$redirect_url = get_permalink($wp_query->get_queried_object_id());
}
// Post Paging
if ( is_singular() && ! is_front_page() && get_query_var('page') ) {
if ( !$redirect_url )
$redirect_url = get_permalink( get_queried_object_id() );
$redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( get_query_var( 'page' ), 'single_paged' );
$redirect['query'] = remove_query_arg( 'page', $redirect['query'] );
}
// paging and feeds
if ( get_query_var('paged') || is_feed() || get_query_var('cpage') ) {
while ( preg_match( "#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", $redirect['path'] ) || preg_match( '#/(comments/?)?(feed|rss|rdf|atom|rss2)(/+)?$#', $redirect['path'] ) || preg_match( '#/comment-page-[0-9]+(/+)?$#', $redirect['path'] ) ) {
// Strip off paging and feed
$redirect['path'] = preg_replace("#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", '/', $redirect['path']); // strip off any existing paging
$redirect['path'] = preg_replace('#/(comments/?)?(feed|rss2?|rdf|atom)(/+|$)#', '/', $redirect['path']); // strip off feed endings
$redirect['path'] = preg_replace('#/comment-page-[0-9]+?(/+)?$#', '/', $redirect['path']); // strip off any existing comment paging
}
$addl_path = '';
if ( is_feed() && in_array( get_query_var('feed'), $wp_rewrite->feeds ) ) {
$addl_path = !empty( $addl_path ) ? trailingslashit($addl_path) : '';
if ( !is_singular() && get_query_var( 'withcomments' ) )
$addl_path .= 'comments/';
if ( ( 'rss' == get_default_feed() && 'feed' == get_query_var('feed') ) || 'rss' == get_query_var('feed') )
$addl_path .= user_trailingslashit( 'feed/' . ( ( get_default_feed() == 'rss2' ) ? '' : 'rss2' ), 'feed' );
else
$addl_path .= user_trailingslashit( 'feed/' . ( ( get_default_feed() == get_query_var('feed') || 'feed' == get_query_var('feed') ) ? '' : get_query_var('feed') ), 'feed' );
$redirect['query'] = remove_query_arg( 'feed', $redirect['query'] );
} elseif ( is_feed() && 'old' == get_query_var('feed') ) {
$old_feed_files = array(
'wp-atom.php' => 'atom',
'wp-commentsrss2.php' => 'comments_rss2',
'wp-feed.php' => get_default_feed(),
'wp-rdf.php' => 'rdf',
'wp-rss.php' => 'rss2',
'wp-rss2.php' => 'rss2',
);
if ( isset( $old_feed_files[ basename( $redirect['path'] ) ] ) ) {
$redirect_url = get_feed_link( $old_feed_files[ basename( $redirect['path'] ) ] );
wp_redirect( $redirect_url, 301 );
die();
}
}
if ( get_query_var('paged') > 0 ) {
$paged = get_query_var('paged');
$redirect['query'] = remove_query_arg( 'paged', $redirect['query'] );
if ( !is_feed() ) {
if ( $paged > 1 && !is_single() ) {
$addl_path = ( !empty( $addl_path ) ? trailingslashit($addl_path) : '' ) . user_trailingslashit("$wp_rewrite->pagination_base/$paged", 'paged');
} elseif ( !is_single() ) {
$addl_path = !empty( $addl_path ) ? trailingslashit($addl_path) : '';
}
} elseif ( $paged > 1 ) {
$redirect['query'] = add_query_arg( 'paged', $paged, $redirect['query'] );
}
}
if ( get_option('page_comments') && ( ( 'newest' == get_option('default_comments_page') && get_query_var('cpage') > 0 ) || ( 'newest' != get_option('default_comments_page') && get_query_var('cpage') > 1 ) ) ) {
$addl_path = ( !empty( $addl_path ) ? trailingslashit($addl_path) : '' ) . user_trailingslashit( 'comment-page-' . get_query_var('cpage'), 'commentpaged' );
$redirect['query'] = remove_query_arg( 'cpage', $redirect['query'] );
}
$redirect['path'] = user_trailingslashit( preg_replace('|/index.php/?$|', '/', $redirect['path']) ); // strip off trailing /index.php/
if ( !empty( $addl_path ) && $wp_rewrite->using_index_permalinks() && strpos($redirect['path'], '/index.php/') === false )
$redirect['path'] = trailingslashit($redirect['path']) . 'index.php/';
if ( !empty( $addl_path ) )
$redirect['path'] = trailingslashit($redirect['path']) . $addl_path;
$redirect_url = $redirect['scheme'] . '://' . $redirect['host'] . $redirect['path'];
}
if ( 'wp-register.php' == basename( $redirect['path'] ) ) {
if ( is_multisite() )
$redirect_url = apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) );
else
$redirect_url = site_url( 'wp-login.php?action=register' );
wp_redirect( $redirect_url, 301 );
die();
}
}
// tack on any additional query vars
$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
if ( $redirect_url && !empty($redirect['query']) ) {
parse_str( $redirect['query'], $_parsed_query );
$redirect = @parse_url($redirect_url);
if ( ! empty( $_parsed_query['name'] ) && ! empty( $redirect['query'] ) ) {
parse_str( $redirect['query'], $_parsed_redirect_query );
if ( empty( $_parsed_redirect_query['name'] ) )
unset( $_parsed_query['name'] );
}
$_parsed_query = rawurlencode_deep( $_parsed_query );
$redirect_url = add_query_arg( $_parsed_query, $redirect_url );
}
if ( $redirect_url )
$redirect = @parse_url($redirect_url);
// www.example.com vs example.com
$user_home = @parse_url(home_url());
if ( !empty($user_home['host']) )
$redirect['host'] = $user_home['host'];
if ( empty($user_home['path']) )
$user_home['path'] = '/';
// Handle ports
if ( !empty($user_home['port']) )
$redirect['port'] = $user_home['port'];
else
unset($redirect['port']);
// trailing /index.php
$redirect['path'] = preg_replace('|/index.php/*?$|', '/', $redirect['path']);
// Remove trailing spaces from the path
$redirect['path'] = preg_replace( '#(%20| )+$#', '', $redirect['path'] );
if ( !empty( $redirect['query'] ) ) {
// Remove trailing spaces from certain terminating query string args
$redirect['query'] = preg_replace( '#((p|page_id|cat|tag)=[^&]*?)(%20| )+$#', '$1', $redirect['query'] );
// Clean up empty query strings
$redirect['query'] = trim(preg_replace( '#(^|&)(p|page_id|cat|tag)=?(&|$)#', '&', $redirect['query']), '&');
// Redirect obsolete feeds
$redirect['query'] = preg_replace( '#(^|&)feed=rss(&|$)#', '$1feed=rss2$3', $redirect['query'] );
// Remove redundant leading ampersands
$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
}
// strip /index.php/ when we're not using PATHINFO permalinks
if ( !$wp_rewrite->using_index_permalinks() )
$redirect['path'] = str_replace('/index.php/', '/', $redirect['path']);
// trailing slashes
if ( is_object($wp_rewrite) && $wp_rewrite->using_permalinks() && !is_404() && (!is_front_page() || ( is_front_page() && (get_query_var('paged') > 1) ) ) ) {
$user_ts_type = '';
if ( get_query_var('paged') > 0 ) {
$user_ts_type = 'paged';
} else {
foreach ( array('single', 'category', 'page', 'day', 'month', 'year', 'home') as $type ) {
$func = 'is_' . $type;
if ( call_user_func($func) ) {
$user_ts_type = $type;
break;
}
}
}
$redirect['path'] = user_trailingslashit($redirect['path'], $user_ts_type);
} elseif ( is_front_page() ) {
$redirect['path'] = trailingslashit($redirect['path']);
}
// Strip multiple slashes out of the URL
if ( strpos($redirect['path'], '//') > -1 )
$redirect['path'] = preg_replace('|/+|', '/', $redirect['path']);
// Always trailing slash the Front Page URL
if ( trailingslashit( $redirect['path'] ) == trailingslashit( $user_home['path'] ) )
$redirect['path'] = trailingslashit($redirect['path']);
// Ignore differences in host capitalization, as this can lead to infinite redirects
// Only redirect no-www <=> yes-www
if ( strtolower($original['host']) == strtolower($redirect['host']) ||
( strtolower($original['host']) != 'www.' . strtolower($redirect['host']) && 'www.' . strtolower($original['host']) != strtolower($redirect['host']) ) )
$redirect['host'] = $original['host'];
$compare_original = array($original['host'], $original['path']);
if ( !empty( $original['port'] ) )
$compare_original[] = $original['port'];
if ( !empty( $original['query'] ) )
$compare_original[] = $original['query'];
$compare_redirect = array($redirect['host'], $redirect['path']);
if ( !empty( $redirect['port'] ) )
$compare_redirect[] = $redirect['port'];
if ( !empty( $redirect['query'] ) )
$compare_redirect[] = $redirect['query'];
if ( $compare_original !== $compare_redirect ) {
$redirect_url = $redirect['scheme'] . '://' . $redirect['host'];
if ( !empty($redirect['port']) )
$redirect_url .= ':' . $redirect['port'];
$redirect_url .= $redirect['path'];
if ( !empty($redirect['query']) )
$redirect_url .= '?' . $redirect['query'];
}
if ( !$redirect_url || $redirect_url == $requested_url )
return false;
// Hex encoded octets are case-insensitive.
if ( false !== strpos($requested_url, '%') ) {
if ( !function_exists('lowercase_octets') ) {
function lowercase_octets($matches) {
return strtolower( $matches[0] );
}
}
$requested_url = preg_replace_callback('|%[a-fA-F0-9][a-fA-F0-9]|', 'lowercase_octets', $requested_url);
}
// Note that you can use the "redirect_canonical" filter to cancel a canonical redirect for whatever reason by returning false
$redirect_url = apply_filters('redirect_canonical', $redirect_url, $requested_url);
if ( !$redirect_url || $redirect_url == $requested_url ) // yes, again -- in case the filter aborted the request
return false;
if ( $do_redirect ) {
// protect against chained redirects
if ( !redirect_canonical($redirect_url, false) ) {
wp_redirect($redirect_url, 301);
exit();
} else {
// Debug
// die("1: $redirect_url<br />2: " . redirect_canonical( $redirect_url, false ) );
return false;
}
} else {
return $redirect_url;
}
}
/**
* Removes arguments from a query string if they are not present in a URL
* DO NOT use this in plugin code.
*
* @since 3.4
* @access private
*
* @return string The altered query string
*/
function _remove_qs_args_if_not_in_url( $query_string, Array $args_to_check, $url ) {
$parsed_url = @parse_url( $url );
if ( ! empty( $parsed_url['query'] ) ) {
parse_str( $parsed_url['query'], $parsed_query );
foreach ( $args_to_check as $qv ) {
if ( !isset( $parsed_query[$qv] ) )
$query_string = remove_query_arg( $qv, $query_string );
}
} else {
$query_string = remove_query_arg( $args_to_check, $query_string );
}
return $query_string;
}
/**
* Attempts to guess the correct URL based on query vars
*
* @since 2.3.0
* @uses $wpdb
*
* @return bool|string The correct URL if one is found. False on failure.
*/
function redirect_guess_404_permalink() {
global $wpdb, $wp_rewrite;
if ( get_query_var('name') ) {
$where = $wpdb->prepare("post_name LIKE %s", like_escape( get_query_var('name') ) . '%');
// if any of post_type, year, monthnum, or day are set, use them to refine the query
if ( get_query_var('post_type') )
$where .= $wpdb->prepare(" AND post_type = %s", get_query_var('post_type'));
else
$where .= " AND post_type IN ('" . implode( "', '", get_post_types( array( 'public' => true ) ) ) . "')";
if ( get_query_var('year') )
$where .= $wpdb->prepare(" AND YEAR(post_date) = %d", get_query_var('year'));
if ( get_query_var('monthnum') )
$where .= $wpdb->prepare(" AND MONTH(post_date) = %d", get_query_var('monthnum'));
if ( get_query_var('day') )
$where .= $wpdb->prepare(" AND DAYOFMONTH(post_date) = %d", get_query_var('day'));
$post_id = $wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE $where AND post_status = 'publish'");
if ( ! $post_id )
return false;
if ( get_query_var( 'feed' ) )
return get_post_comments_feed_link( $post_id, get_query_var( 'feed' ) );
elseif ( get_query_var( 'page' ) )
return trailingslashit( get_permalink( $post_id ) ) . user_trailingslashit( get_query_var( 'page' ), 'single_paged' );
else
return get_permalink( $post_id );
}
return false;
}
add_action('template_redirect', 'redirect_canonical');
function wp_redirect_admin_locations() {
global $wp_rewrite;
if ( ! ( is_404() && $wp_rewrite->using_permalinks() ) )
return;
$admins = array(
home_url( 'wp-admin', 'relative' ),
home_url( 'dashboard', 'relative' ),
home_url( 'admin', 'relative' ),
site_url( 'dashboard', 'relative' ),
site_url( 'admin', 'relative' ),
);
if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $admins ) ) {
wp_redirect( admin_url() );
exit;
}
$logins = array(
home_url( 'wp-login.php', 'relative' ),
home_url( 'login', 'relative' ),
site_url( 'login', 'relative' ),
);
if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $logins ) ) {
wp_redirect( site_url( 'wp-login.php', 'login' ) );
exit;
}
}
add_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );

1468
wp-includes/capabilities.php Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

336
wp-includes/category.php Normal file
View File

@ -0,0 +1,336 @@
<?php
/**
* WordPress Category API
*
* @package WordPress
*/
/**
* Retrieves all category IDs.
*
* @since 2.0.0
* @link http://codex.wordpress.org/Function_Reference/get_all_category_ids
*
* @return object List of all of the category IDs.
*/
function get_all_category_ids() {
if ( ! $cat_ids = wp_cache_get( 'all_category_ids', 'category' ) ) {
$cat_ids = get_terms( 'category', array('fields' => 'ids', 'get' => 'all') );
wp_cache_add( 'all_category_ids', $cat_ids, 'category' );
}
return $cat_ids;
}
/**
* Retrieve list of category objects.
*
* If you change the type to 'link' in the arguments, then the link categories
* will be returned instead. Also all categories will be updated to be backwards
* compatible with pre-2.3 plugins and themes.
*
* @since 2.1.0
* @see get_terms() Type of arguments that can be changed.
* @link http://codex.wordpress.org/Function_Reference/get_categories
*
* @param string|array $args Optional. Change the defaults retrieving categories.
* @return array List of categories.
*/
function get_categories( $args = '' ) {
$defaults = array( 'taxonomy' => 'category' );
$args = wp_parse_args( $args, $defaults );
$taxonomy = apply_filters( 'get_categories_taxonomy', $args['taxonomy'], $args );
// Back compat
if ( isset($args['type']) && 'link' == $args['type'] ) {
_deprecated_argument( __FUNCTION__, '3.0', '' );
$taxonomy = $args['taxonomy'] = 'link_category';
}
$categories = (array) get_terms( $taxonomy, $args );
foreach ( array_keys( $categories ) as $k )
_make_cat_compat( $categories[$k] );
return $categories;
}
/**
* Retrieves category data given a category ID or category object.
*
* If you pass the $category parameter an object, which is assumed to be the
* category row object retrieved the database. It will cache the category data.
*
* If you pass $category an integer of the category ID, then that category will
* be retrieved from the database, if it isn't already cached, and pass it back.
*
* If you look at get_term(), then both types will be passed through several
* filters and finally sanitized based on the $filter parameter value.
*
* The category will converted to maintain backwards compatibility.
*
* @since 1.5.1
* @uses get_term() Used to get the category data from the taxonomy.
*
* @param int|object $category Category ID or Category row object
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
* @return mixed Category data in type defined by $output parameter.
*/
function get_category( $category, $output = OBJECT, $filter = 'raw' ) {
$category = get_term( $category, 'category', $output, $filter );
if ( is_wp_error( $category ) )
return $category;
_make_cat_compat( $category );
return $category;
}
/**
* Retrieve category based on URL containing the category slug.
*
* Breaks the $category_path parameter up to get the category slug.
*
* Tries to find the child path and will return it. If it doesn't find a
* match, then it will return the first category matching slug, if $full_match,
* is set to false. If it does not, then it will return null.
*
* It is also possible that it will return a WP_Error object on failure. Check
* for it when using this function.
*
* @since 2.1.0
*
* @param string $category_path URL containing category slugs.
* @param bool $full_match Optional. Whether full path should be matched.
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @return null|object|array Null on failure. Type is based on $output value.
*/
function get_category_by_path( $category_path, $full_match = true, $output = OBJECT ) {
$category_path = rawurlencode( urldecode( $category_path ) );
$category_path = str_replace( '%2F', '/', $category_path );
$category_path = str_replace( '%20', ' ', $category_path );
$category_paths = '/' . trim( $category_path, '/' );
$leaf_path = sanitize_title( basename( $category_paths ) );
$category_paths = explode( '/', $category_paths );
$full_path = '';
foreach ( (array) $category_paths as $pathdir )
$full_path .= ( $pathdir != '' ? '/' : '' ) . sanitize_title( $pathdir );
$categories = get_terms( 'category', array('get' => 'all', 'slug' => $leaf_path) );
if ( empty( $categories ) )
return null;
foreach ( $categories as $category ) {
$path = '/' . $leaf_path;
$curcategory = $category;
while ( ( $curcategory->parent != 0 ) && ( $curcategory->parent != $curcategory->term_id ) ) {
$curcategory = get_term( $curcategory->parent, 'category' );
if ( is_wp_error( $curcategory ) )
return $curcategory;
$path = '/' . $curcategory->slug . $path;
}
if ( $path == $full_path )
return get_category( $category->term_id, $output );
}
// If full matching is not required, return the first cat that matches the leaf.
if ( ! $full_match )
return get_category( $categories[0]->term_id, $output );
return null;
}
/**
* Retrieve category object by category slug.
*
* @since 2.3.0
*
* @param string $slug The category slug.
* @return object Category data object
*/
function get_category_by_slug( $slug ) {
$category = get_term_by( 'slug', $slug, 'category' );
if ( $category )
_make_cat_compat( $category );
return $category;
}
/**
* Retrieve the ID of a category from its name.
*
* @since 1.0.0
*
* @param string $cat_name Category name.
* @return int 0, if failure and ID of category on success.
*/
function get_cat_ID( $cat_name ) {
$cat = get_term_by( 'name', $cat_name, 'category' );
if ( $cat )
return $cat->term_id;
return 0;
}
/**
* Retrieve the name of a category from its ID.
*
* @since 1.0.0
*
* @param int $cat_id Category ID
* @return string Category name, or an empty string if category doesn't exist.
*/
function get_cat_name( $cat_id ) {
$cat_id = (int) $cat_id;
$category = get_category( $cat_id );
if ( ! $category || is_wp_error( $category ) )
return '';
return $category->name;
}
/**
* Check if a category is an ancestor of another category.
*
* You can use either an id or the category object for both parameters. If you
* use an integer the category will be retrieved.
*
* @since 2.1.0
*
* @param int|object $cat1 ID or object to check if this is the parent category.
* @param int|object $cat2 The child category.
* @return bool Whether $cat2 is child of $cat1
*/
function cat_is_ancestor_of( $cat1, $cat2 ) {
return term_is_ancestor_of( $cat1, $cat2, 'category' );
}
/**
* Sanitizes category data based on context.
*
* @since 2.3.0
* @uses sanitize_term() See this function for what context are supported.
*
* @param object|array $category Category data
* @param string $context Optional. Default is 'display'.
* @return object|array Same type as $category with sanitized data for safe use.
*/
function sanitize_category( $category, $context = 'display' ) {
return sanitize_term( $category, 'category', $context );
}
/**
* Sanitizes data in single category key field.
*
* @since 2.3.0
* @uses sanitize_term_field() See function for more details.
*
* @param string $field Category key to sanitize
* @param mixed $value Category value to sanitize
* @param int $cat_id Category ID
* @param string $context What filter to use, 'raw', 'display', etc.
* @return mixed Same type as $value after $value has been sanitized.
*/
function sanitize_category_field( $field, $value, $cat_id, $context ) {
return sanitize_term_field( $field, $value, $cat_id, 'category', $context );
}
/* Tags */
/**
* Retrieves all post tags.
*
* @since 2.3.0
* @see get_terms() For list of arguments to pass.
* @uses apply_filters() Calls 'get_tags' hook on array of tags and with $args.
*
* @param string|array $args Tag arguments to use when retrieving tags.
* @return array List of tags.
*/
function get_tags( $args = '' ) {
$tags = get_terms( 'post_tag', $args );
if ( empty( $tags ) ) {
$return = array();
return $return;
}
$tags = apply_filters( 'get_tags', $tags, $args );
return $tags;
}
/**
* Retrieve post tag by tag ID or tag object.
*
* If you pass the $tag parameter an object, which is assumed to be the tag row
* object retrieved the database. It will cache the tag data.
*
* If you pass $tag an integer of the tag ID, then that tag will
* be retrieved from the database, if it isn't already cached, and pass it back.
*
* If you look at get_term(), then both types will be passed through several
* filters and finally sanitized based on the $filter parameter value.
*
* @since 2.3.0
*
* @param int|object $tag
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
* @return object|array Return type based on $output value.
*/
function get_tag( $tag, $output = OBJECT, $filter = 'raw' ) {
return get_term( $tag, 'post_tag', $output, $filter );
}
/* Cache */
/**
* Remove the category cache data based on ID.
*
* @since 2.1.0
* @uses clean_term_cache() Clears the cache for the category based on ID
*
* @param int $id Category ID
*/
function clean_category_cache( $id ) {
clean_term_cache( $id, 'category' );
}
/**
* Update category structure to old pre 2.3 from new taxonomy structure.
*
* This function was added for the taxonomy support to update the new category
* structure with the old category one. This will maintain compatibility with
* plugins and themes which depend on the old key or property names.
*
* The parameter should only be passed a variable and not create the array or
* object inline to the parameter. The reason for this is that parameter is
* passed by reference and PHP will fail unless it has the variable.
*
* There is no return value, because everything is updated on the variable you
* pass to it. This is one of the features with using pass by reference in PHP.
*
* @since 2.3.0
* @access private
*
* @param array|object $category Category Row object or array
*/
function _make_cat_compat( &$category ) {
if ( is_object( $category ) ) {
$category->cat_ID = &$category->term_id;
$category->category_count = &$category->count;
$category->category_description = &$category->description;
$category->cat_name = &$category->name;
$category->category_nicename = &$category->slug;
$category->category_parent = &$category->parent;
} elseif ( is_array( $category ) && isset( $category['term_id'] ) ) {
$category['cat_ID'] = &$category['term_id'];
$category['category_count'] = &$category['count'];
$category['category_description'] = &$category['description'];
$category['cat_name'] = &$category['name'];
$category['category_nicename'] = &$category['slug'];
$category['category_parent'] = &$category['parent'];
}
}

1070
wp-includes/class-IXR.php Normal file

File diff suppressed because it is too large Load Diff

131
wp-includes/class-feed.php Normal file
View File

@ -0,0 +1,131 @@
<?php
if ( !class_exists('SimplePie') )
require_once (ABSPATH . WPINC . '/class-simplepie.php');
class WP_Feed_Cache extends SimplePie_Cache {
/**
* Create a new SimplePie_Cache object
*
* @static
* @access public
*/
function create($location, $filename, $extension) {
return new WP_Feed_Cache_Transient($location, $filename, $extension);
}
}
class WP_Feed_Cache_Transient {
var $name;
var $mod_name;
var $lifetime = 43200; //Default lifetime in cache of 12 hours
function __construct($location, $filename, $extension) {
$this->name = 'feed_' . $filename;
$this->mod_name = 'feed_mod_' . $filename;
$this->lifetime = apply_filters('wp_feed_cache_transient_lifetime', $this->lifetime, $filename);
}
function save($data) {
if ( is_a($data, 'SimplePie') )
$data = $data->data;
set_transient($this->name, $data, $this->lifetime);
set_transient($this->mod_name, time(), $this->lifetime);
return true;
}
function load() {
return get_transient($this->name);
}
function mtime() {
return get_transient($this->mod_name);
}
function touch() {
return set_transient($this->mod_name, time(), $this->lifetime);
}
function unlink() {
delete_transient($this->name);
delete_transient($this->mod_name);
return true;
}
}
class WP_SimplePie_File extends SimplePie_File {
function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
$this->url = $url;
$this->timeout = $timeout;
$this->redirects = $redirects;
$this->headers = $headers;
$this->useragent = $useragent;
$this->method = SIMPLEPIE_FILE_SOURCE_REMOTE;
if ( preg_match('/^http(s)?:\/\//i', $url) ) {
$args = array(
'timeout' => $this->timeout,
'redirection' => $this->redirects,
'reject_unsafe_urls' => true,
);
if ( !empty($this->headers) )
$args['headers'] = $this->headers;
if ( SIMPLEPIE_USERAGENT != $this->useragent ) //Use default WP user agent unless custom has been specified
$args['user-agent'] = $this->useragent;
$res = wp_remote_request($url, $args);
if ( is_wp_error($res) ) {
$this->error = 'WP HTTP Error: ' . $res->get_error_message();
$this->success = false;
} else {
$this->headers = wp_remote_retrieve_headers( $res );
$this->body = wp_remote_retrieve_body( $res );
$this->status_code = wp_remote_retrieve_response_code( $res );
}
} else {
$this->error = '';
$this->success = false;
}
}
}
/**
* WordPress SimplePie Sanitization Class
*
* Extension of the SimplePie_Sanitize class to use KSES, because
* we cannot universally count on DOMDocument being available
*
* @package WordPress
* @since 3.5.0
*/
class WP_SimplePie_Sanitize_KSES extends SimplePie_Sanitize {
public function sanitize( $data, $type, $base = '' ) {
$data = trim( $data );
if ( $type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML ) {
if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) {
$type |= SIMPLEPIE_CONSTRUCT_HTML;
}
else {
$type |= SIMPLEPIE_CONSTRUCT_TEXT;
}
}
if ( $type & SIMPLEPIE_CONSTRUCT_BASE64 ) {
$data = base64_decode( $data );
}
if ( $type & ( SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML ) ) {
$data = wp_kses_post( $data );
if ( $this->output_encoding !== 'UTF-8' ) {
$data = $this->registry->call( 'Misc', 'change_encoding', array( $data, 'UTF-8', $this->output_encoding ) );
}
return $data;
} else {
return parent::sanitize( $data, $type, $base );
}
}
}

1804
wp-includes/class-http.php Normal file

File diff suppressed because it is too large Load Diff

862
wp-includes/class-json.php Normal file
View File

@ -0,0 +1,862 @@
<?php
if ( !class_exists( 'Services_JSON' ) ) :
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Converts to and from JSON format.
*
* JSON (JavaScript Object Notation) is a lightweight data-interchange
* format. It is easy for humans to read and write. It is easy for machines
* to parse and generate. It is based on a subset of the JavaScript
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
* This feature can also be found in Python. JSON is a text format that is
* completely language independent but uses conventions that are familiar
* to programmers of the C-family of languages, including C, C++, C#, Java,
* JavaScript, Perl, TCL, and many others. These properties make JSON an
* ideal data-interchange language.
*
* This package provides a simple encoder and decoder for JSON notation. It
* is intended for use with client-side Javascript applications that make
* use of HTTPRequest to perform server communication functions - data can
* be encoded into JSON notation for use in a client-side javascript, or
* decoded from incoming Javascript requests. JSON format is native to
* Javascript, and can be directly eval()'ed with no further parsing
* overhead
*
* All strings should be in ASCII or UTF-8 format!
*
* LICENSE: Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met: Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* @category
* @package Services_JSON
* @author Michal Migurski <mike-json@teczno.com>
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
* @copyright 2005 Michal Migurski
* @version CVS: $Id: JSON.php 288200 2009-09-09 15:41:29Z alan_k $
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
*/
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_SLICE', 1);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_STR', 2);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_ARR', 3);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_OBJ', 4);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_CMT', 5);
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_LOOSE_TYPE', 16);
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
/**
* Converts to and from JSON format.
*
* Brief example of use:
*
* <code>
* // create a new instance of Services_JSON
* $json = new Services_JSON();
*
* // convert a complexe value to JSON notation, and send it to the browser
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
* $output = $json->encode($value);
*
* print($output);
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
*
* // accept incoming POST data, assumed to be in JSON notation
* $input = file_get_contents('php://input', 1000000);
* $value = $json->decode($input);
* </code>
*/
class Services_JSON
{
/**
* constructs a new JSON instance
*
* @param int $use object behavior flags; combine with boolean-OR
*
* possible values:
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
* "{...}" syntax creates associative arrays
* instead of objects in decode().
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
* Values which can't be encoded (e.g. resources)
* appear as NULL instead of throwing errors.
* By default, a deeply-nested resource will
* bubble up with an error, so all return values
* from encode() should be checked with isError()
*/
function Services_JSON($use = 0)
{
$this->use = $use;
}
/**
* convert a string from one UTF-16 char to one UTF-8 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf16 UTF-16 character
* @return string UTF-8 character
* @access private
*/
function utf162utf8($utf16)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
}
$bytes = (ord($utf16[0]) << 8) | ord($utf16[1]);
switch(true) {
case ((0x7F & $bytes) == $bytes):
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x7F & $bytes);
case (0x07FF & $bytes) == $bytes:
// return a 2-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xC0 | (($bytes >> 6) & 0x1F))
. chr(0x80 | ($bytes & 0x3F));
case (0xFFFF & $bytes) == $bytes:
// return a 3-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xE0 | (($bytes >> 12) & 0x0F))
. chr(0x80 | (($bytes >> 6) & 0x3F))
. chr(0x80 | ($bytes & 0x3F));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* convert a string from one UTF-8 char to one UTF-16 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf8 UTF-8 character
* @return string UTF-16 character
* @access private
*/
function utf82utf16($utf8)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
}
switch(strlen($utf8)) {
case 1:
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return $utf8;
case 2:
// return a UTF-16 character from a 2-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x07 & (ord($utf8[0]) >> 2))
. chr((0xC0 & (ord($utf8[0]) << 6))
| (0x3F & ord($utf8[1])));
case 3:
// return a UTF-16 character from a 3-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr((0xF0 & (ord($utf8[0]) << 4))
| (0x0F & (ord($utf8[1]) >> 2)))
. chr((0xC0 & (ord($utf8[1]) << 6))
| (0x7F & ord($utf8[2])));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* encodes an arbitrary variable into JSON format (and sends JSON Header)
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function encode($var)
{
header('Content-type: application/json');
return $this->_encode($var);
}
/**
* encodes an arbitrary variable into JSON format without JSON Header - warning - may allow CSS!!!!)
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function encodeUnsafe($var)
{
return $this->_encode($var);
}
/**
* PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function _encode($var)
{
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false';
case 'NULL':
return 'null';
case 'integer':
return (int) $var;
case 'double':
case 'float':
return (float) $var;
case 'string':
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
$ascii = '';
$strlen_var = strlen($var);
/*
* Iterate over every character in the string,
* escaping with a slash or encoding to UTF-8 where necessary
*/
for ($c = 0; $c < $strlen_var; ++$c) {
$ord_var_c = ord($var[$c]);
switch (true) {
case $ord_var_c == 0x08:
$ascii .= '\b';
break;
case $ord_var_c == 0x09:
$ascii .= '\t';
break;
case $ord_var_c == 0x0A:
$ascii .= '\n';
break;
case $ord_var_c == 0x0C:
$ascii .= '\f';
break;
case $ord_var_c == 0x0D:
$ascii .= '\r';
break;
case $ord_var_c == 0x22:
case $ord_var_c == 0x2F:
case $ord_var_c == 0x5C:
// double quote, slash, slosh
$ascii .= '\\'.$var[$c];
break;
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var[$c];
break;
case (($ord_var_c & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
if ($c+1 >= $strlen_var) {
$c += 1;
$ascii .= '?';
break;
}
$char = pack('C*', $ord_var_c, ord($var[$c + 1]));
$c += 1;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF0) == 0xE0):
if ($c+2 >= $strlen_var) {
$c += 2;
$ascii .= '?';
break;
}
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
@ord($var[$c + 1]),
@ord($var[$c + 2]));
$c += 2;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF8) == 0xF0):
if ($c+3 >= $strlen_var) {
$c += 3;
$ascii .= '?';
break;
}
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]));
$c += 3;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFC) == 0xF8):
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
if ($c+4 >= $strlen_var) {
$c += 4;
$ascii .= '?';
break;
}
$char = pack('C*', $ord_var_c,
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]),
ord($var[$c + 4]));
$c += 4;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFE) == 0xFC):
if ($c+5 >= $strlen_var) {
$c += 5;
$ascii .= '?';
break;
}
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]),
ord($var[$c + 4]),
ord($var[$c + 5]));
$c += 5;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
}
}
return '"'.$ascii.'"';
case 'array':
/*
* As per JSON spec if any array key is not an integer
* we must treat the the whole array as an object. We
* also try to catch a sparsely populated associative
* array with numeric keys here because some JS engines
* will create an array with empty indexes up to
* max_index which can cause memory issues and because
* the keys, which may be relevant, will be remapped
* otherwise.
*
* As per the ECMA and JSON specification an object may
* have any string as a property. Unfortunately due to
* a hole in the ECMA specification if the key is a
* ECMA reserved word or starts with a digit the
* parameter is only accessible using ECMAScript's
* bracket notation.
*/
// treat as a JSON object
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
$properties = array_map(array($this, 'name_value'),
array_keys($var),
array_values($var));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
}
// treat it like a regular array
$elements = array_map(array($this, '_encode'), $var);
foreach($elements as $element) {
if(Services_JSON::isError($element)) {
return $element;
}
}
return '[' . join(',', $elements) . ']';
case 'object':
$vars = get_object_vars($var);
$properties = array_map(array($this, 'name_value'),
array_keys($vars),
array_values($vars));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
default:
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
? 'null'
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
}
}
/**
* array-walking function for use in generating JSON-formatted name-value pairs
*
* @param string $name name of key to use
* @param mixed $value reference to an array element to be encoded
*
* @return string JSON-formatted name-value pair, like '"name":value'
* @access private
*/
function name_value($name, $value)
{
$encoded_value = $this->_encode($value);
if(Services_JSON::isError($encoded_value)) {
return $encoded_value;
}
return $this->_encode(strval($name)) . ':' . $encoded_value;
}
/**
* reduce a string by removing leading and trailing comments and whitespace
*
* @param $str string string value to strip of comments and whitespace
*
* @return string string value stripped of comments and whitespace
* @access private
*/
function reduce_string($str)
{
$str = preg_replace(array(
// eliminate single line comments in '// ...' form
'#^\s*//(.+)$#m',
// eliminate multi-line comments in '/* ... */' form, at start of string
'#^\s*/\*(.+)\*/#Us',
// eliminate multi-line comments in '/* ... */' form, at end of string
'#/\*(.+)\*/\s*$#Us'
), '', $str);
// eliminate extraneous space
return trim($str);
}
/**
* decodes a JSON string into appropriate variable
*
* @param string $str JSON-formatted string
*
* @return mixed number, boolean, string, array, or object
* corresponding to given JSON input string.
* See argument 1 to Services_JSON() above for object-output behavior.
* Note that decode() always returns strings
* in ASCII or UTF-8 format!
* @access public
*/
function decode($str)
{
$str = $this->reduce_string($str);
switch (strtolower($str)) {
case 'true':
return true;
case 'false':
return false;
case 'null':
return null;
default:
$m = array();
if (is_numeric($str)) {
// Lookie-loo, it's a number
// This would work on its own, but I'm trying to be
// good about returning integers where appropriate:
// return (float)$str;
// Return float or int, as appropriate
return ((float)$str == (integer)$str)
? (integer)$str
: (float)$str;
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
// STRINGS RETURNED IN UTF-8 FORMAT
$delim = substr($str, 0, 1);
$chrs = substr($str, 1, -1);
$utf8 = '';
$strlen_chrs = strlen($chrs);
for ($c = 0; $c < $strlen_chrs; ++$c) {
$substr_chrs_c_2 = substr($chrs, $c, 2);
$ord_chrs_c = ord($chrs[$c]);
switch (true) {
case $substr_chrs_c_2 == '\b':
$utf8 .= chr(0x08);
++$c;
break;
case $substr_chrs_c_2 == '\t':
$utf8 .= chr(0x09);
++$c;
break;
case $substr_chrs_c_2 == '\n':
$utf8 .= chr(0x0A);
++$c;
break;
case $substr_chrs_c_2 == '\f':
$utf8 .= chr(0x0C);
++$c;
break;
case $substr_chrs_c_2 == '\r':
$utf8 .= chr(0x0D);
++$c;
break;
case $substr_chrs_c_2 == '\\"':
case $substr_chrs_c_2 == '\\\'':
case $substr_chrs_c_2 == '\\\\':
case $substr_chrs_c_2 == '\\/':
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
$utf8 .= $chrs[++$c];
}
break;
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
// single, escaped unicode character
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
. chr(hexdec(substr($chrs, ($c + 4), 2)));
$utf8 .= $this->utf162utf8($utf16);
$c += 5;
break;
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
$utf8 .= $chrs[$c];
break;
case ($ord_chrs_c & 0xE0) == 0xC0:
// characters U-00000080 - U-000007FF, mask 110XXXXX
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 2);
++$c;
break;
case ($ord_chrs_c & 0xF0) == 0xE0:
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 3);
$c += 2;
break;
case ($ord_chrs_c & 0xF8) == 0xF0:
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 4);
$c += 3;
break;
case ($ord_chrs_c & 0xFC) == 0xF8:
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 5);
$c += 4;
break;
case ($ord_chrs_c & 0xFE) == 0xFC:
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 6);
$c += 5;
break;
}
}
return $utf8;
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
// array, or object notation
if ($str[0] == '[') {
$stk = array(SERVICES_JSON_IN_ARR);
$arr = array();
} else {
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = array();
} else {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = new stdClass();
}
}
array_push($stk, array('what' => SERVICES_JSON_SLICE,
'where' => 0,
'delim' => false));
$chrs = substr($str, 1, -1);
$chrs = $this->reduce_string($chrs);
if ($chrs == '') {
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} else {
return $obj;
}
}
//print("\nparsing {$chrs}\n");
$strlen_chrs = strlen($chrs);
for ($c = 0; $c <= $strlen_chrs; ++$c) {
$top = end($stk);
$substr_chrs_c_2 = substr($chrs, $c, 2);
if (($c == $strlen_chrs) || (($chrs[$c] == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
// found a comma that is not inside a string, array, etc.,
// OR we've reached the end of the character list
$slice = substr($chrs, $top['where'], ($c - $top['where']));
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
if (reset($stk) == SERVICES_JSON_IN_ARR) {
// we are in an array, so just push an element onto the stack
array_push($arr, $this->decode($slice));
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
// we are in an object, so figure
// out the property name and set an
// element in an associative array,
// for now
$parts = array();
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// "name":value pair
$key = $this->decode($parts[1]);
$val = $this->decode($parts[2]);
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// name:value pair, where name is unquoted
$key = $parts[1];
$val = $this->decode($parts[2]);
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
}
}
} elseif ((($chrs[$c] == '"') || ($chrs[$c] == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
// found a quote, and we are not inside a string
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs[$c]));
//print("Found start of string at {$c}\n");
} elseif (($chrs[$c] == $top['delim']) &&
($top['what'] == SERVICES_JSON_IN_STR) &&
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
} elseif (($chrs[$c] == '[') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print("Found start of array at {$c}\n");
} elseif (($chrs[$c] == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($chrs[$c] == '{') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-brace, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print("Found start of object at {$c}\n");
} elseif (($chrs[$c] == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a comment start, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print("Found start of comment at {$c}\n");
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
// found a comment end, and we're in one now
array_pop($stk);
$c++;
for ($i = $top['where']; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ', $i, 1);
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
}
}
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
return $obj;
}
}
}
}
/**
* @todo Ultimately, this should just call PEAR::isError()
*/
function isError($data, $code = null)
{
if (class_exists('pear')) {
return PEAR::isError($data, $code);
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
is_subclass_of($data, 'services_json_error'))) {
return true;
}
return false;
}
}
if (class_exists('PEAR_Error')) {
class Services_JSON_Error extends PEAR_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
}
}
} else {
/**
* @todo Ultimately, this class shall be descended from PEAR_Error
*/
class Services_JSON_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
}
}
}
endif;

View File

@ -0,0 +1,321 @@
<?php
/**
* API for fetching the HTML to embed remote content based on a provided URL.
* Used internally by the {@link WP_Embed} class, but is designed to be generic.
*
* @link http://codex.wordpress.org/oEmbed oEmbed Codex Article
* @link http://oembed.com/ oEmbed Homepage
*
* @package WordPress
* @subpackage oEmbed
*/
/**
* oEmbed class.
*
* @package WordPress
* @subpackage oEmbed
* @since 2.9.0
*/
class WP_oEmbed {
var $providers = array();
/**
* Constructor
*
* @uses apply_filters() Filters a list of pre-defined oEmbed providers.
*/
function __construct() {
// List out some popular sites that support oEmbed.
// The WP_Embed class disables discovery for non-unfiltered_html users, so only providers in this array will be used for them.
// Add to this list using the wp_oembed_add_provider() function (see its PHPDoc for details).
$this->providers = apply_filters( 'oembed_providers', array(
'#https?://(www\.)?youtube.com/watch.*#i' => array( 'http://www.youtube.com/oembed', true ),
'http://youtu.be/*' => array( 'http://www.youtube.com/oembed', false ),
'http://blip.tv/*' => array( 'http://blip.tv/oembed/', false ),
'#https?://(www\.)?vimeo\.com/.*#i' => array( 'http://vimeo.com/api/oembed.{format}', true ),
'#https?://(www\.)?dailymotion\.com/.*#i' => array( 'http://www.dailymotion.com/services/oembed', true ),
'#https?://(www\.)?flickr\.com/.*#i' => array( 'http://www.flickr.com/services/oembed/', true ),
'#https?://(.+\.)?smugmug\.com/.*#i' => array( 'http://api.smugmug.com/services/oembed/', true ),
'#https?://(www\.)?hulu\.com/watch/.*#i' => array( 'http://www.hulu.com/api/oembed.{format}', true ),
'#https?://(www\.)?viddler\.com/.*#i' => array( 'http://lab.viddler.com/services/oembed/', true ),
'http://qik.com/*' => array( 'http://qik.com/api/oembed.{format}', false ),
'http://revision3.com/*' => array( 'http://revision3.com/api/oembed/', false ),
'http://i*.photobucket.com/albums/*' => array( 'http://photobucket.com/oembed', false ),
'http://gi*.photobucket.com/groups/*' => array( 'http://photobucket.com/oembed', false ),
'#https?://(www\.)?scribd\.com/.*#i' => array( 'http://www.scribd.com/services/oembed', true ),
'http://wordpress.tv/*' => array( 'http://wordpress.tv/oembed/', false ),
'#https?://(.+\.)?polldaddy\.com/.*#i' => array( 'http://polldaddy.com/oembed/', true ),
'#https?://(www\.)?funnyordie\.com/videos/.*#i' => array( 'http://www.funnyordie.com/oembed', true ),
'#https?://(www\.)?twitter.com/.+?/status(es)?/.*#i' => array( 'http://api.twitter.com/1/statuses/oembed.{format}', true ),
'#https?://(www\.)?soundcloud\.com/.*#i' => array( 'http://soundcloud.com/oembed', true ),
'#https?://(www\.)?slideshare.net/*#' => array( 'http://www.slideshare.net/api/oembed/2', true ),
'#http://instagr(\.am|am\.com)/p/.*#i' => array( 'http://api.instagram.com/oembed', true ),
) );
// Fix any embeds that contain new lines in the middle of the HTML which breaks wpautop().
add_filter( 'oembed_dataparse', array($this, '_strip_newlines'), 10, 3 );
}
/**
* The do-it-all function that takes a URL and attempts to return the HTML.
*
* @see WP_oEmbed::discover()
* @see WP_oEmbed::fetch()
* @see WP_oEmbed::data2html()
*
* @param string $url The URL to the content that should be attempted to be embedded.
* @param array $args Optional arguments. Usually passed from a shortcode.
* @return bool|string False on failure, otherwise the UNSANITIZED (and potentially unsafe) HTML that should be used to embed.
*/
function get_html( $url, $args = '' ) {
$provider = false;
if ( !isset($args['discover']) )
$args['discover'] = true;
foreach ( $this->providers as $matchmask => $data ) {
list( $providerurl, $regex ) = $data;
// Turn the asterisk-type provider URLs into regex
if ( !$regex ) {
$matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i';
$matchmask = preg_replace( '|^#http\\\://|', '#https?\://', $matchmask );
}
if ( preg_match( $matchmask, $url ) ) {
$provider = str_replace( '{format}', 'json', $providerurl ); // JSON is easier to deal with than XML
break;
}
}
if ( !$provider && $args['discover'] )
$provider = $this->discover( $url );
if ( !$provider || false === $data = $this->fetch( $provider, $url, $args ) )
return false;
return apply_filters( 'oembed_result', $this->data2html( $data, $url ), $url, $args );
}
/**
* Attempts to find oEmbed provider discovery <link> tags at the given URL.
*
* @param string $url The URL that should be inspected for discovery <link> tags.
* @return bool|string False on failure, otherwise the oEmbed provider URL.
*/
function discover( $url ) {
$providers = array();
// Fetch URL content
if ( $html = wp_remote_retrieve_body( wp_remote_get( $url, array( 'reject_unsafe_urls' => true ) ) ) ) {
// <link> types that contain oEmbed provider URLs
$linktypes = apply_filters( 'oembed_linktypes', array(
'application/json+oembed' => 'json',
'text/xml+oembed' => 'xml',
'application/xml+oembed' => 'xml', // Incorrect, but used by at least Vimeo
) );
// Strip <body>
$html = substr( $html, 0, stripos( $html, '</head>' ) );
// Do a quick check
$tagfound = false;
foreach ( $linktypes as $linktype => $format ) {
if ( stripos($html, $linktype) ) {
$tagfound = true;
break;
}
}
if ( $tagfound && preg_match_all( '/<link([^<>]+)>/i', $html, $links ) ) {
foreach ( $links[1] as $link ) {
$atts = shortcode_parse_atts( $link );
if ( !empty($atts['type']) && !empty($linktypes[$atts['type']]) && !empty($atts['href']) ) {
$providers[$linktypes[$atts['type']]] = $atts['href'];
// Stop here if it's JSON (that's all we need)
if ( 'json' == $linktypes[$atts['type']] )
break;
}
}
}
}
// JSON is preferred to XML
if ( !empty($providers['json']) )
return $providers['json'];
elseif ( !empty($providers['xml']) )
return $providers['xml'];
else
return false;
}
/**
* Connects to a oEmbed provider and returns the result.
*
* @param string $provider The URL to the oEmbed provider.
* @param string $url The URL to the content that is desired to be embedded.
* @param array $args Optional arguments. Usually passed from a shortcode.
* @return bool|object False on failure, otherwise the result in the form of an object.
*/
function fetch( $provider, $url, $args = '' ) {
$args = wp_parse_args( $args, wp_embed_defaults() );
$provider = add_query_arg( 'maxwidth', (int) $args['width'], $provider );
$provider = add_query_arg( 'maxheight', (int) $args['height'], $provider );
$provider = add_query_arg( 'url', urlencode($url), $provider );
$provider = apply_filters( 'oembed_fetch_url', $provider, $url, $args );
foreach( array( 'json', 'xml' ) as $format ) {
$result = $this->_fetch_with_format( $provider, $format );
if ( is_wp_error( $result ) && 'not-implemented' == $result->get_error_code() )
continue;
return ( $result && ! is_wp_error( $result ) ) ? $result : false;
}
return false;
}
/**
* Fetches result from an oEmbed provider for a specific format and complete provider URL
*
* @since 3.0.0
* @access private
* @param string $provider_url_with_args URL to the provider with full arguments list (url, maxheight, etc.)
* @param string $format Format to use
* @return bool|object False on failure, otherwise the result in the form of an object.
*/
function _fetch_with_format( $provider_url_with_args, $format ) {
$provider_url_with_args = add_query_arg( 'format', $format, $provider_url_with_args );
$response = wp_remote_get( $provider_url_with_args, array( 'reject_unsafe_urls' => true ) );
if ( 501 == wp_remote_retrieve_response_code( $response ) )
return new WP_Error( 'not-implemented' );
if ( ! $body = wp_remote_retrieve_body( $response ) )
return false;
$parse_method = "_parse_$format";
return $this->$parse_method( $body );
}
/**
* Parses a json response body.
*
* @since 3.0.0
* @access private
*/
function _parse_json( $response_body ) {
return ( ( $data = json_decode( trim( $response_body ) ) ) && is_object( $data ) ) ? $data : false;
}
/**
* Parses an XML response body.
*
* @since 3.0.0
* @access private
*/
function _parse_xml( $response_body ) {
if ( !function_exists('simplexml_load_string') ) {
return false;
}
if ( ! function_exists( 'libxml_disable_entity_loader' ) )
return false;
$loader = libxml_disable_entity_loader( true );
$errors = libxml_use_internal_errors( true );
$data = simplexml_load_string( $response_body );
libxml_use_internal_errors( $errors );
$return = false;
if ( is_object( $data ) ) {
$return = new stdClass;
foreach ( $data as $key => $value ) {
$return->$key = (string) $value;
}
}
libxml_disable_entity_loader( $loader );
return $return;
}
/**
* Converts a data object from {@link WP_oEmbed::fetch()} and returns the HTML.
*
* @param object $data A data object result from an oEmbed provider.
* @param string $url The URL to the content that is desired to be embedded.
* @return bool|string False on error, otherwise the HTML needed to embed.
*/
function data2html( $data, $url ) {
if ( ! is_object( $data ) || empty( $data->type ) )
return false;
$return = false;
switch ( $data->type ) {
case 'photo':
if ( empty( $data->url ) || empty( $data->width ) || empty( $data->height ) )
break;
if ( ! is_string( $data->url ) || ! is_numeric( $data->width ) || ! is_numeric( $data->height ) )
break;
$title = ! empty( $data->title ) && is_string( $data->title ) ? $data->title : '';
$return = '<a href="' . esc_url( $url ) . '"><img src="' . esc_url( $data->url ) . '" alt="' . esc_attr($title) . '" width="' . esc_attr($data->width) . '" height="' . esc_attr($data->height) . '" /></a>';
break;
case 'video':
case 'rich':
if ( ! empty( $data->html ) && is_string( $data->html ) )
$return = $data->html;
break;
case 'link':
if ( ! empty( $data->title ) && is_string( $data->title ) )
$return = '<a href="' . esc_url( $url ) . '">' . esc_html( $data->title ) . '</a>';
break;
default:
$return = false;
}
// You can use this filter to add support for custom data types or to filter the result
return apply_filters( 'oembed_dataparse', $return, $data, $url );
}
/**
* Strip any new lines from the HTML.
*
* @access private
* @param string $html Existing HTML.
* @param object $data Data object from WP_oEmbed::data2html()
* @param string $url The original URL passed to oEmbed.
* @return string Possibly modified $html
*/
function _strip_newlines( $html, $data, $url ) {
if ( false !== strpos( $html, "\n" ) )
$html = str_replace( array( "\r\n", "\n" ), '', $html );
return $html;
}
}
/**
* Returns the initialized {@link WP_oEmbed} object
*
* @since 2.9.0
* @access private
*
* @see WP_oEmbed
* @uses WP_oEmbed
*
* @return WP_oEmbed object.
*/
function _wp_oembed_get_object() {
static $wp_oembed;
if ( is_null($wp_oembed) )
$wp_oembed = new WP_oEmbed();
return $wp_oembed;
}

View File

@ -0,0 +1,260 @@
<?php
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
*/
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
/**
* Portable PHP password hashing framework.
*
* @package phpass
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
* @since 2.5
*/
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function PasswordHash($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
}
function get_random_bytes($count)
{
$output = '';
if ( @is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id != '$P$' && $id != '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_extended($input)
{
$count_log2 = min($this->iteration_count_log2 + 8, 24);
# This should be odd to not reveal weak DES keys, and the
# maximum valid value is (2**24 - 1) which is odd anyway.
$count = (1 << $count_log2) - 1;
$output = '_';
$output .= $this->itoa64[$count & 0x3f];
$output .= $this->itoa64[($count >> 6) & 0x3f];
$output .= $this->itoa64[($count >> 12) & 0x3f];
$output .= $this->itoa64[($count >> 18) & 0x3f];
$output .= $this->encode64($input, 3);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
$random = '';
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
?>

File diff suppressed because it is too large Load Diff

652
wp-includes/class-pop3.php Normal file
View File

@ -0,0 +1,652 @@
<?php
/**
* mail_fetch/setup.php
*
* Copyright (c) 1999-2011 CDI (cdi@thewebmasters.net) All Rights Reserved
* Modified by Philippe Mingo 2001-2009 mingo@rotedic.com
* An RFC 1939 compliant wrapper class for the POP3 protocol.
*
* Licensed under the GNU GPL. For full terms see the file COPYING.
*
* POP3 class
*
* @copyright 1999-2011 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @package plugins
* @subpackage mail_fetch
*/
class POP3 {
var $ERROR = ''; // Error string.
var $TIMEOUT = 60; // Default timeout before giving up on a
// network operation.
var $COUNT = -1; // Mailbox msg count
var $BUFFER = 512; // Socket buffer for socket fgets() calls.
// Per RFC 1939 the returned line a POP3
// server can send is 512 bytes.
var $FP = ''; // The connection to the server's
// file descriptor
var $MAILSERVER = ''; // Set this to hard code the server name
var $DEBUG = FALSE; // set to true to echo pop3
// commands and responses to error_log
// this WILL log passwords!
var $BANNER = ''; // Holds the banner returned by the
// pop server - used for apop()
var $ALLOWAPOP = FALSE; // Allow or disallow apop()
// This must be set to true
// manually
function POP3 ( $server = '', $timeout = '' ) {
settype($this->BUFFER,"integer");
if( !empty($server) ) {
// Do not allow programs to alter MAILSERVER
// if it is already specified. They can get around
// this if they -really- want to, so don't count on it.
if(empty($this->MAILSERVER))
$this->MAILSERVER = $server;
}
if(!empty($timeout)) {
settype($timeout,"integer");
$this->TIMEOUT = $timeout;
if (!ini_get('safe_mode'))
set_time_limit($timeout);
}
return true;
}
function update_timer () {
if (!ini_get('safe_mode'))
set_time_limit($this->TIMEOUT);
return true;
}
function connect ($server, $port = 110) {
// Opens a socket to the specified server. Unless overridden,
// port defaults to 110. Returns true on success, false on fail
// If MAILSERVER is set, override $server with it's value
if (!isset($port) || !$port) {$port = 110;}
if(!empty($this->MAILSERVER))
$server = $this->MAILSERVER;
if(empty($server)){
$this->ERROR = "POP3 connect: " . _("No server specified");
unset($this->FP);
return false;
}
$fp = @fsockopen("$server", $port, $errno, $errstr);
if(!$fp) {
$this->ERROR = "POP3 connect: " . _("Error ") . "[$errno] [$errstr]";
unset($this->FP);
return false;
}
socket_set_blocking($fp,-1);
$this->update_timer();
$reply = fgets($fp,$this->BUFFER);
$reply = $this->strip_clf($reply);
if($this->DEBUG)
error_log("POP3 SEND [connect: $server] GOT [$reply]",0);
if(!$this->is_ok($reply)) {
$this->ERROR = "POP3 connect: " . _("Error ") . "[$reply]";
unset($this->FP);
return false;
}
$this->FP = $fp;
$this->BANNER = $this->parse_banner($reply);
return true;
}
function user ($user = "") {
// Sends the USER command, returns true or false
if( empty($user) ) {
$this->ERROR = "POP3 user: " . _("no login ID submitted");
return false;
} elseif(!isset($this->FP)) {
$this->ERROR = "POP3 user: " . _("connection not established");
return false;
} else {
$reply = $this->send_cmd("USER $user");
if(!$this->is_ok($reply)) {
$this->ERROR = "POP3 user: " . _("Error ") . "[$reply]";
return false;
} else
return true;
}
}
function pass ($pass = "") {
// Sends the PASS command, returns # of msgs in mailbox,
// returns false (undef) on Auth failure
if(empty($pass)) {
$this->ERROR = "POP3 pass: " . _("No password submitted");
return false;
} elseif(!isset($this->FP)) {
$this->ERROR = "POP3 pass: " . _("connection not established");
return false;
} else {
$reply = $this->send_cmd("PASS $pass");
if(!$this->is_ok($reply)) {
$this->ERROR = "POP3 pass: " . _("Authentication failed") . " [$reply]";
$this->quit();
return false;
} else {
// Auth successful.
$count = $this->last("count");
$this->COUNT = $count;
return $count;
}
}
}
function apop ($login,$pass) {
// Attempts an APOP login. If this fails, it'll
// try a standard login. YOUR SERVER MUST SUPPORT
// THE USE OF THE APOP COMMAND!
// (apop is optional per rfc1939)
if(!isset($this->FP)) {
$this->ERROR = "POP3 apop: " . _("No connection to server");
return false;
} elseif(!$this->ALLOWAPOP) {
$retVal = $this->login($login,$pass);
return $retVal;
} elseif(empty($login)) {
$this->ERROR = "POP3 apop: " . _("No login ID submitted");
return false;
} elseif(empty($pass)) {
$this->ERROR = "POP3 apop: " . _("No password submitted");
return false;
} else {
$banner = $this->BANNER;
if( (!$banner) or (empty($banner)) ) {
$this->ERROR = "POP3 apop: " . _("No server banner") . ' - ' . _("abort");
$retVal = $this->login($login,$pass);
return $retVal;
} else {
$AuthString = $banner;
$AuthString .= $pass;
$APOPString = md5($AuthString);
$cmd = "APOP $login $APOPString";
$reply = $this->send_cmd($cmd);
if(!$this->is_ok($reply)) {
$this->ERROR = "POP3 apop: " . _("apop authentication failed") . ' - ' . _("abort");
$retVal = $this->login($login,$pass);
return $retVal;
} else {
// Auth successful.
$count = $this->last("count");
$this->COUNT = $count;
return $count;
}
}
}
}
function login ($login = "", $pass = "") {
// Sends both user and pass. Returns # of msgs in mailbox or
// false on failure (or -1, if the error occurs while getting
// the number of messages.)
if( !isset($this->FP) ) {
$this->ERROR = "POP3 login: " . _("No connection to server");
return false;
} else {
$fp = $this->FP;
if( !$this->user( $login ) ) {
// Preserve the error generated by user()
return false;
} else {
$count = $this->pass($pass);
if( (!$count) || ($count == -1) ) {
// Preserve the error generated by last() and pass()
return false;
} else
return $count;
}
}
}
function top ($msgNum, $numLines = "0") {
// Gets the header and first $numLines of the msg body
// returns data in an array with each returned line being
// an array element. If $numLines is empty, returns
// only the header information, and none of the body.
if(!isset($this->FP)) {
$this->ERROR = "POP3 top: " . _("No connection to server");
return false;
}
$this->update_timer();
$fp = $this->FP;
$buffer = $this->BUFFER;
$cmd = "TOP $msgNum $numLines";
fwrite($fp, "TOP $msgNum $numLines\r\n");
$reply = fgets($fp, $buffer);
$reply = $this->strip_clf($reply);
if($this->DEBUG) {
@error_log("POP3 SEND [$cmd] GOT [$reply]",0);
}
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 top: " . _("Error ") . "[$reply]";
return false;
}
$count = 0;
$MsgArray = array();
$line = fgets($fp,$buffer);
while ( !preg_match('/^\.\r\n/',$line))
{
$MsgArray[$count] = $line;
$count++;
$line = fgets($fp,$buffer);
if(empty($line)) { break; }
}
return $MsgArray;
}
function pop_list ($msgNum = "") {
// If called with an argument, returns that msgs' size in octets
// No argument returns an associative array of undeleted
// msg numbers and their sizes in octets
if(!isset($this->FP))
{
$this->ERROR = "POP3 pop_list: " . _("No connection to server");
return false;
}
$fp = $this->FP;
$Total = $this->COUNT;
if( (!$Total) or ($Total == -1) )
{
return false;
}
if($Total == 0)
{
return array("0","0");
// return -1; // mailbox empty
}
$this->update_timer();
if(!empty($msgNum))
{
$cmd = "LIST $msgNum";
fwrite($fp,"$cmd\r\n");
$reply = fgets($fp,$this->BUFFER);
$reply = $this->strip_clf($reply);
if($this->DEBUG) {
@error_log("POP3 SEND [$cmd] GOT [$reply]",0);
}
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]";
return false;
}
list($junk,$num,$size) = preg_split('/\s+/',$reply);
return $size;
}
$cmd = "LIST";
$reply = $this->send_cmd($cmd);
if(!$this->is_ok($reply))
{
$reply = $this->strip_clf($reply);
$this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]";
return false;
}
$MsgArray = array();
$MsgArray[0] = $Total;
for($msgC=1;$msgC <= $Total; $msgC++)
{
if($msgC > $Total) { break; }
$line = fgets($fp,$this->BUFFER);
$line = $this->strip_clf($line);
if(strpos($line, '.') === 0)
{
$this->ERROR = "POP3 pop_list: " . _("Premature end of list");
return false;
}
list($thisMsg,$msgSize) = preg_split('/\s+/',$line);
settype($thisMsg,"integer");
if($thisMsg != $msgC)
{
$MsgArray[$msgC] = "deleted";
}
else
{
$MsgArray[$msgC] = $msgSize;
}
}
return $MsgArray;
}
function get ($msgNum) {
// Retrieve the specified msg number. Returns an array
// where each line of the msg is an array element.
if(!isset($this->FP))
{
$this->ERROR = "POP3 get: " . _("No connection to server");
return false;
}
$this->update_timer();
$fp = $this->FP;
$buffer = $this->BUFFER;
$cmd = "RETR $msgNum";
$reply = $this->send_cmd($cmd);
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 get: " . _("Error ") . "[$reply]";
return false;
}
$count = 0;
$MsgArray = array();
$line = fgets($fp,$buffer);
while ( !preg_match('/^\.\r\n/',$line))
{
if ( $line{0} == '.' ) { $line = substr($line,1); }
$MsgArray[$count] = $line;
$count++;
$line = fgets($fp,$buffer);
if(empty($line)) { break; }
}
return $MsgArray;
}
function last ( $type = "count" ) {
// Returns the highest msg number in the mailbox.
// returns -1 on error, 0+ on success, if type != count
// results in a popstat() call (2 element array returned)
$last = -1;
if(!isset($this->FP))
{
$this->ERROR = "POP3 last: " . _("No connection to server");
return $last;
}
$reply = $this->send_cmd("STAT");
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 last: " . _("Error ") . "[$reply]";
return $last;
}
$Vars = preg_split('/\s+/',$reply);
$count = $Vars[1];
$size = $Vars[2];
settype($count,"integer");
settype($size,"integer");
if($type != "count")
{
return array($count,$size);
}
return $count;
}
function reset () {
// Resets the status of the remote server. This includes
// resetting the status of ALL msgs to not be deleted.
// This method automatically closes the connection to the server.
if(!isset($this->FP))
{
$this->ERROR = "POP3 reset: " . _("No connection to server");
return false;
}
$reply = $this->send_cmd("RSET");
if(!$this->is_ok($reply))
{
// The POP3 RSET command -never- gives a -ERR
// response - if it ever does, something truely
// wild is going on.
$this->ERROR = "POP3 reset: " . _("Error ") . "[$reply]";
@error_log("POP3 reset: ERROR [$reply]",0);
}
$this->quit();
return true;
}
function send_cmd ( $cmd = "" )
{
// Sends a user defined command string to the
// POP server and returns the results. Useful for
// non-compliant or custom POP servers.
// Do NOT includ the \r\n as part of your command
// string - it will be appended automatically.
// The return value is a standard fgets() call, which
// will read up to $this->BUFFER bytes of data, until it
// encounters a new line, or EOF, whichever happens first.
// This method works best if $cmd responds with only
// one line of data.
if(!isset($this->FP))
{
$this->ERROR = "POP3 send_cmd: " . _("No connection to server");
return false;
}
if(empty($cmd))
{
$this->ERROR = "POP3 send_cmd: " . _("Empty command string");
return "";
}
$fp = $this->FP;
$buffer = $this->BUFFER;
$this->update_timer();
fwrite($fp,"$cmd\r\n");
$reply = fgets($fp,$buffer);
$reply = $this->strip_clf($reply);
if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
return $reply;
}
function quit() {
// Closes the connection to the POP3 server, deleting
// any msgs marked as deleted.
if(!isset($this->FP))
{
$this->ERROR = "POP3 quit: " . _("connection does not exist");
return false;
}
$fp = $this->FP;
$cmd = "QUIT";
fwrite($fp,"$cmd\r\n");
$reply = fgets($fp,$this->BUFFER);
$reply = $this->strip_clf($reply);
if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
fclose($fp);
unset($this->FP);
return true;
}
function popstat () {
// Returns an array of 2 elements. The number of undeleted
// msgs in the mailbox, and the size of the mbox in octets.
$PopArray = $this->last("array");
if($PopArray == -1) { return false; }
if( (!$PopArray) or (empty($PopArray)) )
{
return false;
}
return $PopArray;
}
function uidl ($msgNum = "")
{
// Returns the UIDL of the msg specified. If called with
// no arguments, returns an associative array where each
// undeleted msg num is a key, and the msg's uidl is the element
// Array element 0 will contain the total number of msgs
if(!isset($this->FP)) {
$this->ERROR = "POP3 uidl: " . _("No connection to server");
return false;
}
$fp = $this->FP;
$buffer = $this->BUFFER;
if(!empty($msgNum)) {
$cmd = "UIDL $msgNum";
$reply = $this->send_cmd($cmd);
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
return false;
}
list ($ok,$num,$myUidl) = preg_split('/\s+/',$reply);
return $myUidl;
} else {
$this->update_timer();
$UIDLArray = array();
$Total = $this->COUNT;
$UIDLArray[0] = $Total;
if ($Total < 1)
{
return $UIDLArray;
}
$cmd = "UIDL";
fwrite($fp, "UIDL\r\n");
$reply = fgets($fp, $buffer);
$reply = $this->strip_clf($reply);
if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
return false;
}
$line = "";
$count = 1;
$line = fgets($fp,$buffer);
while ( !preg_match('/^\.\r\n/',$line)) {
list ($msg,$msgUidl) = preg_split('/\s+/',$line);
$msgUidl = $this->strip_clf($msgUidl);
if($count == $msg) {
$UIDLArray[$msg] = $msgUidl;
}
else
{
$UIDLArray[$count] = 'deleted';
}
$count++;
$line = fgets($fp,$buffer);
}
}
return $UIDLArray;
}
function delete ($msgNum = "") {
// Flags a specified msg as deleted. The msg will not
// be deleted until a quit() method is called.
if(!isset($this->FP))
{
$this->ERROR = "POP3 delete: " . _("No connection to server");
return false;
}
if(empty($msgNum))
{
$this->ERROR = "POP3 delete: " . _("No msg number submitted");
return false;
}
$reply = $this->send_cmd("DELE $msgNum");
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 delete: " . _("Command failed ") . "[$reply]";
return false;
}
return true;
}
// *********************************************************
// The following methods are internal to the class.
function is_ok ($cmd = "") {
// Return true or false on +OK or -ERR
if( empty($cmd) )
return false;
else
return( stripos($cmd, '+OK') !== false );
}
function strip_clf ($text = "") {
// Strips \r\n from server responses
if(empty($text))
return $text;
else {
$stripped = str_replace(array("\r","\n"),'',$text);
return $stripped;
}
}
function parse_banner ( $server_text ) {
$outside = true;
$banner = "";
$length = strlen($server_text);
for($count =0; $count < $length; $count++)
{
$digit = substr($server_text,$count,1);
if(!empty($digit)) {
if( (!$outside) && ($digit != '<') && ($digit != '>') )
{
$banner .= $digit;
}
if ($digit == '<')
{
$outside = false;
}
if($digit == '>')
{
$outside = true;
}
}
}
$banner = $this->strip_clf($banner); // Just in case
return "<$banner>";
}
} // End class
// For php4 compatibility
if (!function_exists("stripos")) {
function stripos($haystack, $needle){
return strpos($haystack, stristr( $haystack, $needle ));
}
}

File diff suppressed because it is too large Load Diff

818
wp-includes/class-smtp.php Normal file
View File

@ -0,0 +1,818 @@
<?php
/*~ class.smtp.php
.---------------------------------------------------------------------------.
| Software: PHPMailer - PHP email class |
| Version: 5.2.1 |
| Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
| ------------------------------------------------------------------------- |
| Admin: Jim Jagielski (project admininistrator) |
| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
| : Jim Jagielski (jimjag) jimjag@gmail.com |
| Founder: Brent R. Matzelle (original founder) |
| Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
| Copyright (c) 2001-2003, Brent R. Matzelle |
| ------------------------------------------------------------------------- |
| License: Distributed under the Lesser General Public License (LGPL) |
| http://www.gnu.org/copyleft/lesser.html |
| This program is distributed in the hope that it will be useful - WITHOUT |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. |
'---------------------------------------------------------------------------'
*/
/**
* PHPMailer - PHP SMTP email transport class
* NOTE: Designed for use with PHP version 5 and up
* @package PHPMailer
* @author Andy Prevost
* @author Marcus Bointon
* @copyright 2004 - 2008 Andy Prevost
* @author Jim Jagielski
* @copyright 2010 - 2012 Jim Jagielski
* @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
* @version $Id: class.smtp.php 450 2010-06-23 16:46:33Z coolbru $
*/
/**
* SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
* commands except TURN which will always return a not implemented
* error. SMTP also provides some utility methods for sending mail
* to an SMTP server.
* original author: Chris Ryan
*/
class SMTP {
/**
* SMTP server port
* @var int
*/
public $SMTP_PORT = 25;
/**
* SMTP reply line ending
* @var string
*/
public $CRLF = "\r\n";
/**
* Sets whether debugging is turned on
* @var bool
*/
public $do_debug; // the level of debug to perform
/**
* Sets VERP use on/off (default is off)
* @var bool
*/
public $do_verp = false;
/**
* Sets the SMTP PHPMailer Version number
* @var string
*/
public $Version = '5.2.1';
/////////////////////////////////////////////////
// PROPERTIES, PRIVATE AND PROTECTED
/////////////////////////////////////////////////
private $smtp_conn; // the socket to the server
private $error; // error if any on the last call
private $helo_rply; // the reply the server sent to us for HELO
/**
* Initialize the class so that the data is in a known state.
* @access public
* @return void
*/
public function __construct() {
$this->smtp_conn = 0;
$this->error = null;
$this->helo_rply = null;
$this->do_debug = 0;
}
/////////////////////////////////////////////////
// CONNECTION FUNCTIONS
/////////////////////////////////////////////////
/**
* Connect to the server specified on the port specified.
* If the port is not specified use the default SMTP_PORT.
* If tval is specified then a connection will try and be
* established with the server for that number of seconds.
* If tval is not specified the default is 30 seconds to
* try on the connection.
*
* SMTP CODE SUCCESS: 220
* SMTP CODE FAILURE: 421
* @access public
* @return bool
*/
public function Connect($host, $port = 0, $tval = 30) {
// set the error val to null so there is no confusion
$this->error = null;
// make sure we are __not__ connected
if($this->connected()) {
// already connected, generate error
$this->error = array("error" => "Already connected to a server");
return false;
}
if(empty($port)) {
$port = $this->SMTP_PORT;
}
// connect to the smtp server
$this->smtp_conn = @fsockopen($host, // the host of the server
$port, // the port to use
$errno, // error number if any
$errstr, // error message if any
$tval); // give up after ? secs
// verify we connected properly
if(empty($this->smtp_conn)) {
$this->error = array("error" => "Failed to connect to server",
"errno" => $errno,
"errstr" => $errstr);
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
}
return false;
}
// SMTP server can take longer to respond, give longer timeout for first read
// Windows does not have support for this timeout function
if(substr(PHP_OS, 0, 3) != "WIN")
socket_set_timeout($this->smtp_conn, $tval, 0);
// get any announcement
$announce = $this->get_lines();
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
}
return true;
}
/**
* Initiate a TLS communication with the server.
*
* SMTP CODE 220 Ready to start TLS
* SMTP CODE 501 Syntax error (no parameters allowed)
* SMTP CODE 454 TLS not available due to temporary reason
* @access public
* @return bool success
*/
public function StartTLS() {
$this->error = null; # to avoid confusion
if(!$this->connected()) {
$this->error = array("error" => "Called StartTLS() without being connected");
return false;
}
fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
}
if($code != 220) {
$this->error =
array("error" => "STARTTLS not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
// Begin encrypted connection
if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
return false;
}
return true;
}
/**
* Performs SMTP authentication. Must be run after running the
* Hello() method. Returns true if successfully authenticated.
* @access public
* @return bool
*/
public function Authenticate($username, $password) {
// Start authentication
fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($code != 334) {
$this->error =
array("error" => "AUTH not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
// Send encoded username
fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($code != 334) {
$this->error =
array("error" => "Username not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
// Send encoded password
fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($code != 235) {
$this->error =
array("error" => "Password not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
return true;
}
/**
* Returns true if connected to a server otherwise false
* @access public
* @return bool
*/
public function Connected() {
if(!empty($this->smtp_conn)) {
$sock_status = socket_get_status($this->smtp_conn);
if($sock_status["eof"]) {
// the socket is valid but we are not connected
if($this->do_debug >= 1) {
echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
}
$this->Close();
return false;
}
return true; // everything looks good
}
return false;
}
/**
* Closes the socket and cleans up the state of the class.
* It is not considered good to use this function without
* first trying to use QUIT.
* @access public
* @return void
*/
public function Close() {
$this->error = null; // so there is no confusion
$this->helo_rply = null;
if(!empty($this->smtp_conn)) {
// close the connection and cleanup
fclose($this->smtp_conn);
$this->smtp_conn = 0;
}
}
/////////////////////////////////////////////////
// SMTP COMMANDS
/////////////////////////////////////////////////
/**
* Issues a data command and sends the msg_data to the server
* finializing the mail transaction. $msg_data is the message
* that is to be send with the headers. Each header needs to be
* on a single line followed by a <CRLF> with the message headers
* and the message body being seperated by and additional <CRLF>.
*
* Implements rfc 821: DATA <CRLF>
*
* SMTP CODE INTERMEDIATE: 354
* [data]
* <CRLF>.<CRLF>
* SMTP CODE SUCCESS: 250
* SMTP CODE FAILURE: 552,554,451,452
* SMTP CODE FAILURE: 451,554
* SMTP CODE ERROR : 500,501,503,421
* @access public
* @return bool
*/
public function Data($msg_data) {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
"error" => "Called Data() without being connected");
return false;
}
fputs($this->smtp_conn,"DATA" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
}
if($code != 354) {
$this->error =
array("error" => "DATA command not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
/* the server is ready to accept data!
* according to rfc 821 we should not send more than 1000
* including the CRLF
* characters on a single line so we will break the data up
* into lines by \r and/or \n then if needed we will break
* each of those into smaller lines to fit within the limit.
* in addition we will be looking for lines that start with
* a period '.' and append and additional period '.' to that
* line. NOTE: this does not count towards limit.
*/
// normalize the line breaks so we know the explode works
$msg_data = str_replace("\r\n","\n",$msg_data);
$msg_data = str_replace("\r","\n",$msg_data);
$lines = explode("\n",$msg_data);
/* we need to find a good way to determine is headers are
* in the msg_data or if it is a straight msg body
* currently I am assuming rfc 822 definitions of msg headers
* and if the first field of the first line (':' sperated)
* does not contain a space then it _should_ be a header
* and we can process all lines before a blank "" line as
* headers.
*/
$field = substr($lines[0],0,strpos($lines[0],":"));
$in_headers = false;
if(!empty($field) && !strstr($field," ")) {
$in_headers = true;
}
$max_line_length = 998; // used below; set here for ease in change
while(list(,$line) = @each($lines)) {
$lines_out = null;
if($line == "" && $in_headers) {
$in_headers = false;
}
// ok we need to break this line up into several smaller lines
while(strlen($line) > $max_line_length) {
$pos = strrpos(substr($line,0,$max_line_length)," ");
// Patch to fix DOS attack
if(!$pos) {
$pos = $max_line_length - 1;
$lines_out[] = substr($line,0,$pos);
$line = substr($line,$pos);
} else {
$lines_out[] = substr($line,0,$pos);
$line = substr($line,$pos + 1);
}
/* if processing headers add a LWSP-char to the front of new line
* rfc 822 on long msg headers
*/
if($in_headers) {
$line = "\t" . $line;
}
}
$lines_out[] = $line;
// send the lines to the server
while(list(,$line_out) = @each($lines_out)) {
if(strlen($line_out) > 0)
{
if(substr($line_out, 0, 1) == ".") {
$line_out = "." . $line_out;
}
}
fputs($this->smtp_conn,$line_out . $this->CRLF);
}
}
// message data has been sent
fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
}
if($code != 250) {
$this->error =
array("error" => "DATA not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
return true;
}
/**
* Sends the HELO command to the smtp server.
* This makes sure that we and the server are in
* the same known state.
*
* Implements from rfc 821: HELO <SP> <domain> <CRLF>
*
* SMTP CODE SUCCESS: 250
* SMTP CODE ERROR : 500, 501, 504, 421
* @access public
* @return bool
*/
public function Hello($host = '') {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
"error" => "Called Hello() without being connected");
return false;
}
// if hostname for HELO was not specified send default
if(empty($host)) {
// determine appropriate default to send to server
$host = "localhost";
}
// Send extended hello first (RFC 2821)
if(!$this->SendHello("EHLO", $host)) {
if(!$this->SendHello("HELO", $host)) {
return false;
}
}
return true;
}
/**
* Sends a HELO/EHLO command.
* @access private
* @return bool
*/
private function SendHello($hello, $host) {
fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
}
if($code != 250) {
$this->error =
array("error" => $hello . " not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
$this->helo_rply = $rply;
return true;
}
/**
* Starts a mail transaction from the email address specified in
* $from. Returns true if successful or false otherwise. If True
* the mail transaction is started and then one or more Recipient
* commands may be called followed by a Data command.
*
* Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
*
* SMTP CODE SUCCESS: 250
* SMTP CODE SUCCESS: 552,451,452
* SMTP CODE SUCCESS: 500,501,421
* @access public
* @return bool
*/
public function Mail($from) {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
"error" => "Called Mail() without being connected");
return false;
}
$useVerp = ($this->do_verp ? "XVERP" : "");
fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
}
if($code != 250) {
$this->error =
array("error" => "MAIL not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
return true;
}
/**
* Sends the quit command to the server and then closes the socket
* if there is no error or the $close_on_error argument is true.
*
* Implements from rfc 821: QUIT <CRLF>
*
* SMTP CODE SUCCESS: 221
* SMTP CODE ERROR : 500
* @access public
* @return bool
*/
public function Quit($close_on_error = true) {
$this->error = null; // so there is no confusion
if(!$this->connected()) {
$this->error = array(
"error" => "Called Quit() without being connected");
return false;
}
// send the quit command to the server
fputs($this->smtp_conn,"quit" . $this->CRLF);
// get any good-bye messages
$byemsg = $this->get_lines();
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
}
$rval = true;
$e = null;
$code = substr($byemsg,0,3);
if($code != 221) {
// use e as a tmp var cause Close will overwrite $this->error
$e = array("error" => "SMTP server rejected quit command",
"smtp_code" => $code,
"smtp_rply" => substr($byemsg,4));
$rval = false;
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
}
}
if(empty($e) || $close_on_error) {
$this->Close();
}
return $rval;
}
/**
* Sends the command RCPT to the SMTP server with the TO: argument of $to.
* Returns true if the recipient was accepted false if it was rejected.
*
* Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
*
* SMTP CODE SUCCESS: 250,251
* SMTP CODE FAILURE: 550,551,552,553,450,451,452
* SMTP CODE ERROR : 500,501,503,421
* @access public
* @return bool
*/
public function Recipient($to) {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
"error" => "Called Recipient() without being connected");
return false;
}
fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
}
if($code != 250 && $code != 251) {
$this->error =
array("error" => "RCPT not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
return true;
}
/**
* Sends the RSET command to abort and transaction that is
* currently in progress. Returns true if successful false
* otherwise.
*
* Implements rfc 821: RSET <CRLF>
*
* SMTP CODE SUCCESS: 250
* SMTP CODE ERROR : 500,501,504,421
* @access public
* @return bool
*/
public function Reset() {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
"error" => "Called Reset() without being connected");
return false;
}
fputs($this->smtp_conn,"RSET" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
}
if($code != 250) {
$this->error =
array("error" => "RSET failed",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
return true;
}
/**
* Starts a mail transaction from the email address specified in
* $from. Returns true if successful or false otherwise. If True
* the mail transaction is started and then one or more Recipient
* commands may be called followed by a Data command. This command
* will send the message to the users terminal if they are logged
* in and send them an email.
*
* Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
*
* SMTP CODE SUCCESS: 250
* SMTP CODE SUCCESS: 552,451,452
* SMTP CODE SUCCESS: 500,501,502,421
* @access public
* @return bool
*/
public function SendAndMail($from) {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
"error" => "Called SendAndMail() without being connected");
return false;
}
fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
if($this->do_debug >= 2) {
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
}
if($code != 250) {
$this->error =
array("error" => "SAML not accepted from server",
"smtp_code" => $code,
"smtp_msg" => substr($rply,4));
if($this->do_debug >= 1) {
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
}
return false;
}
return true;
}
/**
* This is an optional command for SMTP that this class does not
* support. This method is here to make the RFC821 Definition
* complete for this class and __may__ be implimented in the future
*
* Implements from rfc 821: TURN <CRLF>
*
* SMTP CODE SUCCESS: 250
* SMTP CODE FAILURE: 502
* SMTP CODE ERROR : 500, 503
* @access public
* @return bool
*/
public function Turn() {
$this->error = array("error" => "This method, TURN, of the SMTP ".
"is not implemented");
if($this->do_debug >= 1) {
echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
}
return false;
}
/**
* Get the current error
* @access public
* @return array
*/
public function getError() {
return $this->error;
}
/////////////////////////////////////////////////
// INTERNAL FUNCTIONS
/////////////////////////////////////////////////
/**
* Read in as many lines as possible
* either before eof or socket timeout occurs on the operation.
* With SMTP we can tell if we have more lines to read if the
* 4th character is '-' symbol. If it is a space then we don't
* need to read anything else.
* @access private
* @return string
*/
private function get_lines() {
$data = "";
while(!feof($this->smtp_conn)) {
$str = @fgets($this->smtp_conn,515);
if($this->do_debug >= 4) {
echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
}
$data .= $str;
if($this->do_debug >= 4) {
echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
}
// if 4th character is a space, we are done reading, break the loop
if(substr($str,3,1) == " ") { break; }
}
return $data;
}
}
?>

1256
wp-includes/class-snoopy.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,492 @@
<?php
/**
* The WordPress Toolbar
*
* @since 3.1.0
*
* @package WordPress
* @subpackage Toolbar
*/
class WP_Admin_Bar {
private $nodes = array();
private $bound = false;
public $user;
public function __get( $name ) {
switch ( $name ) {
case 'proto' :
return is_ssl() ? 'https://' : 'http://';
break;
case 'menu' :
_deprecated_argument( 'WP_Admin_Bar', '3.3', 'Modify admin bar nodes with WP_Admin_Bar::get_node(), WP_Admin_Bar::add_node(), and WP_Admin_Bar::remove_node(), not the <code>menu</code> property.' );
return array(); // Sorry, folks.
break;
}
}
public function initialize() {
$this->user = new stdClass;
if ( is_user_logged_in() ) {
/* Populate settings we need for the menu based on the current user. */
$this->user->blogs = get_blogs_of_user( get_current_user_id() );
if ( is_multisite() ) {
$this->user->active_blog = get_active_blog_for_user( get_current_user_id() );
$this->user->domain = empty( $this->user->active_blog ) ? user_admin_url() : trailingslashit( get_home_url( $this->user->active_blog->blog_id ) );
$this->user->account_domain = $this->user->domain;
} else {
$this->user->active_blog = $this->user->blogs[get_current_blog_id()];
$this->user->domain = trailingslashit( home_url() );
$this->user->account_domain = $this->user->domain;
}
}
add_action( 'wp_head', 'wp_admin_bar_header' );
add_action( 'admin_head', 'wp_admin_bar_header' );
if ( current_theme_supports( 'admin-bar' ) ) {
$admin_bar_args = get_theme_support( 'admin-bar' ); // add_theme_support( 'admin-bar', array( 'callback' => '__return_false') );
$header_callback = $admin_bar_args[0]['callback'];
}
if ( empty($header_callback) )
$header_callback = '_admin_bar_bump_cb';
add_action('wp_head', $header_callback);
wp_enqueue_script( 'admin-bar' );
wp_enqueue_style( 'admin-bar' );
do_action( 'admin_bar_init' );
}
public function add_menu( $node ) {
$this->add_node( $node );
}
public function remove_menu( $id ) {
$this->remove_node( $id );
}
/**
* Add a node to the menu.
*
* @param array $args - The arguments for each node.
* - id - string - The ID of the item.
* - title - string - The title of the node.
* - parent - string - The ID of the parent node. Optional.
* - href - string - The link for the item. Optional.
* - group - boolean - If the node is a group. Optional. Default false.
* - meta - array - Meta data including the following keys: html, class, onclick, target, title, tabindex.
*/
public function add_node( $args ) {
// Shim for old method signature: add_node( $parent_id, $menu_obj, $args )
if ( func_num_args() >= 3 && is_string( func_get_arg(0) ) )
$args = array_merge( array( 'parent' => func_get_arg(0) ), func_get_arg(2) );
if ( is_object( $args ) )
$args = get_object_vars( $args );
// Ensure we have a valid title.
if ( empty( $args['id'] ) ) {
if ( empty( $args['title'] ) )
return;
_doing_it_wrong( __METHOD__, __( 'The menu ID should not be empty.' ), '3.3' );
// Deprecated: Generate an ID from the title.
$args['id'] = esc_attr( sanitize_title( trim( $args['title'] ) ) );
}
$defaults = array(
'id' => false,
'title' => false,
'parent' => false,
'href' => false,
'group' => false,
'meta' => array(),
);
// If the node already exists, keep any data that isn't provided.
if ( $maybe_defaults = $this->get_node( $args['id'] ) )
$defaults = get_object_vars( $maybe_defaults );
// Do the same for 'meta' items.
if ( ! empty( $defaults['meta'] ) && ! empty( $args['meta'] ) )
$args['meta'] = wp_parse_args( $args['meta'], $defaults['meta'] );
$args = wp_parse_args( $args, $defaults );
$back_compat_parents = array(
'my-account-with-avatar' => array( 'my-account', '3.3' ),
'my-blogs' => array( 'my-sites', '3.3' ),
);
if ( isset( $back_compat_parents[ $args['parent'] ] ) ) {
list( $new_parent, $version ) = $back_compat_parents[ $args['parent'] ];
_deprecated_argument( __METHOD__, $version, sprintf( 'Use <code>%s</code> as the parent for the <code>%s</code> admin bar node instead of <code>%s</code>.', $new_parent, $args['id'], $args['parent'] ) );
$args['parent'] = $new_parent;
}
$this->_set_node( $args );
}
final protected function _set_node( $args ) {
$this->nodes[ $args['id'] ] = (object) $args;
}
/**
* Gets a node.
*
* @return object Node.
*/
final public function get_node( $id ) {
if ( $node = $this->_get_node( $id ) )
return clone $node;
}
final protected function _get_node( $id ) {
if ( $this->bound )
return;
if ( empty( $id ) )
$id = 'root';
if ( isset( $this->nodes[ $id ] ) )
return $this->nodes[ $id ];
}
final public function get_nodes() {
if ( ! $nodes = $this->_get_nodes() )
return;
foreach ( $nodes as &$node ) {
$node = clone $node;
}
return $nodes;
}
final protected function _get_nodes() {
if ( $this->bound )
return;
return $this->nodes;
}
/**
* Add a group to a menu node.
*
* @since 3.3.0
*
* @param array $args - The arguments for each node.
* - id - string - The ID of the item.
* - parent - string - The ID of the parent node. Optional. Default root.
* - meta - array - Meta data including the following keys: class, onclick, target, title.
*/
final public function add_group( $args ) {
$args['group'] = true;
$this->add_node( $args );
}
/**
* Remove a node.
*
* @param string The ID of the item.
*/
public function remove_node( $id ) {
$this->_unset_node( $id );
}
final protected function _unset_node( $id ) {
unset( $this->nodes[ $id ] );
}
public function render() {
$root = $this->_bind();
if ( $root )
$this->_render( $root );
}
final protected function _bind() {
if ( $this->bound )
return;
// Add the root node.
// Clear it first, just in case. Don't mess with The Root.
$this->remove_node( 'root' );
$this->add_node( array(
'id' => 'root',
'group' => false,
) );
// Normalize nodes: define internal 'children' and 'type' properties.
foreach ( $this->_get_nodes() as $node ) {
$node->children = array();
$node->type = ( $node->group ) ? 'group' : 'item';
unset( $node->group );
// The Root wants your orphans. No lonely items allowed.
if ( ! $node->parent )
$node->parent = 'root';
}
foreach ( $this->_get_nodes() as $node ) {
if ( 'root' == $node->id )
continue;
// Fetch the parent node. If it isn't registered, ignore the node.
if ( ! $parent = $this->_get_node( $node->parent ) ) {
continue;
}
// Generate the group class (we distinguish between top level and other level groups).
$group_class = ( $node->parent == 'root' ) ? 'ab-top-menu' : 'ab-submenu';
if ( $node->type == 'group' ) {
if ( empty( $node->meta['class'] ) )
$node->meta['class'] = $group_class;
else
$node->meta['class'] .= ' ' . $group_class;
}
// Items in items aren't allowed. Wrap nested items in 'default' groups.
if ( $parent->type == 'item' && $node->type == 'item' ) {
$default_id = $parent->id . '-default';
$default = $this->_get_node( $default_id );
// The default group is added here to allow groups that are
// added before standard menu items to render first.
if ( ! $default ) {
// Use _set_node because add_node can be overloaded.
// Make sure to specify default settings for all properties.
$this->_set_node( array(
'id' => $default_id,
'parent' => $parent->id,
'type' => 'group',
'children' => array(),
'meta' => array(
'class' => $group_class,
),
'title' => false,
'href' => false,
) );
$default = $this->_get_node( $default_id );
$parent->children[] = $default;
}
$parent = $default;
// Groups in groups aren't allowed. Add a special 'container' node.
// The container will invisibly wrap both groups.
} elseif ( $parent->type == 'group' && $node->type == 'group' ) {
$container_id = $parent->id . '-container';
$container = $this->_get_node( $container_id );
// We need to create a container for this group, life is sad.
if ( ! $container ) {
// Use _set_node because add_node can be overloaded.
// Make sure to specify default settings for all properties.
$this->_set_node( array(
'id' => $container_id,
'type' => 'container',
'children' => array( $parent ),
'parent' => false,
'title' => false,
'href' => false,
'meta' => array(),
) );
$container = $this->_get_node( $container_id );
// Link the container node if a grandparent node exists.
$grandparent = $this->_get_node( $parent->parent );
if ( $grandparent ) {
$container->parent = $grandparent->id;
$index = array_search( $parent, $grandparent->children, true );
if ( $index === false )
$grandparent->children[] = $container;
else
array_splice( $grandparent->children, $index, 1, array( $container ) );
}
$parent->parent = $container->id;
}
$parent = $container;
}
// Update the parent ID (it might have changed).
$node->parent = $parent->id;
// Add the node to the tree.
$parent->children[] = $node;
}
$root = $this->_get_node( 'root' );
$this->bound = true;
return $root;
}
final protected function _render( $root ) {
global $is_IE;
// Add browser classes.
// We have to do this here since admin bar shows on the front end.
$class = 'nojq nojs';
if ( $is_IE ) {
if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 7' ) )
$class .= ' ie7';
elseif ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 8' ) )
$class .= ' ie8';
elseif ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 9' ) )
$class .= ' ie9';
} elseif ( wp_is_mobile() ) {
$class .= ' mobile';
}
?>
<div id="wpadminbar" class="<?php echo $class; ?>" role="navigation">
<a class="screen-reader-shortcut" href="#wp-toolbar" tabindex="1"><?php _e('Skip to toolbar'); ?></a>
<div class="quicklinks" id="wp-toolbar" role="navigation" aria-label="<?php esc_attr_e('Top navigation toolbar.'); ?>" tabindex="0">
<?php foreach ( $root->children as $group ) {
$this->_render_group( $group );
} ?>
</div>
<?php if ( is_user_logged_in() ) : ?>
<a class="screen-reader-shortcut" href="<?php echo esc_url( wp_logout_url() ); ?>"><?php _e('Log Out'); ?></a>
<?php endif; ?>
</div>
<?php
}
final protected function _render_container( $node ) {
if ( $node->type != 'container' || empty( $node->children ) )
return;
?><div id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>" class="ab-group-container"><?php
foreach ( $node->children as $group ) {
$this->_render_group( $group );
}
?></div><?php
}
final protected function _render_group( $node ) {
if ( $node->type == 'container' )
return $this->_render_container( $node );
if ( $node->type != 'group' || empty( $node->children ) )
return;
if ( ! empty( $node->meta['class'] ) )
$class = ' class="' . esc_attr( trim( $node->meta['class'] ) ) . '"';
else
$class = '';
?><ul id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $class; ?>><?php
foreach ( $node->children as $item ) {
$this->_render_item( $item );
}
?></ul><?php
}
final protected function _render_item( $node ) {
if ( $node->type != 'item' )
return;
$is_parent = ! empty( $node->children );
$has_link = ! empty( $node->href );
$tabindex = isset( $node->meta['tabindex'] ) ? (int) $node->meta['tabindex'] : '';
$aria_attributes = $tabindex ? 'tabindex="' . $tabindex . '"' : '';
$menuclass = '';
if ( $is_parent ) {
$menuclass = 'menupop ';
$aria_attributes .= ' aria-haspopup="true"';
}
if ( ! empty( $node->meta['class'] ) )
$menuclass .= $node->meta['class'];
if ( $menuclass )
$menuclass = ' class="' . esc_attr( trim( $menuclass ) ) . '"';
?>
<li id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $menuclass; ?>><?php
if ( $has_link ):
?><a class="ab-item" <?php echo $aria_attributes; ?> href="<?php echo esc_url( $node->href ) ?>"<?php
if ( ! empty( $node->meta['onclick'] ) ) :
?> onclick="<?php echo esc_js( $node->meta['onclick'] ); ?>"<?php
endif;
if ( ! empty( $node->meta['target'] ) ) :
?> target="<?php echo esc_attr( $node->meta['target'] ); ?>"<?php
endif;
if ( ! empty( $node->meta['title'] ) ) :
?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php
endif;
?>><?php
else:
?><div class="ab-item ab-empty-item" <?php echo $aria_attributes;
if ( ! empty( $node->meta['title'] ) ) :
?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php
endif;
?>><?php
endif;
echo $node->title;
if ( $has_link ) :
?></a><?php
else:
?></div><?php
endif;
if ( $is_parent ) :
?><div class="ab-sub-wrapper"><?php
foreach ( $node->children as $group ) {
$this->_render_group( $group );
}
?></div><?php
endif;
if ( ! empty( $node->meta['html'] ) )
echo $node->meta['html'];
?>
</li><?php
}
public function recursive_render( $id, $node ) {
_deprecated_function( __METHOD__, '3.3', 'WP_Admin_bar::render(), WP_Admin_Bar::_render_item()' );
$this->_render_item( $node );
}
public function add_menus() {
// User related, aligned right.
add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 );
add_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 );
add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 7 );
// Site related.
add_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 );
add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 );
add_action( 'admin_bar_menu', 'wp_admin_bar_site_menu', 30 );
add_action( 'admin_bar_menu', 'wp_admin_bar_updates_menu', 40 );
// Content related.
if ( ! is_network_admin() && ! is_user_admin() ) {
add_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 60 );
add_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 70 );
}
add_action( 'admin_bar_menu', 'wp_admin_bar_edit_menu', 80 );
add_action( 'admin_bar_menu', 'wp_admin_bar_add_secondary_groups', 200 );
do_action( 'add_admin_bar_menus' );
}
}

View File

@ -0,0 +1,139 @@
<?php
/**
* Send XML response back to AJAX request.
*
* @package WordPress
* @since 2.1.0
*/
class WP_Ajax_Response {
/**
* Store XML responses to send.
*
* @since 2.1.0
* @var array
* @access private
*/
var $responses = array();
/**
* Constructor - Passes args to {@link WP_Ajax_Response::add()}.
*
* @since 2.1.0
* @see WP_Ajax_Response::add()
*
* @param string|array $args Optional. Will be passed to add() method.
* @return WP_Ajax_Response
*/
function __construct( $args = '' ) {
if ( !empty($args) )
$this->add($args);
}
/**
* Append to XML response based on given arguments.
*
* The arguments that can be passed in the $args parameter are below. It is
* also possible to pass a WP_Error object in either the 'id' or 'data'
* argument. The parameter isn't actually optional, content should be given
* in order to send the correct response.
*
* 'what' argument is a string that is the XMLRPC response type.
* 'action' argument is a boolean or string that acts like a nonce.
* 'id' argument can be WP_Error or an integer.
* 'old_id' argument is false by default or an integer of the previous ID.
* 'position' argument is an integer or a string with -1 = top, 1 = bottom,
* html ID = after, -html ID = before.
* 'data' argument is a string with the content or message.
* 'supplemental' argument is an array of strings that will be children of
* the supplemental element.
*
* @since 2.1.0
*
* @param string|array $args Override defaults.
* @return string XML response.
*/
function add( $args = '' ) {
$defaults = array(
'what' => 'object', 'action' => false,
'id' => '0', 'old_id' => false,
'position' => 1,
'data' => '', 'supplemental' => array()
);
$r = wp_parse_args( $args, $defaults );
extract( $r, EXTR_SKIP );
$position = preg_replace( '/[^a-z0-9:_-]/i', '', $position );
if ( is_wp_error($id) ) {
$data = $id;
$id = 0;
}
$response = '';
if ( is_wp_error($data) ) {
foreach ( (array) $data->get_error_codes() as $code ) {
$response .= "<wp_error code='$code'><![CDATA[" . $data->get_error_message($code) . "]]></wp_error>";
if ( !$error_data = $data->get_error_data($code) )
continue;
$class = '';
if ( is_object($error_data) ) {
$class = ' class="' . get_class($error_data) . '"';
$error_data = get_object_vars($error_data);
}
$response .= "<wp_error_data code='$code'$class>";
if ( is_scalar($error_data) ) {
$response .= "<![CDATA[$error_data]]>";
} elseif ( is_array($error_data) ) {
foreach ( $error_data as $k => $v )
$response .= "<$k><![CDATA[$v]]></$k>";
}
$response .= "</wp_error_data>";
}
} else {
$response = "<response_data><![CDATA[$data]]></response_data>";
}
$s = '';
if ( is_array($supplemental) ) {
foreach ( $supplemental as $k => $v )
$s .= "<$k><![CDATA[$v]]></$k>";
$s = "<supplemental>$s</supplemental>";
}
if ( false === $action )
$action = $_POST['action'];
$x = '';
$x .= "<response action='{$action}_$id'>"; // The action attribute in the xml output is formatted like a nonce action
$x .= "<$what id='$id' " . ( false === $old_id ? '' : "old_id='$old_id' " ) . "position='$position'>";
$x .= $response;
$x .= $s;
$x .= "</$what>";
$x .= "</response>";
$this->responses[] = $x;
return $x;
}
/**
* Display XML formatted responses.
*
* Sets the content type header to text/xml.
*
* @since 2.1.0
*/
function send() {
header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ) );
echo "<?xml version='1.0' encoding='" . get_option( 'blog_charset' ) . "' standalone='yes'?><wp_ajax>";
foreach ( (array) $this->responses as $response )
echo $response;
echo '</wp_ajax>';
if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
wp_die();
else
die();
}
}

View File

@ -0,0 +1,819 @@
<?php
/**
* Customize Control Class
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Control {
/**
* @access public
* @var WP_Customize_Manager
*/
public $manager;
/**
* @access public
* @var string
*/
public $id;
/**
* All settings tied to the control.
*
* @access public
* @var array
*/
public $settings;
/**
* The primary setting for the control (if there is one).
*
* @access public
* @var string
*/
public $setting = 'default';
/**
* @access public
* @var int
*/
public $priority = 10;
/**
* @access public
* @var string
*/
public $section = '';
/**
* @access public
* @var string
*/
public $label = '';
/**
* @todo: Remove choices
*
* @access public
* @var array
*/
public $choices = array();
/**
* @access public
* @var array
*/
public $json = array();
/**
* @access public
* @var string
*/
public $type = 'text';
/**
* Constructor.
*
* If $args['settings'] is not defined, use the $id as the setting ID.
*
* @since 3.4.0
*
* @param WP_Customize_Manager $manager
* @param string $id
* @param array $args
*/
function __construct( $manager, $id, $args = array() ) {
$keys = array_keys( get_object_vars( $this ) );
foreach ( $keys as $key ) {
if ( isset( $args[ $key ] ) )
$this->$key = $args[ $key ];
}
$this->manager = $manager;
$this->id = $id;
// Process settings.
if ( empty( $this->settings ) )
$this->settings = $id;
$settings = array();
if ( is_array( $this->settings ) ) {
foreach ( $this->settings as $key => $setting ) {
$settings[ $key ] = $this->manager->get_setting( $setting );
}
} else {
$this->setting = $this->manager->get_setting( $this->settings );
$settings['default'] = $this->setting;
}
$this->settings = $settings;
}
/**
* Enqueue control related scripts/styles.
*
* @since 3.4.0
*/
public function enqueue() {}
/**
* Fetch a setting's value.
* Grabs the main setting by default.
*
* @since 3.4.0
*
* @param string $setting_key
* @return mixed The requested setting's value, if the setting exists.
*/
public final function value( $setting_key = 'default' ) {
if ( isset( $this->settings[ $setting_key ] ) )
return $this->settings[ $setting_key ]->value();
}
/**
* Refresh the parameters passed to the JavaScript via JSON.
*
* @since 3.4.0
*/
public function to_json() {
$this->json['settings'] = array();
foreach ( $this->settings as $key => $setting ) {
$this->json['settings'][ $key ] = $setting->id;
}
$this->json['type'] = $this->type;
}
/**
* Check if the theme supports the control and check user capabilities.
*
* @since 3.4.0
*
* @return bool False if theme doesn't support the control or user doesn't have the required permissions, otherwise true.
*/
public final function check_capabilities() {
foreach ( $this->settings as $setting ) {
if ( ! $setting->check_capabilities() )
return false;
}
$section = $this->manager->get_section( $this->section );
if ( isset( $section ) && ! $section->check_capabilities() )
return false;
return true;
}
/**
* Check capabilities and render the control.
*
* @since 3.4.0
* @uses WP_Customize_Control::render()
*/
public final function maybe_render() {
if ( ! $this->check_capabilities() )
return;
do_action( 'customize_render_control', $this );
do_action( 'customize_render_control_' . $this->id, $this );
$this->render();
}
/**
* Render the control. Renders the control wrapper, then calls $this->render_content().
*
* @since 3.4.0
*/
protected function render() {
$id = 'customize-control-' . str_replace( '[', '-', str_replace( ']', '', $this->id ) );
$class = 'customize-control customize-control-' . $this->type;
?><li id="<?php echo esc_attr( $id ); ?>" class="<?php echo esc_attr( $class ); ?>">
<?php $this->render_content(); ?>
</li><?php
}
/**
* Get the data link parameter for a setting.
*
* @since 3.4.0
*
* @param string $setting_key
* @return string Data link parameter, if $setting_key is a valid setting, empty string otherwise.
*/
public function get_link( $setting_key = 'default' ) {
if ( ! isset( $this->settings[ $setting_key ] ) )
return '';
return 'data-customize-setting-link="' . esc_attr( $this->settings[ $setting_key ]->id ) . '"';
}
/**
* Render the data link parameter for a setting
*
* @since 3.4.0
* @uses WP_Customize_Control::get_link()
*
* @param string $setting_key
*/
public function link( $setting_key = 'default' ) {
echo $this->get_link( $setting_key );
}
/**
* Render the control's content.
*
* Allows the content to be overriden without having to rewrite the wrapper.
*
* @since 3.4.0
*/
protected function render_content() {
switch( $this->type ) {
case 'text':
?>
<label>
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
<input type="text" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); ?> />
</label>
<?php
break;
case 'checkbox':
?>
<label>
<input type="checkbox" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); checked( $this->value() ); ?> />
<?php echo esc_html( $this->label ); ?>
</label>
<?php
break;
case 'radio':
if ( empty( $this->choices ) )
return;
$name = '_customize-radio-' . $this->id;
?>
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
<?php
foreach ( $this->choices as $value => $label ) :
?>
<label>
<input type="radio" value="<?php echo esc_attr( $value ); ?>" name="<?php echo esc_attr( $name ); ?>" <?php $this->link(); checked( $this->value(), $value ); ?> />
<?php echo esc_html( $label ); ?><br/>
</label>
<?php
endforeach;
break;
case 'select':
if ( empty( $this->choices ) )
return;
?>
<label>
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
<select <?php $this->link(); ?>>
<?php
foreach ( $this->choices as $value => $label )
echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
?>
</select>
</label>
<?php
break;
case 'dropdown-pages':
$dropdown = wp_dropdown_pages(
array(
'name' => '_customize-dropdown-pages-' . $this->id,
'echo' => 0,
'show_option_none' => __( '&mdash; Select &mdash;' ),
'option_none_value' => '0',
'selected' => $this->value(),
)
);
// Hackily add in the data link parameter.
$dropdown = str_replace( '<select', '<select ' . $this->get_link(), $dropdown );
printf(
'<label class="customize-control-select"><span class="customize-control-title">%s</span> %s</label>',
$this->label,
$dropdown
);
break;
}
}
}
/**
* Customize Color Control Class
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Color_Control extends WP_Customize_Control {
/**
* @access public
* @var string
*/
public $type = 'color';
/**
* @access public
* @var array
*/
public $statuses;
/**
* Constructor.
*
* If $args['settings'] is not defined, use the $id as the setting ID.
*
* @since 3.4.0
* @uses WP_Customize_Control::__construct()
*
* @param WP_Customize_Manager $manager
* @param string $id
* @param array $args
*/
public function __construct( $manager, $id, $args = array() ) {
$this->statuses = array( '' => __('Default') );
parent::__construct( $manager, $id, $args );
}
/**
* Enqueue control related scripts/styles.
*
* @since 3.4.0
*/
public function enqueue() {
wp_enqueue_script( 'wp-color-picker' );
wp_enqueue_style( 'wp-color-picker' );
}
/**
* Refresh the parameters passed to the JavaScript via JSON.
*
* @since 3.4.0
* @uses WP_Customize_Control::to_json()
*/
public function to_json() {
parent::to_json();
$this->json['statuses'] = $this->statuses;
}
/**
* Render the control's content.
*
* @since 3.4.0
*/
public function render_content() {
$this_default = $this->setting->default;
$default_attr = '';
if ( $this_default ) {
if ( false === strpos( $this_default, '#' ) )
$this_default = '#' . $this_default;
$default_attr = ' data-default-color="' . esc_attr( $this_default ) . '"';
}
// The input's value gets set by JS. Don't fill it.
?>
<label>
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
<div class="customize-control-content">
<input class="color-picker-hex" type="text" maxlength="7" placeholder="<?php esc_attr_e( 'Hex Value' ); ?>"<?php echo $default_attr ?> />
</div>
</label>
<?php
}
}
/**
* Customize Upload Control Class
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Upload_Control extends WP_Customize_Control {
public $type = 'upload';
public $removed = '';
public $context;
public $extensions = array();
/**
* Enqueue control related scripts/styles.
*
* @since 3.4.0
*/
public function enqueue() {
wp_enqueue_script( 'wp-plupload' );
}
/**
* Refresh the parameters passed to the JavaScript via JSON.
*
* @since 3.4.0
* @uses WP_Customize_Control::to_json()
*/
public function to_json() {
parent::to_json();
$this->json['removed'] = $this->removed;
if ( $this->context )
$this->json['context'] = $this->context;
if ( $this->extensions )
$this->json['extensions'] = implode( ',', $this->extensions );
}
/**
* Render the control's content.
*
* @since 3.4.0
*/
public function render_content() {
?>
<label>
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
<div>
<a href="#" class="button-secondary upload"><?php _e( 'Upload' ); ?></a>
<a href="#" class="remove"><?php _e( 'Remove' ); ?></a>
</div>
</label>
<?php
}
}
/**
* Customize Image Control Class
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Image_Control extends WP_Customize_Upload_Control {
public $type = 'image';
public $get_url;
public $statuses;
public $extensions = array( 'jpg', 'jpeg', 'gif', 'png' );
protected $tabs = array();
/**
* Constructor.
*
* If $args['settings'] is not defined, use the $id as the setting ID.
*
* @since 3.4.0
* @uses WP_Customize_Upload_Control::__construct()
*
* @param WP_Customize_Manager $manager
* @param string $id
* @param array $args
*/
public function __construct( $manager, $id, $args ) {
$this->statuses = array( '' => __('No Image') );
parent::__construct( $manager, $id, $args );
$this->add_tab( 'upload-new', __('Upload New'), array( $this, 'tab_upload_new' ) );
$this->add_tab( 'uploaded', __('Uploaded'), array( $this, 'tab_uploaded' ) );
// Early priority to occur before $this->manager->prepare_controls();
add_action( 'customize_controls_init', array( $this, 'prepare_control' ), 5 );
}
/**
* Prepares the control.
*
* If no tabs exist, removes the control from the manager.
*
* @since 3.4.2
*/
public function prepare_control() {
if ( ! $this->tabs )
$this->manager->remove_control( $this->id );
}
/**
* Refresh the parameters passed to the JavaScript via JSON.
*
* @since 3.4.0
* @uses WP_Customize_Upload_Control::to_json()
*/
public function to_json() {
parent::to_json();
$this->json['statuses'] = $this->statuses;
}
/**
* Render the control's content.
*
* @since 3.4.0
*/
public function render_content() {
$src = $this->value();
if ( isset( $this->get_url ) )
$src = call_user_func( $this->get_url, $src );
?>
<div class="customize-image-picker">
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
<div class="customize-control-content">
<div class="dropdown preview-thumbnail" tabindex="0">
<div class="dropdown-content">
<?php if ( empty( $src ) ): ?>
<img style="display:none;" />
<?php else: ?>
<img src="<?php echo esc_url( set_url_scheme( $src ) ); ?>" />
<?php endif; ?>
<div class="dropdown-status"></div>
</div>
<div class="dropdown-arrow"></div>
</div>
</div>
<div class="library">
<ul>
<?php foreach ( $this->tabs as $id => $tab ): ?>
<li data-customize-tab='<?php echo esc_attr( $id ); ?>' tabindex='0'>
<?php echo esc_html( $tab['label'] ); ?>
</li>
<?php endforeach; ?>
</ul>
<?php foreach ( $this->tabs as $id => $tab ): ?>
<div class="library-content" data-customize-tab='<?php echo esc_attr( $id ); ?>'>
<?php call_user_func( $tab['callback'] ); ?>
</div>
<?php endforeach; ?>
</div>
<div class="actions">
<a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>
</div>
</div>
<?php
}
/**
* Add a tab to the control.
*
* @since 3.4.0
*
* @param string $id
* @param string $label
* @param mixed $callback
*/
public function add_tab( $id, $label, $callback ) {
$this->tabs[ $id ] = array(
'label' => $label,
'callback' => $callback,
);
}
/**
* Remove a tab from the control.
*
* @since 3.4.0
*
* @param string $id
*/
public function remove_tab( $id ) {
unset( $this->tabs[ $id ] );
}
/**
* @since 3.4.0
*/
public function tab_upload_new() {
if ( ! _device_can_upload() ) {
?>
<p><?php _e('The web browser on your device cannot be used to upload files. You may be able to use the <a href="http://wordpress.org/extend/mobile/">native app for your device</a> instead.'); ?></p>
<?php
} else {
?>
<div class="upload-dropzone">
<?php _e('Drop a file here or <a href="#" class="upload">select a file</a>.'); ?>
</div>
<div class="upload-fallback">
<span class="button-secondary"><?php _e('Select File'); ?></span>
</div>
<?php
}
}
/**
* @since 3.4.0
*/
public function tab_uploaded() {
?>
<div class="uploaded-target"></div>
<?php
}
/**
* @since 3.4.0
*
* @param string $url
* @param string $thumbnail_url
*/
public function print_tab_image( $url, $thumbnail_url = null ) {
$url = set_url_scheme( $url );
$thumbnail_url = ( $thumbnail_url ) ? set_url_scheme( $thumbnail_url ) : $url;
?>
<a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $url ); ?>">
<img src="<?php echo esc_url( $thumbnail_url ); ?>" />
</a>
<?php
}
}
/**
* Customize Background Image Control Class
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Background_Image_Control extends WP_Customize_Image_Control {
/**
* Constructor.
*
* @since 3.4.0
* @uses WP_Customize_Image_Control::__construct()
*
* @param WP_Customize_Manager $manager
*/
public function __construct( $manager ) {
parent::__construct( $manager, 'background_image', array(
'label' => __( 'Background Image' ),
'section' => 'background_image',
'context' => 'custom-background',
'get_url' => 'get_background_image',
) );
if ( $this->setting->default )
$this->add_tab( 'default', __('Default'), array( $this, 'tab_default_background' ) );
}
/**
* @since 3.4.0
*/
public function tab_uploaded() {
$backgrounds = get_posts( array(
'post_type' => 'attachment',
'meta_key' => '_wp_attachment_is_custom_background',
'meta_value' => $this->manager->get_stylesheet(),
'orderby' => 'none',
'nopaging' => true,
) );
?><div class="uploaded-target"></div><?php
if ( empty( $backgrounds ) )
return;
foreach ( (array) $backgrounds as $background )
$this->print_tab_image( esc_url_raw( $background->guid ) );
}
/**
* @since 3.4.0
* @uses WP_Customize_Image_Control::print_tab_image()
*/
public function tab_default_background() {
$this->print_tab_image( $this->setting->default );
}
}
/**
* Customize Header Image Control Class
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
/**
* The processed default headers.
* @since 3.4.2
* @var array
*/
protected $default_headers;
/**
* The uploaded headers.
* @since 3.4.2
* @var array
*/
protected $uploaded_headers;
/**
* Constructor.
*
* @since 3.4.0
* @uses WP_Customize_Image_Control::__construct()
* @uses WP_Customize_Image_Control::add_tab()
*
* @param WP_Customize_Manager $manager
*/
public function __construct( $manager ) {
parent::__construct( $manager, 'header_image', array(
'label' => __( 'Header Image' ),
'settings' => array(
'default' => 'header_image',
'data' => 'header_image_data',
),
'section' => 'header_image',
'context' => 'custom-header',
'removed' => 'remove-header',
'get_url' => 'get_header_image',
'statuses' => array(
'' => __('Default'),
'remove-header' => __('No Image'),
'random-default-image' => __('Random Default Image'),
'random-uploaded-image' => __('Random Uploaded Image'),
)
) );
// Remove the upload tab.
$this->remove_tab( 'upload-new' );
}
/**
* Prepares the control.
*
* If no tabs exist, removes the control from the manager.
*
* @since 3.4.2
*/
public function prepare_control() {
global $custom_image_header;
if ( empty( $custom_image_header ) )
return parent::prepare_control();
// Process default headers and uploaded headers.
$custom_image_header->process_default_headers();
$this->default_headers = $custom_image_header->default_headers;
$this->uploaded_headers = get_uploaded_header_images();
if ( $this->default_headers )
$this->add_tab( 'default', __('Default'), array( $this, 'tab_default_headers' ) );
if ( ! $this->uploaded_headers )
$this->remove_tab( 'uploaded' );
return parent::prepare_control();
}
/**
* @since 3.4.0
*
* @param mixed $choice Which header image to select. (@see Custom_Image_Header::get_header_image() )
* @param array $header
*/
public function print_header_image( $choice, $header ) {
$header['url'] = set_url_scheme( $header['url'] );
$header['thumbnail_url'] = set_url_scheme( $header['thumbnail_url'] );
$header_image_data = array( 'choice' => $choice );
foreach ( array( 'attachment_id', 'width', 'height', 'url', 'thumbnail_url' ) as $key ) {
if ( isset( $header[ $key ] ) )
$header_image_data[ $key ] = $header[ $key ];
}
?>
<a href="#" class="thumbnail"
data-customize-image-value="<?php echo esc_url( $header['url'] ); ?>"
data-customize-header-image-data="<?php echo esc_attr( json_encode( $header_image_data ) ); ?>">
<img src="<?php echo esc_url( $header['thumbnail_url'] ); ?>" />
</a>
<?php
}
/**
* @since 3.4.0
*/
public function tab_uploaded() {
?><div class="uploaded-target"></div><?php
foreach ( $this->uploaded_headers as $choice => $header )
$this->print_header_image( $choice, $header );
}
/**
* @since 3.4.0
*/
public function tab_default_headers() {
foreach ( $this->default_headers as $choice => $header )
$this->print_header_image( $choice, $header );
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
<?php
/**
* Customize Section Class.
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Section {
public $manager;
public $id;
public $priority = 10;
public $capability = 'edit_theme_options';
public $theme_supports = '';
public $title = '';
public $description = '';
public $controls;
/**
* Constructor.
*
* @since 3.4.0
*
* @param WP_Customize_Manager $manager
* @param string $id An specific ID of the section.
* @param array $args Section arguments.
*/
function __construct( $manager, $id, $args = array() ) {
$keys = array_keys( get_class_vars( __CLASS__ ) );
foreach ( $keys as $key ) {
if ( isset( $args[ $key ] ) )
$this->$key = $args[ $key ];
}
$this->manager = $manager;
$this->id = $id;
$this->controls = array(); // Users cannot customize the $controls array.
return $this;
}
/**
* Check if the theme supports the section and check user capabilities.
*
* @since 3.4.0
*
* @return bool False if theme doesn't support the section or user doesn't have the capability.
*/
public final function check_capabilities() {
if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
return false;
if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) )
return false;
return true;
}
/**
* Check capabilities and render the section.
*
* @since 3.4.0
*/
public final function maybe_render() {
if ( ! $this->check_capabilities() )
return;
do_action( 'customize_render_section', $this );
do_action( 'customize_render_section_' . $this->id );
$this->render();
}
/**
* Render the section.
*
* @since 3.4.0
*/
protected function render() {
?>
<li id="customize-section-<?php echo esc_attr( $this->id ); ?>" class="control-section customize-section">
<h3 class="customize-section-title" tabindex="0" title="<?php echo esc_attr( $this->description ); ?>"><?php echo esc_html( $this->title ); ?></h3>
<ul class="customize-section-content">
<?php
foreach ( $this->controls as $control )
$control->maybe_render();
?>
</ul>
</li>
<?php
}
}

View File

@ -0,0 +1,439 @@
<?php
/**
* Customize Setting Class.
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Setting {
public $manager;
public $id;
public $type = 'theme_mod';
public $capability = 'edit_theme_options';
public $theme_supports = '';
public $default = '';
public $transport = 'refresh';
public $sanitize_callback = '';
public $sanitize_js_callback = '';
protected $id_data = array();
private $_post_value; // Cached, sanitized $_POST value.
/**
* Constructor.
*
* @since 3.4.0
*
* @param WP_Customize_Manager $manager
* @param string $id An specific ID of the setting. Can be a
* theme mod or option name.
* @param array $args Setting arguments.
* @return WP_Customize_Setting
*/
function __construct( $manager, $id, $args = array() ) {
$keys = array_keys( get_class_vars( __CLASS__ ) );
foreach ( $keys as $key ) {
if ( isset( $args[ $key ] ) )
$this->$key = $args[ $key ];
}
$this->manager = $manager;
$this->id = $id;
// Parse the ID for array keys.
$this->id_data[ 'keys' ] = preg_split( '/\[/', str_replace( ']', '', $this->id ) );
$this->id_data[ 'base' ] = array_shift( $this->id_data[ 'keys' ] );
// Rebuild the ID.
$this->id = $this->id_data[ 'base' ];
if ( ! empty( $this->id_data[ 'keys' ] ) )
$this->id .= '[' . implode( '][', $this->id_data[ 'keys' ] ) . ']';
if ( $this->sanitize_callback )
add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 );
if ( $this->sanitize_js_callback )
add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 );
return $this;
}
/**
* Handle previewing the setting.
*
* @since 3.4.0
*/
public function preview() {
switch( $this->type ) {
case 'theme_mod' :
add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
break;
case 'option' :
if ( empty( $this->id_data[ 'keys' ] ) )
add_filter( 'pre_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
else {
add_filter( 'option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
add_filter( 'default_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
}
break;
default :
do_action( 'customize_preview_' . $this->id );
}
}
/**
* Callback function to filter the theme mods and options.
*
* @since 3.4.0
* @uses WP_Customize_Setting::multidimensional_replace()
*
* @param mixed $original Old value.
* @return mixed New or old value.
*/
public function _preview_filter( $original ) {
return $this->multidimensional_replace( $original, $this->id_data[ 'keys' ], $this->post_value() );
}
/**
* Set the value of the parameter for a specific theme.
*
* @since 3.4.0
*
* @return bool False if cap check fails or value isn't set.
*/
public final function save() {
$value = $this->post_value();
if ( ! $this->check_capabilities() || ! isset( $value ) )
return false;
do_action( 'customize_save_' . $this->id_data[ 'base' ] );
$this->update( $value );
}
/**
* Fetches, validates, and sanitizes the $_POST value.
*
* @since 3.4.0
*
* @param mixed $default A default value which is used as a fallback. Default is null.
* @return mixed The default value on failure, otherwise the sanitized value.
*/
public final function post_value( $default = null ) {
if ( isset( $this->_post_value ) )
return $this->_post_value;
$result = $this->manager->post_value( $this );
if ( isset( $result ) )
return $this->_post_value = $result;
else
return $default;
}
/**
* Sanitize an input.
*
* @since 3.4.0
*
* @param mixed $value The value to sanitize.
* @return mixed Null if an input isn't valid, otherwise the sanitized value.
*/
public function sanitize( $value ) {
$value = stripslashes_deep( $value );
return apply_filters( "customize_sanitize_{$this->id}", $value, $this );
}
/**
* Set the value of the parameter for a specific theme.
*
* @since 3.4.0
*
* @param mixed $value The value to update.
* @return mixed The result of saving the value.
*/
protected function update( $value ) {
switch( $this->type ) {
case 'theme_mod' :
return $this->_update_theme_mod( $value );
break;
case 'option' :
return $this->_update_option( $value );
break;
default :
return do_action( 'customize_update_' . $this->type, $value );
}
}
/**
* Update the theme mod from the value of the parameter.
*
* @since 3.4.0
*
* @param mixed $value The value to update.
* @return mixed The result of saving the value.
*/
protected function _update_theme_mod( $value ) {
// Handle non-array theme mod.
if ( empty( $this->id_data[ 'keys' ] ) )
return set_theme_mod( $this->id_data[ 'base' ], $value );
// Handle array-based theme mod.
$mods = get_theme_mod( $this->id_data[ 'base' ] );
$mods = $this->multidimensional_replace( $mods, $this->id_data[ 'keys' ], $value );
if ( isset( $mods ) )
return set_theme_mod( $this->id_data[ 'base' ], $mods );
}
/**
* Update the theme mod from the value of the parameter.
*
* @since 3.4.0
*
* @param mixed $value The value to update.
* @return mixed The result of saving the value.
*/
protected function _update_option( $value ) {
// Handle non-array option.
if ( empty( $this->id_data[ 'keys' ] ) )
return update_option( $this->id_data[ 'base' ], $value );
// Handle array-based options.
$options = get_option( $this->id_data[ 'base' ] );
$options = $this->multidimensional_replace( $options, $this->id_data[ 'keys' ], $value );
if ( isset( $options ) )
return update_option( $this->id_data[ 'base' ], $options );
}
/**
* Fetch the value of the parameter for a specific theme.
*
* @since 3.4.0
*
* @return mixed The requested value.
*/
public function value() {
switch( $this->type ) {
case 'theme_mod' :
$function = 'get_theme_mod';
break;
case 'option' :
$function = 'get_option';
break;
default :
return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default );
}
// Handle non-array value
if ( empty( $this->id_data[ 'keys' ] ) )
return $function( $this->id_data[ 'base' ], $this->default );
// Handle array-based value
$values = $function( $this->id_data[ 'base' ] );
return $this->multidimensional_get( $values, $this->id_data[ 'keys' ], $this->default );
}
/**
* Escape the parameter's value for use in JavaScript.
*
* @since 3.4.0
*
* @return mixed The requested escaped value.
*/
public function js_value() {
$value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this );
if ( is_string( $value ) )
return html_entity_decode( $value, ENT_QUOTES, 'UTF-8');
return $value;
}
/**
* Check if the theme supports the setting and check user capabilities.
*
* @since 3.4.0
*
* @return bool False if theme doesn't support the setting or user can't change setting, otherwise true.
*/
public final function check_capabilities() {
if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
return false;
if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) )
return false;
return true;
}
/**
* Multidimensional helper function.
*
* @since 3.4.0
*
* @param $root
* @param $keys
* @param bool $create Default is false.
* @return null|array Keys are 'root', 'node', and 'key'.
*/
final protected function multidimensional( &$root, $keys, $create = false ) {
if ( $create && empty( $root ) )
$root = array();
if ( ! isset( $root ) || empty( $keys ) )
return;
$last = array_pop( $keys );
$node = &$root;
foreach ( $keys as $key ) {
if ( $create && ! isset( $node[ $key ] ) )
$node[ $key ] = array();
if ( ! is_array( $node ) || ! isset( $node[ $key ] ) )
return;
$node = &$node[ $key ];
}
if ( $create && ! isset( $node[ $last ] ) )
$node[ $last ] = array();
if ( ! isset( $node[ $last ] ) )
return;
return array(
'root' => &$root,
'node' => &$node,
'key' => $last,
);
}
/**
* Will attempt to replace a specific value in a multidimensional array.
*
* @since 3.4.0
*
* @param $root
* @param $keys
* @param mixed $value The value to update.
* @return
*/
final protected function multidimensional_replace( $root, $keys, $value ) {
if ( ! isset( $value ) )
return $root;
elseif ( empty( $keys ) ) // If there are no keys, we're replacing the root.
return $value;
$result = $this->multidimensional( $root, $keys, true );
if ( isset( $result ) )
$result['node'][ $result['key'] ] = $value;
return $root;
}
/**
* Will attempt to fetch a specific value from a multidimensional array.
*
* @since 3.4.0
*
* @param $root
* @param $keys
* @param $default A default value which is used as a fallback. Default is null.
* @return mixed The requested value or the default value.
*/
final protected function multidimensional_get( $root, $keys, $default = null ) {
if ( empty( $keys ) ) // If there are no keys, test the root.
return isset( $root ) ? $root : $default;
$result = $this->multidimensional( $root, $keys );
return isset( $result ) ? $result['node'][ $result['key'] ] : $default;
}
/**
* Will attempt to check if a specific value in a multidimensional array is set.
*
* @since 3.4.0
*
* @param $root
* @param $keys
* @return bool True if value is set, false if not.
*/
final protected function multidimensional_isset( $root, $keys ) {
$result = $this->multidimensional_get( $root, $keys );
return isset( $result );
}
}
/**
* A setting that is used to filter a value, but will not save the results.
*
* Results should be properly handled using another setting or callback.
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
class WP_Customize_Filter_Setting extends WP_Customize_Setting {
/**
* @since 3.4.0
*/
public function update( $value ) {}
}
/**
* A setting that is used to filter a value, but will not save the results.
*
* Results should be properly handled using another setting or callback.
*
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting {
public $id = 'header_image_data';
/**
* @since 3.4.0
*
* @param $value
*/
public function update( $value ) {
global $custom_image_header;
// If the value doesn't exist (removed or random),
// use the header_image value.
if ( ! $value )
$value = $this->manager->get_setting('header_image')->post_value();
if ( is_array( $value ) && isset( $value['choice'] ) )
$custom_image_header->set_header_image( $value['choice'] );
else
$custom_image_header->set_header_image( $value );
}
}
/**
* @package WordPress
* @subpackage Customize
* @since 3.4.0
*/
final class WP_Customize_Background_Image_Setting extends WP_Customize_Setting {
public $id = 'background_image_thumb';
/**
* @since 3.4.0
* @uses remove_theme_mod()
*
* @param $value
*/
public function update( $value ) {
remove_theme_mod( 'background_image_thumb' );
}
}

View File

@ -0,0 +1,863 @@
<?php
/**
* Facilitates adding of the WordPress editor as used on the Write and Edit screens.
*
* @package WordPress
* @since 3.3.0
*
* Private, not included by default. See wp_editor() in wp-includes/general-template.php.
*/
final class _WP_Editors {
public static $mce_locale;
private static $mce_settings = array();
private static $qt_settings = array();
private static $plugins = array();
private static $qt_buttons = array();
private static $ext_plugins;
private static $baseurl;
private static $first_init;
private static $this_tinymce = false;
private static $this_quicktags = false;
private static $has_tinymce = false;
private static $has_quicktags = false;
private static $has_medialib = false;
private static $editor_buttons_css = true;
private function __construct() {}
public static function parse_settings($editor_id, $settings) {
$set = wp_parse_args( $settings, array(
'wpautop' => true, // use wpautop?
'media_buttons' => true, // show insert/upload button(s)
'textarea_name' => $editor_id, // set the textarea name to something different, square brackets [] can be used here
'textarea_rows' => 20,
'tabindex' => '',
'tabfocus_elements' => ':prev,:next', // the previous and next element ID to move the focus to when pressing the Tab key in TinyMCE
'editor_css' => '', // intended for extra styles for both visual and Text editors buttons, needs to include the <style> tags, can use "scoped".
'editor_class' => '', // add extra class(es) to the editor textarea
'teeny' => false, // output the minimal editor config used in Press This
'dfw' => false, // replace the default fullscreen with DFW (needs specific DOM elements and css)
'tinymce' => true, // load TinyMCE, can be used to pass settings directly to TinyMCE using an array()
'quicktags' => true // load Quicktags, can be used to pass settings directly to Quicktags using an array()
) );
self::$this_tinymce = ( $set['tinymce'] && user_can_richedit() );
self::$this_quicktags = (bool) $set['quicktags'];
if ( self::$this_tinymce )
self::$has_tinymce = true;
if ( self::$this_quicktags )
self::$has_quicktags = true;
if ( empty( $set['editor_height'] ) )
return $set;
if ( 'content' === $editor_id ) {
// A cookie (set when a user resizes the editor) overrides the height.
$cookie = (int) get_user_setting( 'ed_size' );
// Upgrade an old TinyMCE cookie if it is still around, and the new one isn't.
if ( ! $cookie && isset( $_COOKIE['TinyMCE_content_size'] ) ) {
parse_str( $_COOKIE['TinyMCE_content_size'], $cookie );
$cookie = $cookie['ch'];
}
if ( $cookie )
$set['editor_height'] = $cookie;
}
if ( $set['editor_height'] < 50 )
$set['editor_height'] = 50;
elseif ( $set['editor_height'] > 5000 )
$set['editor_height'] = 5000;
return $set;
}
/**
* Outputs the HTML for a single instance of the editor.
*
* @param string $content The initial content of the editor.
* @param string $editor_id ID for the textarea and TinyMCE and Quicktags instances (can contain only ASCII letters and numbers).
* @param array $settings See the _parse_settings() method for description.
*/
public static function editor( $content, $editor_id, $settings = array() ) {
$set = self::parse_settings($editor_id, $settings);
$editor_class = ' class="' . trim( $set['editor_class'] . ' wp-editor-area' ) . '"';
$tabindex = $set['tabindex'] ? ' tabindex="' . (int) $set['tabindex'] . '"' : '';
$switch_class = 'html-active';
$toolbar = $buttons = '';
if ( ! empty( $set['editor_height'] ) )
$height = ' style="height: ' . $set['editor_height'] . 'px"';
else
$height = ' rows="' . $set['textarea_rows'] . '"';
if ( !current_user_can( 'upload_files' ) )
$set['media_buttons'] = false;
if ( self::$this_quicktags && self::$this_tinymce ) {
$switch_class = 'html-active';
// 'html' and 'switch-html' are used for the "Text" editor tab.
if ( 'html' == wp_default_editor() ) {
add_filter('the_editor_content', 'wp_htmledit_pre');
} else {
add_filter('the_editor_content', 'wp_richedit_pre');
$switch_class = 'tmce-active';
}
$buttons .= '<a id="' . $editor_id . '-html" class="wp-switch-editor switch-html" onclick="switchEditors.switchto(this);">' . _x( 'Text', 'Name for the Text editor tab (formerly HTML)' ) . "</a>\n";
$buttons .= '<a id="' . $editor_id . '-tmce" class="wp-switch-editor switch-tmce" onclick="switchEditors.switchto(this);">' . __('Visual') . "</a>\n";
}
echo '<div id="wp-' . $editor_id . '-wrap" class="wp-core-ui wp-editor-wrap ' . $switch_class . '">';
if ( self::$editor_buttons_css ) {
wp_print_styles('editor-buttons');
self::$editor_buttons_css = false;
}
if ( !empty($set['editor_css']) )
echo $set['editor_css'] . "\n";
if ( !empty($buttons) || $set['media_buttons'] ) {
echo '<div id="wp-' . $editor_id . '-editor-tools" class="wp-editor-tools hide-if-no-js">';
echo $buttons;
if ( $set['media_buttons'] ) {
self::$has_medialib = true;
if ( !function_exists('media_buttons') )
include(ABSPATH . 'wp-admin/includes/media.php');
echo '<div id="wp-' . $editor_id . '-media-buttons" class="wp-media-buttons">';
do_action('media_buttons', $editor_id);
echo "</div>\n";
}
echo "</div>\n";
}
$the_editor = apply_filters('the_editor', '<div id="wp-' . $editor_id . '-editor-container" class="wp-editor-container"><textarea' . $editor_class . $height . $tabindex . ' cols="40" name="' . $set['textarea_name'] . '" id="' . $editor_id . '">%s</textarea></div>');
$content = apply_filters('the_editor_content', $content);
printf($the_editor, $content);
echo "\n</div>\n\n";
self::editor_settings($editor_id, $set);
}
public static function editor_settings($editor_id, $set) {
global $editor_styles;
$first_run = false;
if ( empty(self::$first_init) ) {
if ( is_admin() ) {
add_action( 'admin_print_footer_scripts', array( __CLASS__, 'editor_js'), 50 );
add_action( 'admin_footer', array( __CLASS__, 'enqueue_scripts'), 1 );
} else {
add_action( 'wp_print_footer_scripts', array( __CLASS__, 'editor_js'), 50 );
add_action( 'wp_footer', array( __CLASS__, 'enqueue_scripts'), 1 );
}
}
if ( self::$this_quicktags ) {
$qtInit = array(
'id' => $editor_id,
'buttons' => ''
);
if ( is_array($set['quicktags']) )
$qtInit = array_merge($qtInit, $set['quicktags']);
if ( empty($qtInit['buttons']) )
$qtInit['buttons'] = 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,spell,close';
if ( $set['dfw'] )
$qtInit['buttons'] .= ',fullscreen';
$qtInit = apply_filters('quicktags_settings', $qtInit, $editor_id);
self::$qt_settings[$editor_id] = $qtInit;
self::$qt_buttons = array_merge( self::$qt_buttons, explode(',', $qtInit['buttons']) );
}
if ( self::$this_tinymce ) {
if ( empty(self::$first_init) ) {
self::$baseurl = includes_url('js/tinymce');
self::$mce_locale = $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
$no_captions = (bool) apply_filters( 'disable_captions', '' );
$plugins = array( 'inlinepopups', 'spellchecker', 'tabfocus', 'paste', 'media', 'fullscreen', 'wordpress', 'wpeditimage', 'wpgallery', 'wplink', 'wpdialogs' );
$first_run = true;
$ext_plugins = '';
if ( $set['teeny'] ) {
self::$plugins = $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs' ), $editor_id );
} else {
/*
The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
The url should be absolute and should include the js file name to be loaded. Example:
array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
*/
$mce_external_plugins = apply_filters('mce_external_plugins', array());
if ( ! empty($mce_external_plugins) ) {
/*
The following filter loads external language files for TinyMCE plugins.
It takes an associative array 'plugin_name' => 'path', where path is the
include path to the file. The language file should follow the same format as
/tinymce/langs/wp-langs.php and should define a variable $strings that
holds all translated strings.
When this filter is not used, the function will try to load {mce_locale}.js.
If that is not found, en.js will be tried next.
*/
$mce_external_languages = apply_filters('mce_external_languages', array());
$loaded_langs = array();
$strings = '';
if ( ! empty($mce_external_languages) ) {
foreach ( $mce_external_languages as $name => $path ) {
if ( @is_file($path) && @is_readable($path) ) {
include_once($path);
$ext_plugins .= $strings . "\n";
$loaded_langs[] = $name;
}
}
}
foreach ( $mce_external_plugins as $name => $url ) {
$url = set_url_scheme( $url );
$plugins[] = '-' . $name;
$plugurl = dirname($url);
$strings = $str1 = $str2 = '';
if ( ! in_array($name, $loaded_langs) ) {
$path = str_replace( content_url(), '', $plugurl );
$path = WP_CONTENT_DIR . $path . '/langs/';
if ( function_exists('realpath') )
$path = trailingslashit( realpath($path) );
if ( @is_file($path . $mce_locale . '.js') )
$strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
if ( @is_file($path . $mce_locale . '_dlg.js') )
$strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
if ( 'en' != $mce_locale && empty($strings) ) {
if ( @is_file($path . 'en.js') ) {
$str1 = @file_get_contents($path . 'en.js');
$strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
}
if ( @is_file($path . 'en_dlg.js') ) {
$str2 = @file_get_contents($path . 'en_dlg.js');
$strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
}
}
if ( ! empty($strings) )
$ext_plugins .= "\n" . $strings . "\n";
}
$ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
$ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
}
}
$plugins = array_unique( apply_filters('tiny_mce_plugins', $plugins) );
}
if ( $set['dfw'] )
$plugins[] = 'wpfullscreen';
self::$plugins = $plugins;
self::$ext_plugins = $ext_plugins;
/*
translators: These languages show up in the spellchecker drop-down menu, in the order specified, and with the first
language listed being the default language. They must be comma-separated and take the format of name=code, where name
is the language name (which you may internationalize), and code is a valid ISO 639 language code. Please test the
spellchecker with your values.
*/
$mce_spellchecker_languages = __( 'English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv' );
/*
The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
The + sign marks the default language. More: http://www.tinymce.com/wiki.php/Plugin:spellchecker.
*/
$mce_spellchecker_languages = apply_filters( 'mce_spellchecker_languages', '+' . $mce_spellchecker_languages );
self::$first_init = array(
'mode' => 'exact',
'width' => '100%',
'theme' => 'advanced',
'skin' => 'wp_theme',
'language' => self::$mce_locale,
'spellchecker_languages' => $mce_spellchecker_languages,
'theme_advanced_toolbar_location' => 'top',
'theme_advanced_toolbar_align' => 'left',
'theme_advanced_statusbar_location' => 'bottom',
'theme_advanced_resizing' => true,
'theme_advanced_resize_horizontal' => false,
'dialog_type' => 'modal',
'formats' => "{
alignleft : [
{selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}},
{selector : 'img,table', classes : 'alignleft'}
],
aligncenter : [
{selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}},
{selector : 'img,table', classes : 'aligncenter'}
],
alignright : [
{selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}},
{selector : 'img,table', classes : 'alignright'}
],
strikethrough : {inline : 'del'}
}",
'relative_urls' => false,
'remove_script_host' => false,
'convert_urls' => false,
'remove_linebreaks' => true,
'gecko_spellcheck' => true,
'fix_list_elements' => true,
'keep_styles' => false,
'entities' => '38,amp,60,lt,62,gt',
'accessibility_focus' => true,
'media_strict' => false,
'paste_remove_styles' => true,
'paste_remove_spans' => true,
'paste_strip_class_attributes' => 'all',
'paste_text_use_dialog' => true,
'webkit_fake_resize' => false,
'spellchecker_rpc_url' => self::$baseurl . '/plugins/spellchecker/rpc.php',
'schema' => 'html5',
'wpeditimage_disable_captions' => $no_captions,
'wp_fullscreen_content_css' => self::$baseurl . '/plugins/wpfullscreen/css/wp-fullscreen.css',
'plugins' => implode( ',', $plugins )
);
// load editor_style.css if the current theme supports it
if ( ! empty( $editor_styles ) && is_array( $editor_styles ) ) {
$mce_css = array();
$editor_styles = array_unique($editor_styles);
$style_uri = get_stylesheet_directory_uri();
$style_dir = get_stylesheet_directory();
if ( is_child_theme() ) {
$template_uri = get_template_directory_uri();
$template_dir = get_template_directory();
foreach ( $editor_styles as $key => $file ) {
if ( $file && file_exists( "$template_dir/$file" ) )
$mce_css[] = "$template_uri/$file";
}
}
foreach ( $editor_styles as $file ) {
if ( $file && file_exists( "$style_dir/$file" ) )
$mce_css[] = "$style_uri/$file";
}
$mce_css = implode( ',', $mce_css );
} else {
$mce_css = '';
}
$mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
if ( ! empty($mce_css) )
self::$first_init['content_css'] = $mce_css;
}
if ( $set['teeny'] ) {
$mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold', 'italic', 'underline', 'blockquote', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'undo', 'redo', 'link', 'unlink', 'fullscreen'), $editor_id );
$mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = array();
} else {
$mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', 'bullist', 'numlist', 'blockquote', 'justifyleft', 'justifycenter', 'justifyright', 'link', 'unlink', 'wp_more', 'spellchecker', 'fullscreen', 'wp_adv' ), $editor_id);
$mce_buttons_2 = apply_filters('mce_buttons_2', array( 'formatselect', 'underline', 'justifyfull', 'forecolor', 'pastetext', 'pasteword', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo', 'wp_help' ), $editor_id);
$mce_buttons_3 = apply_filters('mce_buttons_3', array(), $editor_id);
$mce_buttons_4 = apply_filters('mce_buttons_4', array(), $editor_id);
}
$body_class = $editor_id;
if ( $post = get_post() )
$body_class .= ' post-type-' . $post->post_type;
if ( !empty($set['tinymce']['body_class']) ) {
$body_class .= ' ' . $set['tinymce']['body_class'];
unset($set['tinymce']['body_class']);
}
if ( $set['dfw'] ) {
// replace the first 'fullscreen' with 'wp_fullscreen'
if ( ($key = array_search('fullscreen', $mce_buttons)) !== false )
$mce_buttons[$key] = 'wp_fullscreen';
elseif ( ($key = array_search('fullscreen', $mce_buttons_2)) !== false )
$mce_buttons_2[$key] = 'wp_fullscreen';
elseif ( ($key = array_search('fullscreen', $mce_buttons_3)) !== false )
$mce_buttons_3[$key] = 'wp_fullscreen';
elseif ( ($key = array_search('fullscreen', $mce_buttons_4)) !== false )
$mce_buttons_4[$key] = 'wp_fullscreen';
}
$mceInit = array (
'elements' => $editor_id,
'wpautop' => (bool) $set['wpautop'],
'remove_linebreaks' => (bool) $set['wpautop'],
'apply_source_formatting' => (bool) !$set['wpautop'],
'theme_advanced_buttons1' => implode($mce_buttons, ','),
'theme_advanced_buttons2' => implode($mce_buttons_2, ','),
'theme_advanced_buttons3' => implode($mce_buttons_3, ','),
'theme_advanced_buttons4' => implode($mce_buttons_4, ','),
'tabfocus_elements' => $set['tabfocus_elements'],
'body_class' => $body_class
);
// The main editor doesn't use the TinyMCE resizing cookie.
$mceInit['theme_advanced_resizing_use_cookie'] = 'content' !== $editor_id || empty( $set['editor_height'] );
if ( $first_run )
$mceInit = array_merge(self::$first_init, $mceInit);
if ( is_array($set['tinymce']) )
$mceInit = array_merge($mceInit, $set['tinymce']);
// For people who really REALLY know what they're doing with TinyMCE
// You can modify $mceInit to add, remove, change elements of the config before tinyMCE.init
// Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through this filter.
// Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
if ( $set['teeny'] ) {
$mceInit = apply_filters('teeny_mce_before_init', $mceInit, $editor_id);
} else {
$mceInit = apply_filters('tiny_mce_before_init', $mceInit, $editor_id);
}
if ( empty($mceInit['theme_advanced_buttons3']) && !empty($mceInit['theme_advanced_buttons4']) ) {
$mceInit['theme_advanced_buttons3'] = $mceInit['theme_advanced_buttons4'];
$mceInit['theme_advanced_buttons4'] = '';
}
self::$mce_settings[$editor_id] = $mceInit;
} // end if self::$this_tinymce
}
private static function _parse_init($init) {
$options = '';
foreach ( $init as $k => $v ) {
if ( is_bool($v) ) {
$val = $v ? 'true' : 'false';
$options .= $k . ':' . $val . ',';
continue;
} elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
$options .= $k . ':' . $v . ',';
continue;
}
$options .= $k . ':"' . $v . '",';
}
return '{' . trim( $options, ' ,' ) . '}';
}
public static function enqueue_scripts() {
wp_enqueue_script('word-count');
if ( self::$has_tinymce )
wp_enqueue_script('editor');
if ( self::$has_quicktags )
wp_enqueue_script('quicktags');
if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) ) {
wp_enqueue_script('wplink');
wp_enqueue_script('wpdialogs-popup');
wp_enqueue_style('wp-jquery-ui-dialog');
}
if ( in_array('wpfullscreen', self::$plugins, true) || in_array('fullscreen', self::$qt_buttons, true) )
wp_enqueue_script('wp-fullscreen');
if ( self::$has_medialib ) {
add_thickbox();
wp_enqueue_script('media-upload');
}
}
public static function editor_js() {
global $tinymce_version, $concatenate_scripts, $compress_scripts;
/**
* Filter "tiny_mce_version" is deprecated
*
* The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
* These plugins can be refreshed by appending query string to the URL passed to "mce_external_plugins" filter.
* If the plugin has a popup dialog, a query string can be added to the button action that opens it (in the plugin's code).
*/
$version = 'ver=' . $tinymce_version;
$tmce_on = !empty(self::$mce_settings);
if ( ! isset($concatenate_scripts) )
script_concat_settings();
$compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
&& false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
if ( $tmce_on && 'en' != self::$mce_locale )
include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
$mceInit = $qtInit = '';
if ( $tmce_on ) {
foreach ( self::$mce_settings as $editor_id => $init ) {
$options = self::_parse_init( $init );
$mceInit .= "'$editor_id':{$options},";
}
$mceInit = '{' . trim($mceInit, ',') . '}';
} else {
$mceInit = '{}';
}
if ( !empty(self::$qt_settings) ) {
foreach ( self::$qt_settings as $editor_id => $init ) {
$options = self::_parse_init( $init );
$qtInit .= "'$editor_id':{$options},";
}
$qtInit = '{' . trim($qtInit, ',') . '}';
} else {
$qtInit = '{}';
}
$ref = array(
'plugins' => implode( ',', self::$plugins ),
'theme' => 'advanced',
'language' => self::$mce_locale
);
$suffix = ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) ? '_src' : '';
do_action('before_wp_tiny_mce', self::$mce_settings);
?>
<script type="text/javascript">
tinyMCEPreInit = {
base : "<?php echo self::$baseurl; ?>",
suffix : "<?php echo $suffix; ?>",
query : "<?php echo $version; ?>",
mceInit : <?php echo $mceInit; ?>,
qtInit : <?php echo $qtInit; ?>,
ref : <?php echo self::_parse_init( $ref ); ?>,
load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
};
</script>
<?php
$baseurl = self::$baseurl;
if ( $tmce_on ) {
if ( $compressed ) {
echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&amp;$version'></script>\n";
} else {
echo "<script type='text/javascript' src='{$baseurl}/tiny_mce.js?$version'></script>\n";
echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce-schema.js?$version'></script>\n";
}
if ( 'en' != self::$mce_locale && isset($lang) )
echo "<script type='text/javascript'>\n$lang\n</script>\n";
else
echo "<script type='text/javascript' src='{$baseurl}/langs/wp-langs-en.js?$version'></script>\n";
}
$mce = ( self::$has_tinymce && wp_default_editor() == 'tinymce' ) || ! self::$has_quicktags;
?>
<script type="text/javascript">
var wpActiveEditor;
(function(){
var init, ed, qt, first_init, DOM, el, i, mce = <?php echo (int) $mce; ?>;
if ( typeof(tinymce) == 'object' ) {
DOM = tinymce.DOM;
// mark wp_theme/ui.css as loaded
DOM.files[tinymce.baseURI.getURI() + '/themes/advanced/skins/wp_theme/ui.css'] = true;
DOM.events.add( DOM.select('.wp-editor-wrap'), 'mousedown', function(e){
if ( this.id )
wpActiveEditor = this.id.slice(3, -5);
});
for ( ed in tinyMCEPreInit.mceInit ) {
if ( first_init ) {
init = tinyMCEPreInit.mceInit[ed] = tinymce.extend( {}, first_init, tinyMCEPreInit.mceInit[ed] );
} else {
init = first_init = tinyMCEPreInit.mceInit[ed];
}
if ( mce )
try { tinymce.init(init); } catch(e){}
}
} else {
if ( tinyMCEPreInit.qtInit ) {
for ( i in tinyMCEPreInit.qtInit ) {
el = tinyMCEPreInit.qtInit[i].id;
if ( el )
document.getElementById('wp-'+el+'-wrap').onmousedown = function(){ wpActiveEditor = this.id.slice(3, -5); }
}
}
}
if ( typeof(QTags) == 'function' ) {
for ( qt in tinyMCEPreInit.qtInit ) {
try { quicktags( tinyMCEPreInit.qtInit[qt] ); } catch(e){}
}
}
})();
<?php
if ( self::$ext_plugins )
echo self::$ext_plugins . "\n";
if ( ! $compressed && $tmce_on ) {
?>
(function(){var t=tinyMCEPreInit,sl=tinymce.ScriptLoader,ln=t.ref.language,th=t.ref.theme,pl=t.ref.plugins;sl.markDone(t.base+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'_dlg.js');sl.markDone(t.base+'/themes/advanced/skins/wp_theme/ui.css');tinymce.each(pl.split(','),function(n){if(n&&n.charAt(0)!='-'){sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'.js');sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'_dlg.js');}});})();
<?php
}
if ( !is_admin() )
echo 'var ajaxurl = "' . admin_url( 'admin-ajax.php', 'relative' ) . '";';
?>
</script>
<?php
if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) )
self::wp_link_dialog();
if ( in_array('wpfullscreen', self::$plugins, true) || in_array('fullscreen', self::$qt_buttons, true) )
self::wp_fullscreen_html();
do_action('after_wp_tiny_mce', self::$mce_settings);
}
public static function wp_fullscreen_html() {
global $content_width;
$post = get_post();
$width = isset($content_width) && 800 > $content_width ? $content_width : 800;
$width = $width + 22; // compensate for the padding and border
$dfw_width = get_user_setting( 'dfw_width', $width );
$save = isset($post->post_status) && $post->post_status == 'publish' ? __('Update') : __('Save');
?>
<div id="wp-fullscreen-body"<?php if ( is_rtl() ) echo ' class="rtl"'; ?>>
<div id="fullscreen-topbar">
<div id="wp-fullscreen-toolbar">
<div id="wp-fullscreen-close"><a href="#" onclick="fullscreen.off();return false;"><?php _e('Exit fullscreen'); ?></a></div>
<div id="wp-fullscreen-central-toolbar" style="width:<?php echo $width; ?>px;">
<div id="wp-fullscreen-mode-bar"><div id="wp-fullscreen-modes">
<a href="#" onclick="fullscreen.switchmode('tinymce');return false;"><?php _e( 'Visual' ); ?></a>
<a href="#" onclick="fullscreen.switchmode('html');return false;"><?php _ex( 'Text', 'Name for the Text editor tab (formerly HTML)' ); ?></a>
</div></div>
<div id="wp-fullscreen-button-bar"><div id="wp-fullscreen-buttons" class="wp_themeSkin">
<?php
$buttons = array(
// format: title, onclick, show in both editors
'bold' => array( 'title' => __('Bold (Ctrl + B)'), 'onclick' => 'fullscreen.b();', 'both' => false ),
'italic' => array( 'title' => __('Italic (Ctrl + I)'), 'onclick' => 'fullscreen.i();', 'both' => false ),
'0' => 'separator',
'bullist' => array( 'title' => __('Unordered list (Alt + Shift + U)'), 'onclick' => 'fullscreen.ul();', 'both' => false ),
'numlist' => array( 'title' => __('Ordered list (Alt + Shift + O)'), 'onclick' => 'fullscreen.ol();', 'both' => false ),
'1' => 'separator',
'blockquote' => array( 'title' => __('Blockquote (Alt + Shift + Q)'), 'onclick' => 'fullscreen.blockquote();', 'both' => false ),
'image' => array( 'title' => __('Insert/edit image (Alt + Shift + M)'), 'onclick' => "fullscreen.medialib();", 'both' => true ),
'2' => 'separator',
'link' => array( 'title' => __('Insert/edit link (Alt + Shift + A)'), 'onclick' => 'fullscreen.link();', 'both' => true ),
'unlink' => array( 'title' => __('Unlink (Alt + Shift + S)'), 'onclick' => 'fullscreen.unlink();', 'both' => false ),
'3' => 'separator',
'help' => array( 'title' => __('Help (Alt + Shift + H)'), 'onclick' => 'fullscreen.help();', 'both' => false )
);
$buttons = apply_filters( 'wp_fullscreen_buttons', $buttons );
foreach ( $buttons as $button => $args ) {
if ( 'separator' == $args ) { ?>
<div><span aria-orientation="vertical" role="separator" class="mceSeparator"></span></div>
<?php continue;
} ?>
<div<?php if ( $args['both'] ) { ?> class="wp-fullscreen-both"<?php } ?>>
<a title="<?php echo $args['title']; ?>" onclick="<?php echo $args['onclick']; ?>return false;" class="mceButton mceButtonEnabled mce_<?php echo $button; ?>" href="#" id="wp_fs_<?php echo $button; ?>" role="button" aria-pressed="false">
<span class="mceIcon mce_<?php echo $button; ?>"></span>
</a>
</div>
<?php
} ?>
</div></div>
<div id="wp-fullscreen-save">
<input type="button" class="button-primary right" value="<?php echo $save; ?>" onclick="fullscreen.save();" />
<span class="spinner"></span>
<span class="fs-saved"><?php if ( $post->post_status == 'publish' ) _e('Updated.'); else _e('Saved.'); ?></span>
</div>
</div>
</div>
</div>
<div id="wp-fullscreen-wrap" style="width:<?php echo $dfw_width; ?>px;">
<?php if ( post_type_supports($post->post_type, 'title') ) { ?>
<label id="wp-fullscreen-title-prompt-text" for="wp-fullscreen-title"><?php echo apply_filters( 'enter_title_here', __( 'Enter title here' ), $post ); ?></label>
<input type="text" id="wp-fullscreen-title" value="" autocomplete="off" />
<?php } ?>
<div id="wp-fullscreen-container">
<textarea id="wp_mce_fullscreen"></textarea>
</div>
<div id="wp-fullscreen-status">
<div id="wp-fullscreen-count"><?php printf( __( 'Word count: %s' ), '<span class="word-count">0</span>' ); ?></div>
<div id="wp-fullscreen-tagline"><?php _e('Just write.'); ?></div>
</div>
</div>
</div>
<div class="fullscreen-overlay" id="fullscreen-overlay"></div>
<div class="fullscreen-overlay fullscreen-fader fade-600" id="fullscreen-fader"></div>
<?php
}
/**
* Performs post queries for internal linking.
*
* @since 3.1.0
*
* @param array $args Optional. Accepts 'pagenum' and 's' (search) arguments.
* @return array Results.
*/
public static function wp_link_query( $args = array() ) {
$pts = get_post_types( array( 'public' => true ), 'objects' );
$pt_names = array_keys( $pts );
$query = array(
'post_type' => $pt_names,
'suppress_filters' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'post_status' => 'publish',
'order' => 'DESC',
'orderby' => 'post_date',
'posts_per_page' => 20,
);
$args['pagenum'] = isset( $args['pagenum'] ) ? absint( $args['pagenum'] ) : 1;
if ( isset( $args['s'] ) )
$query['s'] = $args['s'];
$query['offset'] = $args['pagenum'] > 1 ? $query['posts_per_page'] * ( $args['pagenum'] - 1 ) : 0;
// Do main query.
$get_posts = new WP_Query;
$posts = $get_posts->query( $query );
// Check if any posts were found.
if ( ! $get_posts->post_count )
return false;
// Build results.
$results = array();
foreach ( $posts as $post ) {
if ( 'post' == $post->post_type )
$info = mysql2date( __( 'Y/m/d' ), $post->post_date );
else
$info = $pts[ $post->post_type ]->labels->singular_name;
$results[] = array(
'ID' => $post->ID,
'title' => trim( esc_html( strip_tags( get_the_title( $post ) ) ) ),
'permalink' => get_permalink( $post->ID ),
'info' => $info,
);
}
return $results;
}
/**
* Dialog for internal linking.
*
* @since 3.1.0
*/
public static function wp_link_dialog() {
?>
<div style="display:none;">
<form id="wp-link" tabindex="-1">
<?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?>
<div id="link-selector">
<div id="link-options">
<p class="howto"><?php _e( 'Enter the destination URL' ); ?></p>
<div>
<label><span><?php _e( 'URL' ); ?></span><input id="url-field" type="text" name="href" /></label>
</div>
<div>
<label><span><?php _e( 'Title' ); ?></span><input id="link-title-field" type="text" name="linktitle" /></label>
</div>
<div class="link-target">
<label><input type="checkbox" id="link-target-checkbox" /> <?php _e( 'Open link in a new window/tab' ); ?></label>
</div>
</div>
<?php $show_internal = '1' == get_user_setting( 'wplink', '0' ); ?>
<p class="howto toggle-arrow <?php if ( $show_internal ) echo 'toggle-arrow-active'; ?>" id="internal-toggle"><?php _e( 'Or link to existing content' ); ?></p>
<div id="search-panel"<?php if ( ! $show_internal ) echo ' style="display:none"'; ?>>
<div class="link-search-wrapper">
<label>
<span class="search-label"><?php _e( 'Search' ); ?></span>
<input type="search" id="search-field" class="link-search-field" autocomplete="off" />
<span class="spinner"></span>
</label>
</div>
<div id="search-results" class="query-results">
<ul></ul>
<div class="river-waiting">
<span class="spinner"></span>
</div>
</div>
<div id="most-recent-results" class="query-results">
<div class="query-notice"><em><?php _e( 'No search term specified. Showing recent items.' ); ?></em></div>
<ul></ul>
<div class="river-waiting">
<span class="spinner"></span>
</div>
</div>
</div>
</div>
<div class="submitbox">
<div id="wp-link-update">
<input type="submit" value="<?php esc_attr_e( 'Add Link' ); ?>" class="button-primary" id="wp-link-submit" name="wp-link-submit">
</div>
<div id="wp-link-cancel">
<a class="submitdelete deletion" href="#"><?php _e( 'Cancel' ); ?></a>
</div>
</div>
</form>
</div>
<?php
}
}

View File

@ -0,0 +1,277 @@
<?php
/**
* API for easily embedding rich media such as videos and images into content.
*
* @package WordPress
* @subpackage Embed
* @since 2.9.0
*/
class WP_Embed {
var $handlers = array();
var $post_ID;
var $usecache = true;
var $linkifunknown = true;
/**
* Constructor
*/
function __construct() {
// Hack to get the [embed] shortcode to run before wpautop()
add_filter( 'the_content', array( $this, 'run_shortcode' ), 8 );
// Shortcode placeholder for strip_shortcodes()
add_shortcode( 'embed', '__return_false' );
// Attempts to embed all URLs in a post
add_filter( 'the_content', array( $this, 'autoembed' ), 8 );
// When a post is saved, invalidate the oEmbed cache
add_action( 'pre_post_update', array( $this, 'delete_oembed_caches' ) );
// After a post is saved, cache oEmbed items via AJAX
add_action( 'edit_form_advanced', array( $this, 'maybe_run_ajax_cache' ) );
}
/**
* Process the [embed] shortcode.
*
* Since the [embed] shortcode needs to be run earlier than other shortcodes,
* this function removes all existing shortcodes, registers the [embed] shortcode,
* calls {@link do_shortcode()}, and then re-registers the old shortcodes.
*
* @uses $shortcode_tags
* @uses remove_all_shortcodes()
* @uses add_shortcode()
* @uses do_shortcode()
*
* @param string $content Content to parse
* @return string Content with shortcode parsed
*/
function run_shortcode( $content ) {
global $shortcode_tags;
// Back up current registered shortcodes and clear them all out
$orig_shortcode_tags = $shortcode_tags;
remove_all_shortcodes();
add_shortcode( 'embed', array( $this, 'shortcode' ) );
// Do the shortcode (only the [embed] one is registered)
$content = do_shortcode( $content );
// Put the original shortcodes back
$shortcode_tags = $orig_shortcode_tags;
return $content;
}
/**
* If a post/page was saved, then output JavaScript to make
* an AJAX request that will call WP_Embed::cache_oembed().
*/
function maybe_run_ajax_cache() {
$post = get_post();
if ( ! $post || empty($_GET['message']) || 1 != $_GET['message'] )
return;
?>
<script type="text/javascript">
/* <![CDATA[ */
jQuery(document).ready(function($){
$.get("<?php echo admin_url( 'admin-ajax.php?action=oembed-cache&post=' . $post->ID, 'relative' ); ?>");
});
/* ]]> */
</script>
<?php
}
/**
* Register an embed handler. Do not use this function directly, use {@link wp_embed_register_handler()} instead.
* This function should probably also only be used for sites that do not support oEmbed.
*
* @param string $id An internal ID/name for the handler. Needs to be unique.
* @param string $regex The regex that will be used to see if this handler should be used for a URL.
* @param callback $callback The callback function that will be called if the regex is matched.
* @param int $priority Optional. Used to specify the order in which the registered handlers will be tested (default: 10). Lower numbers correspond with earlier testing, and handlers with the same priority are tested in the order in which they were added to the action.
*/
function register_handler( $id, $regex, $callback, $priority = 10 ) {
$this->handlers[$priority][$id] = array(
'regex' => $regex,
'callback' => $callback,
);
}
/**
* Unregister a previously registered embed handler. Do not use this function directly, use {@link wp_embed_unregister_handler()} instead.
*
* @param string $id The handler ID that should be removed.
* @param int $priority Optional. The priority of the handler to be removed (default: 10).
*/
function unregister_handler( $id, $priority = 10 ) {
if ( isset($this->handlers[$priority][$id]) )
unset($this->handlers[$priority][$id]);
}
/**
* The {@link do_shortcode()} callback function.
*
* Attempts to convert a URL into embed HTML. Starts by checking the URL against the regex of the registered embed handlers.
* If none of the regex matches and it's enabled, then the URL will be given to the {@link WP_oEmbed} class.
*
* @uses wp_oembed_get()
* @uses wp_parse_args()
* @uses wp_embed_defaults()
* @uses WP_Embed::maybe_make_link()
* @uses get_option()
* @uses author_can()
* @uses wp_cache_get()
* @uses wp_cache_set()
* @uses get_post_meta()
* @uses update_post_meta()
*
* @param array $attr Shortcode attributes.
* @param string $url The URL attempting to be embedded.
* @return string The embed HTML on success, otherwise the original URL.
*/
function shortcode( $attr, $url = '' ) {
$post = get_post();
if ( empty( $url ) )
return '';
$rawattr = $attr;
$attr = wp_parse_args( $attr, wp_embed_defaults() );
// kses converts & into &amp; and we need to undo this
// See http://core.trac.wordpress.org/ticket/11311
$url = str_replace( '&amp;', '&', $url );
// Look for known internal handlers
ksort( $this->handlers );
foreach ( $this->handlers as $priority => $handlers ) {
foreach ( $handlers as $id => $handler ) {
if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) {
if ( false !== $return = call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ) )
return apply_filters( 'embed_handler_html', $return, $url, $attr );
}
}
}
$post_ID = ( ! empty( $post->ID ) ) ? $post->ID : null;
if ( ! empty( $this->post_ID ) ) // Potentially set by WP_Embed::cache_oembed()
$post_ID = $this->post_ID;
// Unknown URL format. Let oEmbed have a go.
if ( $post_ID ) {
// Check for a cached result (stored in the post meta)
$cachekey = '_oembed_' . md5( $url . serialize( $attr ) );
if ( $this->usecache ) {
$cache = get_post_meta( $post_ID, $cachekey, true );
// Failures are cached
if ( '{{unknown}}' === $cache )
return $this->maybe_make_link( $url );
if ( ! empty( $cache ) )
return apply_filters( 'embed_oembed_html', $cache, $url, $attr, $post_ID );
}
// Use oEmbed to get the HTML
$attr['discover'] = ( apply_filters('embed_oembed_discover', false) && author_can( $post_ID, 'unfiltered_html' ) );
$html = wp_oembed_get( $url, $attr );
// Cache the result
$cache = ( $html ) ? $html : '{{unknown}}';
update_post_meta( $post_ID, $cachekey, $cache );
// If there was a result, return it
if ( $html )
return apply_filters( 'embed_oembed_html', $html, $url, $attr, $post_ID );
}
// Still unknown
return $this->maybe_make_link( $url );
}
/**
* Delete all oEmbed caches.
*
* @param int $post_ID Post ID to delete the caches for.
*/
function delete_oembed_caches( $post_ID ) {
$post_metas = get_post_custom_keys( $post_ID );
if ( empty($post_metas) )
return;
foreach( $post_metas as $post_meta_key ) {
if ( '_oembed_' == substr( $post_meta_key, 0, 8 ) )
delete_post_meta( $post_ID, $post_meta_key );
}
}
/**
* Triggers a caching of all oEmbed results.
*
* @param int $post_ID Post ID to do the caching for.
*/
function cache_oembed( $post_ID ) {
$post = get_post( $post_ID );
if ( empty($post->ID) || !in_array( $post->post_type, apply_filters( 'embed_cache_oembed_types', array( 'post', 'page' ) ) ) )
return;
// Trigger a caching
if ( !empty($post->post_content) ) {
$this->post_ID = $post->ID;
$this->usecache = false;
$content = $this->run_shortcode( $post->post_content );
$this->autoembed( $content );
$this->usecache = true;
}
}
/**
* Passes any unlinked URLs that are on their own line to {@link WP_Embed::shortcode()} for potential embedding.
*
* @uses WP_Embed::autoembed_callback()
*
* @param string $content The content to be searched.
* @return string Potentially modified $content.
*/
function autoembed( $content ) {
return preg_replace_callback( '|^\s*(https?://[^\s"]+)\s*$|im', array( $this, 'autoembed_callback' ), $content );
}
/**
* Callback function for {@link WP_Embed::autoembed()}.
*
* @uses WP_Embed::shortcode()
*
* @param array $match A regex match array.
* @return string The embed HTML on success, otherwise the original URL.
*/
function autoembed_callback( $match ) {
$oldval = $this->linkifunknown;
$this->linkifunknown = false;
$return = $this->shortcode( array(), $match[1] );
$this->linkifunknown = $oldval;
return "\n$return\n";
}
/**
* Conditionally makes a hyperlink based on an internal class variable.
*
* @param string $url URL to potentially be linked.
* @return string Linked URL or the original URL.
*/
function maybe_make_link( $url ) {
$output = ( $this->linkifunknown ) ? '<a href="' . esc_url($url) . '">' . esc_html($url) . '</a>' : $url;
return apply_filters( 'embed_maybe_make_link', $output, $url );
}
}
$GLOBALS['wp_embed'] = new WP_Embed();

View File

@ -0,0 +1,210 @@
<?php
/**
* WordPress Error API.
*
* Contains the WP_Error class and the is_wp_error() function.
*
* @package WordPress
*/
/**
* WordPress Error class.
*
* Container for checking for WordPress errors and error messages. Return
* WP_Error and use {@link is_wp_error()} to check if this class is returned.
* Many core WordPress functions pass this class in the event of an error and
* if not handled properly will result in code errors.
*
* @package WordPress
* @since 2.1.0
*/
class WP_Error {
/**
* Stores the list of errors.
*
* @since 2.1.0
* @var array
* @access private
*/
var $errors = array();
/**
* Stores the list of data for error codes.
*
* @since 2.1.0
* @var array
* @access private
*/
var $error_data = array();
/**
* Constructor - Sets up error message.
*
* If code parameter is empty then nothing will be done. It is possible to
* add multiple messages to the same code, but with other methods in the
* class.
*
* All parameters are optional, but if the code parameter is set, then the
* data parameter is optional.
*
* @since 2.1.0
*
* @param string|int $code Error code
* @param string $message Error message
* @param mixed $data Optional. Error data.
* @return WP_Error
*/
function __construct($code = '', $message = '', $data = '') {
if ( empty($code) )
return;
$this->errors[$code][] = $message;
if ( ! empty($data) )
$this->error_data[$code] = $data;
}
/**
* Retrieve all error codes.
*
* @since 2.1.0
* @access public
*
* @return array List of error codes, if available.
*/
function get_error_codes() {
if ( empty($this->errors) )
return array();
return array_keys($this->errors);
}
/**
* Retrieve first error code available.
*
* @since 2.1.0
* @access public
*
* @return string|int Empty string, if no error codes.
*/
function get_error_code() {
$codes = $this->get_error_codes();
if ( empty($codes) )
return '';
return $codes[0];
}
/**
* Retrieve all error messages or error messages matching code.
*
* @since 2.1.0
*
* @param string|int $code Optional. Retrieve messages matching code, if exists.
* @return array Error strings on success, or empty array on failure (if using code parameter).
*/
function get_error_messages($code = '') {
// Return all messages if no code specified.
if ( empty($code) ) {
$all_messages = array();
foreach ( (array) $this->errors as $code => $messages )
$all_messages = array_merge($all_messages, $messages);
return $all_messages;
}
if ( isset($this->errors[$code]) )
return $this->errors[$code];
else
return array();
}
/**
* Get single error message.
*
* This will get the first message available for the code. If no code is
* given then the first code available will be used.
*
* @since 2.1.0
*
* @param string|int $code Optional. Error code to retrieve message.
* @return string
*/
function get_error_message($code = '') {
if ( empty($code) )
$code = $this->get_error_code();
$messages = $this->get_error_messages($code);
if ( empty($messages) )
return '';
return $messages[0];
}
/**
* Retrieve error data for error code.
*
* @since 2.1.0
*
* @param string|int $code Optional. Error code.
* @return mixed Null, if no errors.
*/
function get_error_data($code = '') {
if ( empty($code) )
$code = $this->get_error_code();
if ( isset($this->error_data[$code]) )
return $this->error_data[$code];
return null;
}
/**
* Append more error messages to list of error messages.
*
* @since 2.1.0
* @access public
*
* @param string|int $code Error code.
* @param string $message Error message.
* @param mixed $data Optional. Error data.
*/
function add($code, $message, $data = '') {
$this->errors[$code][] = $message;
if ( ! empty($data) )
$this->error_data[$code] = $data;
}
/**
* Add data for error code.
*
* The error code can only contain one error data.
*
* @since 2.1.0
*
* @param mixed $data Error data.
* @param string|int $code Error code.
*/
function add_data($data, $code = '') {
if ( empty($code) )
$code = $this->get_error_code();
$this->error_data[$code] = $data;
}
}
/**
* Check whether variable is a WordPress Error.
*
* Looks at the object and if a WP_Error class. Does not check to see if the
* parent is also WP_Error, so can't inherit WP_Error and still use this
* function.
*
* @since 2.1.0
*
* @param mixed $thing Check if unknown variable is WordPress Error object.
* @return bool True, if WP_Error. False, if not WP_Error.
*/
function is_wp_error($thing) {
if ( is_object($thing) && is_a($thing, 'WP_Error') )
return true;
return false;
}

View File

@ -0,0 +1,92 @@
<?php
/**
* WP_HTTP_IXR_Client
*
* @package WordPress
* @since 3.1.0
*
*/
class WP_HTTP_IXR_Client extends IXR_Client {
function __construct($server, $path = false, $port = false, $timeout = 15) {
if ( ! $path ) {
// Assume we have been given a URL instead
$bits = parse_url($server);
$this->scheme = $bits['scheme'];
$this->server = $bits['host'];
$this->port = isset($bits['port']) ? $bits['port'] : $port;
$this->path = !empty($bits['path']) ? $bits['path'] : '/';
// Make absolutely sure we have a path
if ( ! $this->path )
$this->path = '/';
} else {
$this->scheme = 'http';
$this->server = $server;
$this->path = $path;
$this->port = $port;
}
$this->useragent = 'The Incutio XML-RPC PHP Library';
$this->timeout = $timeout;
}
function query() {
$args = func_get_args();
$method = array_shift($args);
$request = new IXR_Request($method, $args);
$xml = $request->getXml();
$port = $this->port ? ":$this->port" : '';
$url = $this->scheme . '://' . $this->server . $port . $this->path;
$args = array(
'headers' => array('Content-Type' => 'text/xml'),
'user-agent' => $this->useragent,
'body' => $xml,
);
// Merge Custom headers ala #8145
foreach ( $this->headers as $header => $value )
$args['headers'][$header] = $value;
if ( $this->timeout !== false )
$args['timeout'] = $this->timeout;
// Now send the request
if ( $this->debug )
echo '<pre class="ixr_request">' . htmlspecialchars($xml) . "\n</pre>\n\n";
$response = wp_remote_post($url, $args);
if ( is_wp_error($response) ) {
$errno = $response->get_error_code();
$errorstr = $response->get_error_message();
$this->error = new IXR_Error(-32300, "transport error: $errno $errorstr");
return false;
}
if ( 200 != wp_remote_retrieve_response_code( $response ) ) {
$this->error = new IXR_Error(-32301, 'transport error - HTTP status code was not 200 (' . wp_remote_retrieve_response_code( $response ) . ')');
return false;
}
if ( $this->debug )
echo '<pre class="ixr_response">' . htmlspecialchars( wp_remote_retrieve_body( $response ) ) . "\n</pre>\n\n";
// Now parse what we've got back
$this->message = new IXR_Message( wp_remote_retrieve_body( $response ) );
if ( ! $this->message->parse() ) {
// XML error
$this->error = new IXR_Error(-32700, 'parse error. not well formed');
return false;
}
// Is the message a fault?
if ( $this->message->messageType == 'fault' ) {
$this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
return false;
}
// Message must be OK
return true;
}
}

View File

@ -0,0 +1,390 @@
<?php
/**
* WordPress GD Image Editor
*
* @package WordPress
* @subpackage Image_Editor
*/
/**
* WordPress Image Editor Class for Image Manipulation through GD
*
* @since 3.5.0
* @package WordPress
* @subpackage Image_Editor
* @uses WP_Image_Editor Extends class
*/
class WP_Image_Editor_GD extends WP_Image_Editor {
protected $image = false; // GD Resource
function __destruct() {
if ( $this->image ) {
// we don't need the original in memory anymore
imagedestroy( $this->image );
}
}
/**
* Checks to see if current environment supports GD.
*
* @since 3.5.0
* @access public
*
* @return boolean
*/
public static function test( $args = array() ) {
if ( ! extension_loaded('gd') || ! function_exists('gd_info') )
return false;
// On some setups GD library does not provide imagerotate() - Ticket #11536
if ( isset( $args['methods'] ) &&
in_array( 'rotate', $args['methods'] ) &&
! function_exists('imagerotate') ){
return false;
}
return true;
}
/**
* Checks to see if editor supports the mime-type specified.
*
* @since 3.5.0
* @access public
*
* @param string $mime_type
* @return boolean
*/
public static function supports_mime_type( $mime_type ) {
$image_types = imagetypes();
switch( $mime_type ) {
case 'image/jpeg':
return ($image_types & IMG_JPG) != 0;
case 'image/png':
return ($image_types & IMG_PNG) != 0;
case 'image/gif':
return ($image_types & IMG_GIF) != 0;
}
return false;
}
/**
* Loads image from $this->file into new GD Resource.
*
* @since 3.5.0
* @access protected
*
* @return boolean|\WP_Error
*/
public function load() {
if ( $this->image )
return true;
if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) )
return new WP_Error( 'error_loading_image', __('File doesn&#8217;t exist?'), $this->file );
// Set artificially high because GD uses uncompressed images in memory
@ini_set( 'memory_limit', apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT ) );
$this->image = @imagecreatefromstring( file_get_contents( $this->file ) );
if ( ! is_resource( $this->image ) )
return new WP_Error( 'invalid_image', __('File is not an image.'), $this->file );
$size = @getimagesize( $this->file );
if ( ! $size )
return new WP_Error( 'invalid_image', __('Could not read image size.'), $this->file );
$this->update_size( $size[0], $size[1] );
$this->mime_type = $size['mime'];
return true;
}
/**
* Sets or updates current image size.
*
* @since 3.5.0
* @access protected
*
* @param int $width
* @param int $height
*/
protected function update_size( $width = false, $height = false ) {
if ( ! $width )
$width = imagesx( $this->image );
if ( ! $height )
$height = imagesy( $this->image );
return parent::update_size( $width, $height );
}
/**
* Resizes current image.
* Wraps _resize, since _resize returns a GD Resource.
*
* @since 3.5.0
* @access public
*
* @param int $max_w
* @param int $max_h
* @param boolean $crop
* @return boolean|WP_Error
*/
public function resize( $max_w, $max_h, $crop = false ) {
if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) )
return true;
$resized = $this->_resize( $max_w, $max_h, $crop );
if ( is_resource( $resized ) ) {
imagedestroy( $this->image );
$this->image = $resized;
return true;
} elseif ( is_wp_error( $resized ) )
return $resized;
return new WP_Error( 'image_resize_error', __('Image resize failed.'), $this->file );
}
protected function _resize( $max_w, $max_h, $crop = false ) {
$dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
if ( ! $dims ) {
return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions'), $this->file );
}
list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
$resized = wp_imagecreatetruecolor( $dst_w, $dst_h );
imagecopyresampled( $resized, $this->image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );
if ( is_resource( $resized ) ) {
$this->update_size( $dst_w, $dst_h );
return $resized;
}
return new WP_Error( 'image_resize_error', __('Image resize failed.'), $this->file );
}
/**
* Processes current image and saves to disk
* multiple sizes from single source.
*
* @since 3.5.0
* @access public
*
* @param array $sizes { {'width'=>int, 'height'=>int, 'crop'=>bool}, ... }
* @return array
*/
public function multi_resize( $sizes ) {
$metadata = array();
$orig_size = $this->size;
foreach ( $sizes as $size => $size_data ) {
$image = $this->_resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
if( ! is_wp_error( $image ) ) {
$resized = $this->_save( $image );
imagedestroy( $image );
if ( ! is_wp_error( $resized ) && $resized ) {
unset( $resized['path'] );
$metadata[$size] = $resized;
}
}
$this->size = $orig_size;
}
return $metadata;
}
/**
* Crops Image.
*
* @since 3.5.0
* @access public
*
* @param string|int $src The source file or Attachment ID.
* @param int $src_x The start x position to crop from.
* @param int $src_y The start y position to crop from.
* @param int $src_w The width to crop.
* @param int $src_h The height to crop.
* @param int $dst_w Optional. The destination width.
* @param int $dst_h Optional. The destination height.
* @param boolean $src_abs Optional. If the source crop points are absolute.
* @return boolean|WP_Error
*/
public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) {
// If destination width/height isn't specified, use same as
// width/height from source.
if ( ! $dst_w )
$dst_w = $src_w;
if ( ! $dst_h )
$dst_h = $src_h;
$dst = wp_imagecreatetruecolor( $dst_w, $dst_h );
if ( $src_abs ) {
$src_w -= $src_x;
$src_h -= $src_y;
}
if ( function_exists( 'imageantialias' ) )
imageantialias( $dst, true );
imagecopyresampled( $dst, $this->image, 0, 0, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );
if ( is_resource( $dst ) ) {
imagedestroy( $this->image );
$this->image = $dst;
$this->update_size();
return true;
}
return new WP_Error( 'image_crop_error', __('Image crop failed.'), $this->file );
}
/**
* Rotates current image counter-clockwise by $angle.
* Ported from image-edit.php
*
* @since 3.5.0
* @access public
*
* @param float $angle
* @return boolean|WP_Error
*/
public function rotate( $angle ) {
if ( function_exists('imagerotate') ) {
$rotated = imagerotate( $this->image, $angle, 0 );
if ( is_resource( $rotated ) ) {
imagedestroy( $this->image );
$this->image = $rotated;
$this->update_size();
return true;
}
}
return new WP_Error( 'image_rotate_error', __('Image rotate failed.'), $this->file );
}
/**
* Flips current image.
*
* @since 3.5.0
* @access public
*
* @param boolean $horz Horizontal Flip
* @param boolean $vert Vertical Flip
* @returns boolean|WP_Error
*/
public function flip( $horz, $vert ) {
$w = $this->size['width'];
$h = $this->size['height'];
$dst = wp_imagecreatetruecolor( $w, $h );
if ( is_resource( $dst ) ) {
$sx = $vert ? ($w - 1) : 0;
$sy = $horz ? ($h - 1) : 0;
$sw = $vert ? -$w : $w;
$sh = $horz ? -$h : $h;
if ( imagecopyresampled( $dst, $this->image, 0, 0, $sx, $sy, $w, $h, $sw, $sh ) ) {
imagedestroy( $this->image );
$this->image = $dst;
return true;
}
}
return new WP_Error( 'image_flip_error', __('Image flip failed.'), $this->file );
}
/**
* Saves current in-memory image to file.
*
* @since 3.5.0
* @access public
*
* @param string $destfilename
* @param string $mime_type
* @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
*/
public function save( $filename = null, $mime_type = null ) {
$saved = $this->_save( $this->image, $filename, $mime_type );
if ( ! is_wp_error( $saved ) ) {
$this->file = $saved['path'];
$this->mime_type = $saved['mime-type'];
}
return $saved;
}
protected function _save( $image, $filename = null, $mime_type = null ) {
list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
if ( ! $filename )
$filename = $this->generate_filename( null, null, $extension );
if ( 'image/gif' == $mime_type ) {
if ( ! $this->make_image( $filename, 'imagegif', array( $image, $filename ) ) )
return new WP_Error( 'image_save_error', __('Image Editor Save Failed') );
}
elseif ( 'image/png' == $mime_type ) {
// convert from full colors to index colors, like original PNG.
if ( function_exists('imageistruecolor') && ! imageistruecolor( $image ) )
imagetruecolortopalette( $image, false, imagecolorstotal( $image ) );
if ( ! $this->make_image( $filename, 'imagepng', array( $image, $filename ) ) )
return new WP_Error( 'image_save_error', __('Image Editor Save Failed') );
}
elseif ( 'image/jpeg' == $mime_type ) {
if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, apply_filters( 'jpeg_quality', $this->quality, 'image_resize' ) ) ) )
return new WP_Error( 'image_save_error', __('Image Editor Save Failed') );
}
else {
return new WP_Error( 'image_save_error', __('Image Editor Save Failed') );
}
// Set correct file permissions
$stat = stat( dirname( $filename ) );
$perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
@ chmod( $filename, $perms );
return array(
'path' => $filename,
'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $filename ) ),
'width' => $this->size['width'],
'height' => $this->size['height'],
'mime-type'=> $mime_type,
);
}
/**
* Returns stream of current image.
*
* @since 3.5.0
* @access public
*
* @param string $mime_type
*/
public function stream( $mime_type = null ) {
list( $filename, $extension, $mime_type ) = $this->get_output_format( null, $mime_type );
switch ( $mime_type ) {
case 'image/png':
header( 'Content-Type: image/png' );
return imagepng( $this->image );
case 'image/gif':
header( 'Content-Type: image/gif' );
return imagegif( $this->image );
default:
header( 'Content-Type: image/jpeg' );
return imagejpeg( $this->image, null, $this->quality );
}
}
}

View File

@ -0,0 +1,468 @@
<?php
/**
* WordPress Imagick Image Editor
*
* @package WordPress
* @subpackage Image_Editor
*/
/**
* WordPress Image Editor Class for Image Manipulation through Imagick PHP Module
*
* @since 3.5.0
* @package WordPress
* @subpackage Image_Editor
* @uses WP_Image_Editor Extends class
*/
class WP_Image_Editor_Imagick extends WP_Image_Editor {
protected $image = null; // Imagick Object
function __destruct() {
if ( $this->image ) {
// we don't need the original in memory anymore
$this->image->clear();
$this->image->destroy();
}
}
/**
* Checks to see if current environment supports Imagick.
*
* We require Imagick 2.2.0 or greater, based on whether the queryFormats()
* method can be called statically.
*
* @since 3.5.0
* @access public
*
* @return boolean
*/
public static function test( $args = array() ) {
// First, test Imagick's extension and classes.
if ( ! extension_loaded( 'imagick' ) || ! class_exists( 'Imagick' ) || ! class_exists( 'ImagickPixel' ) )
return false;
if ( version_compare( phpversion( 'imagick' ), '2.2.0', '<' ) )
return false;
$required_methods = array(
'clear',
'destroy',
'valid',
'getimage',
'writeimage',
'getimageblob',
'getimagegeometry',
'getimageformat',
'setimageformat',
'setimagecompression',
'setimagecompressionquality',
'setimagepage',
'scaleimage',
'cropimage',
'rotateimage',
'flipimage',
'flopimage',
);
// Now, test for deep requirements within Imagick.
if ( ! defined( 'imagick::COMPRESSION_JPEG' ) )
return false;
if ( array_diff( $required_methods, get_class_methods( 'Imagick' ) ) )
return false;
return true;
}
/**
* Checks to see if editor supports the mime-type specified.
*
* @since 3.5.0
* @access public
*
* @param string $mime_type
* @return boolean
*/
public static function supports_mime_type( $mime_type ) {
$imagick_extension = strtoupper( self::get_extension( $mime_type ) );
if ( ! $imagick_extension )
return false;
// setIteratorIndex is optional unless mime is an animated format.
// Here, we just say no if you are missing it and aren't loading a jpeg.
if ( ! method_exists( 'Imagick', 'setIteratorIndex' ) && $mime_type != 'image/jpeg' )
return false;
try {
return ( (bool) Imagick::queryFormats( $imagick_extension ) );
}
catch ( Exception $e ) {
return false;
}
}
/**
* Loads image from $this->file into new Imagick Object.
*
* @since 3.5.0
* @access protected
*
* @return boolean|WP_Error True if loaded; WP_Error on failure.
*/
public function load() {
if ( $this->image )
return true;
if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) )
return new WP_Error( 'error_loading_image', __('File doesn&#8217;t exist?'), $this->file );
// Even though Imagick uses less PHP memory than GD, set higher limit for users that have low PHP.ini limits
@ini_set( 'memory_limit', apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT ) );
try {
$this->image = new Imagick( $this->file );
if( ! $this->image->valid() )
return new WP_Error( 'invalid_image', __('File is not an image.'), $this->file);
// Select the first frame to handle animated images properly
if ( is_callable( array( $this->image, 'setIteratorIndex' ) ) )
$this->image->setIteratorIndex(0);
$this->mime_type = $this->get_mime_type( $this->image->getImageFormat() );
}
catch ( Exception $e ) {
return new WP_Error( 'invalid_image', $e->getMessage(), $this->file );
}
$updated_size = $this->update_size();
if ( is_wp_error( $updated_size ) )
return $updated_size;
return $this->set_quality();
}
/**
* Sets Image Compression quality on a 1-100% scale.
*
* @since 3.5.0
* @access public
*
* @param int $quality Compression Quality. Range: [1,100]
* @return boolean|WP_Error
*/
public function set_quality( $quality = null ) {
if ( !$quality )
$quality = $this->quality;
try {
if( 'image/jpeg' == $this->mime_type ) {
$this->image->setImageCompressionQuality( apply_filters( 'jpeg_quality', $quality, 'image_resize' ) );
$this->image->setImageCompression( imagick::COMPRESSION_JPEG );
}
else {
$this->image->setImageCompressionQuality( $quality );
}
}
catch ( Exception $e ) {
return new WP_Error( 'image_quality_error', $e->getMessage() );
}
return parent::set_quality( $quality );
}
/**
* Sets or updates current image size.
*
* @since 3.5.0
* @access protected
*
* @param int $width
* @param int $height
*/
protected function update_size( $width = null, $height = null ) {
$size = null;
if ( !$width || !$height ) {
try {
$size = $this->image->getImageGeometry();
}
catch ( Exception $e ) {
return new WP_Error( 'invalid_image', __('Could not read image size'), $this->file );
}
}
if ( ! $width )
$width = $size['width'];
if ( ! $height )
$height = $size['height'];
return parent::update_size( $width, $height );
}
/**
* Resizes current image.
*
* @since 3.5.0
* @access public
*
* @param int $max_w
* @param int $max_h
* @param boolean $crop
* @return boolean|WP_Error
*/
public function resize( $max_w, $max_h, $crop = false ) {
if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) )
return true;
$dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
if ( ! $dims )
return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions') );
list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
if ( $crop ) {
return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
}
try {
/**
* @TODO: Thumbnail is more efficient, given a newer version of Imagemagick.
* $this->image->thumbnailImage( $dst_w, $dst_h );
*/
$this->image->scaleImage( $dst_w, $dst_h );
}
catch ( Exception $e ) {
return new WP_Error( 'image_resize_error', $e->getMessage() );
}
return $this->update_size( $dst_w, $dst_h );
}
/**
* Processes current image and saves to disk
* multiple sizes from single source.
*
* @since 3.5.0
* @access public
*
* @param array $sizes { {'width'=>int, 'height'=>int, 'crop'=>bool}, ... }
* @return array
*/
public function multi_resize( $sizes ) {
$metadata = array();
$orig_size = $this->size;
$orig_image = $this->image->getImage();
foreach ( $sizes as $size => $size_data ) {
if ( ! $this->image )
$this->image = $orig_image->getImage();
$resize_result = $this->resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
if( ! is_wp_error( $resize_result ) ) {
$resized = $this->_save( $this->image );
$this->image->clear();
$this->image->destroy();
$this->image = null;
if ( ! is_wp_error( $resized ) && $resized ) {
unset( $resized['path'] );
$metadata[$size] = $resized;
}
}
$this->size = $orig_size;
}
$this->image = $orig_image;
return $metadata;
}
/**
* Crops Image.
*
* @since 3.5.0
* @access public
*
* @param string|int $src The source file or Attachment ID.
* @param int $src_x The start x position to crop from.
* @param int $src_y The start y position to crop from.
* @param int $src_w The width to crop.
* @param int $src_h The height to crop.
* @param int $dst_w Optional. The destination width.
* @param int $dst_h Optional. The destination height.
* @param boolean $src_abs Optional. If the source crop points are absolute.
* @return boolean|WP_Error
*/
public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) {
if ( $src_abs ) {
$src_w -= $src_x;
$src_h -= $src_y;
}
try {
$this->image->cropImage( $src_w, $src_h, $src_x, $src_y );
$this->image->setImagePage( $src_w, $src_h, 0, 0);
if ( $dst_w || $dst_h ) {
// If destination width/height isn't specified, use same as
// width/height from source.
if ( ! $dst_w )
$dst_w = $src_w;
if ( ! $dst_h )
$dst_h = $src_h;
$this->image->scaleImage( $dst_w, $dst_h );
return $this->update_size();
}
}
catch ( Exception $e ) {
return new WP_Error( 'image_crop_error', $e->getMessage() );
}
return $this->update_size();
}
/**
* Rotates current image counter-clockwise by $angle.
*
* @since 3.5.0
* @access public
*
* @param float $angle
* @return boolean|WP_Error
*/
public function rotate( $angle ) {
/**
* $angle is 360-$angle because Imagick rotates clockwise
* (GD rotates counter-clockwise)
*/
try {
$this->image->rotateImage( new ImagickPixel('none'), 360-$angle );
}
catch ( Exception $e ) {
return new WP_Error( 'image_rotate_error', $e->getMessage() );
}
return $this->update_size();
}
/**
* Flips current image.
*
* @since 3.5.0
* @access public
*
* @param boolean $horz Horizontal Flip
* @param boolean $vert Vertical Flip
* @returns boolean|WP_Error
*/
public function flip( $horz, $vert ) {
try {
if ( $horz )
$this->image->flipImage();
if ( $vert )
$this->image->flopImage();
}
catch ( Exception $e ) {
return new WP_Error( 'image_flip_error', $e->getMessage() );
}
return true;
}
/**
* Saves current image to file.
*
* @since 3.5.0
* @access public
*
* @param string $destfilename
* @param string $mime_type
* @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
*/
public function save( $destfilename = null, $mime_type = null ) {
$saved = $this->_save( $this->image, $destfilename, $mime_type );
if ( ! is_wp_error( $saved ) ) {
$this->file = $saved['path'];
$this->mime_type = $saved['mime-type'];
try {
$this->image->setImageFormat( strtoupper( $this->get_extension( $this->mime_type ) ) );
}
catch ( Exception $e ) {
return new WP_Error( 'image_save_error', $e->getMessage(), $this->file );
}
}
return $saved;
}
protected function _save( $image, $filename = null, $mime_type = null ) {
list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
if ( ! $filename )
$filename = $this->generate_filename( null, null, $extension );
try {
// Store initial Format
$orig_format = $this->image->getImageFormat();
$this->image->setImageFormat( strtoupper( $this->get_extension( $mime_type ) ) );
$this->make_image( $filename, array( $image, 'writeImage' ), array( $filename ) );
// Reset original Format
$this->image->setImageFormat( $orig_format );
}
catch ( Exception $e ) {
return new WP_Error( 'image_save_error', $e->getMessage(), $filename );
}
// Set correct file permissions
$stat = stat( dirname( $filename ) );
$perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
@ chmod( $filename, $perms );
return array(
'path' => $filename,
'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $filename ) ),
'width' => $this->size['width'],
'height' => $this->size['height'],
'mime-type' => $mime_type,
);
}
/**
* Streams current image to browser.
*
* @since 3.5.0
* @access public
*
* @param string $mime_type
* @return boolean|WP_Error
*/
public function stream( $mime_type = null ) {
list( $filename, $extension, $mime_type ) = $this->get_output_format( null, $mime_type );
try {
// Temporarily change format for stream
$this->image->setImageFormat( strtoupper( $extension ) );
// Output stream of image content
header( "Content-Type: $mime_type" );
print $this->image->getImageBlob();
// Reset Image to original Format
$this->image->setImageFormat( $this->get_extension( $this->mime_type ) );
}
catch ( Exception $e ) {
return new WP_Error( 'image_stream_error', $e->getMessage() );
}
return true;
}
}

View File

@ -0,0 +1,400 @@
<?php
/**
* Base WordPress Image Editor
*
* @package WordPress
* @subpackage Image_Editor
*/
/**
* Base image editor class from which implementations extend
*
* @since 3.5.0
*/
abstract class WP_Image_Editor {
protected $file = null;
protected $size = null;
protected $mime_type = null;
protected $default_mime_type = 'image/jpeg';
protected $quality = 90;
/**
* Each instance handles a single file.
*/
public function __construct( $file ) {
$this->file = $file;
}
/**
* Checks to see if current environment supports the editor chosen.
* Must be overridden in a sub-class.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param array $args
* @return boolean
*/
public static function test( $args = array() ) {
return false;
}
/**
* Checks to see if editor supports the mime-type specified.
* Must be overridden in a sub-class.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param string $mime_type
* @return boolean
*/
public static function supports_mime_type( $mime_type ) {
return false;
}
/**
* Loads image from $this->file into editor.
*
* @since 3.5.0
* @access protected
* @abstract
*
* @return boolean|WP_Error True if loaded; WP_Error on failure.
*/
abstract public function load();
/**
* Saves current image to file.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param string $destfilename
* @param string $mime_type
* @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
*/
abstract public function save( $destfilename = null, $mime_type = null );
/**
* Resizes current image.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param int $max_w
* @param int $max_h
* @param boolean $crop
* @return boolean|WP_Error
*/
abstract public function resize( $max_w, $max_h, $crop = false );
/**
* Processes current image and saves to disk
* multiple sizes from single source.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param array $sizes { {'width'=>int, 'height'=>int, 'crop'=>bool}, ... }
* @return array
*/
abstract public function multi_resize( $sizes );
/**
* Crops Image.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param string|int $src The source file or Attachment ID.
* @param int $src_x The start x position to crop from.
* @param int $src_y The start y position to crop from.
* @param int $src_w The width to crop.
* @param int $src_h The height to crop.
* @param int $dst_w Optional. The destination width.
* @param int $dst_h Optional. The destination height.
* @param boolean $src_abs Optional. If the source crop points are absolute.
* @return boolean|WP_Error
*/
abstract public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false );
/**
* Rotates current image counter-clockwise by $angle.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param float $angle
* @return boolean|WP_Error
*/
abstract public function rotate( $angle );
/**
* Flips current image.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param boolean $horz Horizontal Flip
* @param boolean $vert Vertical Flip
* @return boolean|WP_Error
*/
abstract public function flip( $horz, $vert );
/**
* Streams current image to browser.
*
* @since 3.5.0
* @access public
* @abstract
*
* @param string $mime_type
* @return boolean|WP_Error
*/
abstract public function stream( $mime_type = null );
/**
* Gets dimensions of image.
*
* @since 3.5.0
* @access public
*
* @return array {'width'=>int, 'height'=>int}
*/
public function get_size() {
return $this->size;
}
/**
* Sets current image size.
*
* @since 3.5.0
* @access protected
*
* @param int $width
* @param int $height
*/
protected function update_size( $width = null, $height = null ) {
$this->size = array(
'width' => (int) $width,
'height' => (int) $height
);
return true;
}
/**
* Sets Image Compression quality on a 1-100% scale.
*
* @since 3.5.0
* @access public
*
* @param int $quality Compression Quality. Range: [1,100]
* @return boolean
*/
public function set_quality( $quality ) {
$this->quality = apply_filters( 'wp_editor_set_quality', $quality );
return ( (bool) $this->quality );
}
/**
* Returns preferred mime-type and extension based on provided
* file's extension and mime, or current file's extension and mime.
*
* Will default to $this->default_mime_type if requested is not supported.
*
* Provides corrected filename only if filename is provided.
*
* @since 3.5.0
* @access protected
*
* @param string $filename
* @param string $mime_type
* @return array { filename|null, extension, mime-type }
*/
protected function get_output_format( $filename = null, $mime_type = null ) {
$new_ext = $file_ext = null;
$file_mime = null;
// By default, assume specified type takes priority
if ( $mime_type ) {
$new_ext = $this->get_extension( $mime_type );
}
if ( $filename ) {
$file_ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
$file_mime = $this->get_mime_type( $file_ext );
}
else {
// If no file specified, grab editor's current extension and mime-type.
$file_ext = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) );
$file_mime = $this->mime_type;
}
// Check to see if specified mime-type is the same as type implied by
// file extension. If so, prefer extension from file.
if ( ! $mime_type || ( $file_mime == $mime_type ) ) {
$mime_type = $file_mime;
$new_ext = $file_ext;
}
// Double-check that the mime-type selected is supported by the editor.
// If not, choose a default instead.
if ( ! $this->supports_mime_type( $mime_type ) ) {
$mime_type = apply_filters( 'image_editor_default_mime_type', $this->default_mime_type );
$new_ext = $this->get_extension( $mime_type );
}
if ( $filename ) {
$ext = '';
$info = pathinfo( $filename );
$dir = $info['dirname'];
if( isset( $info['extension'] ) )
$ext = $info['extension'];
$filename = trailingslashit( $dir ) . wp_basename( $filename, ".$ext" ) . ".{$new_ext}";
}
return array( $filename, $new_ext, $mime_type );
}
/**
* Builds an output filename based on current file, and adding proper suffix
*
* @since 3.5.0
* @access public
*
* @param string $suffix
* @param string $dest_path
* @param string $extension
* @return string filename
*/
public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) {
// $suffix will be appended to the destination filename, just before the extension
if ( ! $suffix )
$suffix = $this->get_suffix();
$info = pathinfo( $this->file );
$dir = $info['dirname'];
$ext = $info['extension'];
$name = wp_basename( $this->file, ".$ext" );
$new_ext = strtolower( $extension ? $extension : $ext );
if ( ! is_null( $dest_path ) && $_dest_path = realpath( $dest_path ) )
$dir = $_dest_path;
return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}";
}
/**
* Builds and returns proper suffix for file based on height and width.
*
* @since 3.5.0
* @access public
*
* @return string suffix
*/
public function get_suffix() {
if ( ! $this->get_size() )
return false;
return "{$this->size['width']}x{$this->size['height']}";
}
/**
* Either calls editor's save function or handles file as a stream.
*
* @since 3.5.0
* @access protected
*
* @param string|stream $filename
* @param callable $function
* @param array $arguments
* @return boolean
*/
protected function make_image( $filename, $function, $arguments ) {
$dst_file = $filename;
if ( $stream = wp_is_stream( $filename ) ) {
$filename = null;
ob_start();
}
$result = call_user_func_array( $function, $arguments );
if ( $result && $stream ) {
$contents = ob_get_contents();
$fp = fopen( $dst_file, 'w' );
if ( ! $fp )
return false;
fwrite( $fp, $contents );
fclose( $fp );
}
if ( $stream ) {
ob_end_clean();
}
return $result;
}
/**
* Returns first matched mime-type from extension,
* as mapped from wp_get_mime_types()
*
* @since 3.5.0
* @access protected
*
* @param string $extension
* @return string|boolean
*/
protected static function get_mime_type( $extension = null ) {
if ( ! $extension )
return false;
$mime_types = wp_get_mime_types();
$extensions = array_keys( $mime_types );
foreach( $extensions as $_extension ) {
if ( preg_match( "/{$extension}/i", $_extension ) ) {
return $mime_types[$_extension];
}
}
return false;
}
/**
* Returns first matched extension from Mime-type,
* as mapped from wp_get_mime_types()
*
* @since 3.5.0
* @access protected
*
* @param string $mime_type
* @return string|boolean
*/
protected static function get_extension( $mime_type = null ) {
$extensions = explode( '|', array_search( $mime_type, wp_get_mime_types() ) );
if ( empty( $extensions[0] ) )
return false;
return $extensions[0];
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,397 @@
<?php
/**
* A class for displaying various tree-like structures.
*
* Extend the Walker class to use it, see examples at the below. Child classes
* do not need to implement all of the abstract methods in the class. The child
* only needs to implement the methods that are needed. Also, the methods are
* not strictly abstract in that the parameter definition needs to be followed.
* The child classes can have additional parameters.
*
* @package WordPress
* @since 2.1.0
* @abstract
*/
class Walker {
/**
* What the class handles.
*
* @since 2.1.0
* @var string
* @access public
*/
var $tree_type;
/**
* DB fields to use.
*
* @since 2.1.0
* @var array
* @access protected
*/
var $db_fields;
/**
* Max number of pages walked by the paged walker
*
* @since 2.7.0
* @var int
* @access protected
*/
var $max_pages = 1;
/**
* Starts the list before the elements are added.
*
* Additional parameters are used in child classes. The args parameter holds
* additional values that may be used with the child class methods. This
* method is called at the start of the output list.
*
* @since 2.1.0
* @abstract
*
* @param string $output Passed by reference. Used to append additional content.
*/
function start_lvl( &$output, $depth = 0, $args = array() ) {}
/**
* Ends the list of after the elements are added.
*
* Additional parameters are used in child classes. The args parameter holds
* additional values that may be used with the child class methods. This
* method finishes the list at the end of output of the elements.
*
* @since 2.1.0
* @abstract
*
* @param string $output Passed by reference. Used to append additional content.
*/
function end_lvl( &$output, $depth = 0, $args = array() ) {}
/**
* Start the element output.
*
* Additional parameters are used in child classes. The args parameter holds
* additional values that may be used with the child class methods. Includes
* the element output also.
*
* @since 2.1.0
* @abstract
*
* @param string $output Passed by reference. Used to append additional content.
*/
function start_el( &$output, $object, $depth, $args, $current_object_id = 0 ) {}
/**
* Ends the element output, if needed.
*
* Additional parameters are used in child classes. The args parameter holds
* additional values that may be used with the child class methods.
*
* @since 2.1.0
* @abstract
*
* @param string $output Passed by reference. Used to append additional content.
*/
function end_el( &$output, $object, $depth = 0, $args = array() ) {}
/**
* Traverse elements to create list from elements.
*
* Display one element if the element doesn't have any children otherwise,
* display the element and its children. Will only traverse up to the max
* depth and no ignore elements under that depth. It is possible to set the
* max depth to include all depths, see walk() method.
*
* This method shouldn't be called directly, use the walk() method instead.
*
* @since 2.5.0
*
* @param object $element Data object
* @param array $children_elements List of elements to continue traversing.
* @param int $max_depth Max depth to traverse.
* @param int $depth Depth of current element.
* @param array $args
* @param string $output Passed by reference. Used to append additional content.
* @return null Null on failure with no changes to parameters.
*/
function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
if ( !$element )
return;
$id_field = $this->db_fields['id'];
//display this element
if ( is_array( $args[0] ) )
$args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );
$cb_args = array_merge( array(&$output, $element, $depth), $args);
call_user_func_array(array($this, 'start_el'), $cb_args);
$id = $element->$id_field;
// descend only when the depth is right and there are childrens for this element
if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
foreach( $children_elements[ $id ] as $child ){
if ( !isset($newlevel) ) {
$newlevel = true;
//start the child delimiter
$cb_args = array_merge( array(&$output, $depth), $args);
call_user_func_array(array($this, 'start_lvl'), $cb_args);
}
$this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
}
unset( $children_elements[ $id ] );
}
if ( isset($newlevel) && $newlevel ){
//end the child delimiter
$cb_args = array_merge( array(&$output, $depth), $args);
call_user_func_array(array($this, 'end_lvl'), $cb_args);
}
//end this element
$cb_args = array_merge( array(&$output, $element, $depth), $args);
call_user_func_array(array($this, 'end_el'), $cb_args);
}
/**
* Display array of elements hierarchically.
*
* It is a generic function which does not assume any existing order of
* elements. max_depth = -1 means flatly display every element. max_depth =
* 0 means display all levels. max_depth > 0 specifies the number of
* display levels.
*
* @since 2.1.0
*
* @param array $elements
* @param int $max_depth
* @return string
*/
function walk( $elements, $max_depth) {
$args = array_slice(func_get_args(), 2);
$output = '';
if ($max_depth < -1) //invalid parameter
return $output;
if (empty($elements)) //nothing to walk
return $output;
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
// flat display
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* need to display in hierarchical order
* separate elements into two buckets: top level and children elements
* children_elements is two dimensional array, eg.
* children_elements[10][] contains all sub-elements whose parent is 10.
*/
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( 0 == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
/*
* when none of the elements is top level
* assume the first one must be root of the sub elements
*/
if ( empty($top_level_elements) ) {
$first = array_slice( $elements, 0, 1 );
$root = $first[0];
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( $root->$parent_field == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
}
foreach ( $top_level_elements as $e )
$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
/*
* if we are displaying all levels, and remaining children_elements is not empty,
* then we got orphans, which should be displayed regardless
*/
if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
$empty_array = array();
foreach ( $children_elements as $orphans )
foreach( $orphans as $op )
$this->display_element( $op, $empty_array, 1, 0, $args, $output );
}
return $output;
}
/**
* paged_walk() - produce a page of nested elements
*
* Given an array of hierarchical elements, the maximum depth, a specific page number,
* and number of elements per page, this function first determines all top level root elements
* belonging to that page, then lists them and all of their children in hierarchical order.
*
* @package WordPress
* @since 2.7
* @param int $max_depth = 0 means display all levels; $max_depth > 0 specifies the number of display levels.
* @param int $page_num the specific page number, beginning with 1.
* @return XHTML of the specified page of elements
*/
function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
/* sanity check */
if ( empty($elements) || $max_depth < -1 )
return '';
$args = array_slice( func_get_args(), 4 );
$output = '';
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
$count = -1;
if ( -1 == $max_depth )
$total_top = count( $elements );
if ( $page_num < 1 || $per_page < 0 ) {
// No paging
$paging = false;
$start = 0;
if ( -1 == $max_depth )
$end = $total_top;
$this->max_pages = 1;
} else {
$paging = true;
$start = ( (int)$page_num - 1 ) * (int)$per_page;
$end = $start + $per_page;
if ( -1 == $max_depth )
$this->max_pages = ceil($total_top / $per_page);
}
// flat display
if ( -1 == $max_depth ) {
if ( !empty($args[0]['reverse_top_level']) ) {
$elements = array_reverse( $elements );
$oldstart = $start;
$start = $total_top - $end;
$end = $total_top - $oldstart;
}
$empty_array = array();
foreach ( $elements as $e ) {
$count++;
if ( $count < $start )
continue;
if ( $count >= $end )
break;
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
}
return $output;
}
/*
* separate elements into two buckets: top level and children elements
* children_elements is two dimensional array, eg.
* children_elements[10][] contains all sub-elements whose parent is 10.
*/
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( 0 == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
$total_top = count( $top_level_elements );
if ( $paging )
$this->max_pages = ceil($total_top / $per_page);
else
$end = $total_top;
if ( !empty($args[0]['reverse_top_level']) ) {
$top_level_elements = array_reverse( $top_level_elements );
$oldstart = $start;
$start = $total_top - $end;
$end = $total_top - $oldstart;
}
if ( !empty($args[0]['reverse_children']) ) {
foreach ( $children_elements as $parent => $children )
$children_elements[$parent] = array_reverse( $children );
}
foreach ( $top_level_elements as $e ) {
$count++;
//for the last page, need to unset earlier children in order to keep track of orphans
if ( $end >= $total_top && $count < $start )
$this->unset_children( $e, $children_elements );
if ( $count < $start )
continue;
if ( $count >= $end )
break;
$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
}
if ( $end >= $total_top && count( $children_elements ) > 0 ) {
$empty_array = array();
foreach ( $children_elements as $orphans )
foreach( $orphans as $op )
$this->display_element( $op, $empty_array, 1, 0, $args, $output );
}
return $output;
}
function get_number_of_root_elements( $elements ){
$num = 0;
$parent_field = $this->db_fields['parent'];
foreach ( $elements as $e) {
if ( 0 == $e->$parent_field )
$num++;
}
return $num;
}
// unset all the children for a given top level element
function unset_children( $e, &$children_elements ){
if ( !$e || !$children_elements )
return;
$id_field = $this->db_fields['id'];
$id = $e->$id_field;
if ( !empty($children_elements[$id]) && is_array($children_elements[$id]) )
foreach ( (array) $children_elements[$id] as $child )
$this->unset_children( $child, $children_elements );
if ( isset($children_elements[$id]) )
unset( $children_elements[$id] );
}
}

File diff suppressed because it is too large Load Diff

645
wp-includes/class-wp.php Normal file
View File

@ -0,0 +1,645 @@
<?php
/**
* WordPress environment setup class.
*
* @package WordPress
* @since 2.0.0
*/
class WP {
/**
* Public query variables.
*
* Long list of public query variables.
*
* @since 2.0.0
* @access public
* @var array
*/
var $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type');
/**
* Private query variables.
*
* Long list of private query variables.
*
* @since 2.0.0
* @var array
*/
var $private_query_vars = array('offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in');
/**
* Extra query variables set by the user.
*
* @since 2.1.0
* @var array
*/
var $extra_query_vars = array();
/**
* Query variables for setting up the WordPress Query Loop.
*
* @since 2.0.0
* @var array
*/
var $query_vars;
/**
* String parsed to set the query variables.
*
* @since 2.0.0
* @var string
*/
var $query_string;
/**
* Permalink or requested URI.
*
* @since 2.0.0
* @var string
*/
var $request;
/**
* Rewrite rule the request matched.
*
* @since 2.0.0
* @var string
*/
var $matched_rule;
/**
* Rewrite query the request matched.
*
* @since 2.0.0
* @var string
*/
var $matched_query;
/**
* Whether already did the permalink.
*
* @since 2.0.0
* @var bool
*/
var $did_permalink = false;
/**
* Add name to list of public query variables.
*
* @since 2.1.0
*
* @param string $qv Query variable name.
*/
function add_query_var($qv) {
if ( !in_array($qv, $this->public_query_vars) )
$this->public_query_vars[] = $qv;
}
/**
* Set the value of a query variable.
*
* @since 2.3.0
*
* @param string $key Query variable name.
* @param mixed $value Query variable value.
*/
function set_query_var($key, $value) {
$this->query_vars[$key] = $value;
}
/**
* Parse request to find correct WordPress query.
*
* Sets up the query variables based on the request. There are also many
* filters and actions that can be used to further manipulate the result.
*
* @since 2.0.0
*
* @param array|string $extra_query_vars Set the extra query variables.
*/
function parse_request($extra_query_vars = '') {
global $wp_rewrite;
if ( ! apply_filters( 'do_parse_request', true, $this, $extra_query_vars ) )
return;
$this->query_vars = array();
$post_type_query_vars = array();
if ( is_array($extra_query_vars) )
$this->extra_query_vars = & $extra_query_vars;
else if (! empty($extra_query_vars))
parse_str($extra_query_vars, $this->extra_query_vars);
// Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
// Fetch the rewrite rules.
$rewrite = $wp_rewrite->wp_rewrite_rules();
if ( ! empty($rewrite) ) {
// If we match a rewrite rule, this will be cleared.
$error = '404';
$this->did_permalink = true;
if ( isset($_SERVER['PATH_INFO']) )
$pathinfo = $_SERVER['PATH_INFO'];
else
$pathinfo = '';
$pathinfo_array = explode('?', $pathinfo);
$pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
$req_uri = $_SERVER['REQUEST_URI'];
$req_uri_array = explode('?', $req_uri);
$req_uri = $req_uri_array[0];
$self = $_SERVER['PHP_SELF'];
$home_path = parse_url(home_url());
if ( isset($home_path['path']) )
$home_path = $home_path['path'];
else
$home_path = '';
$home_path = trim($home_path, '/');
// Trim path info from the end and the leading home path from the
// front. For path info requests, this leaves us with the requesting
// filename, if any. For 404 requests, this leaves us with the
// requested permalink.
$req_uri = str_replace($pathinfo, '', $req_uri);
$req_uri = trim($req_uri, '/');
$req_uri = preg_replace("|^$home_path|i", '', $req_uri);
$req_uri = trim($req_uri, '/');
$pathinfo = trim($pathinfo, '/');
$pathinfo = preg_replace("|^$home_path|i", '', $pathinfo);
$pathinfo = trim($pathinfo, '/');
$self = trim($self, '/');
$self = preg_replace("|^$home_path|i", '', $self);
$self = trim($self, '/');
// The requested permalink is in $pathinfo for path info requests and
// $req_uri for other requests.
if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
$request = $pathinfo;
} else {
// If the request uri is the index, blank it out so that we don't try to match it against a rule.
if ( $req_uri == $wp_rewrite->index )
$req_uri = '';
$request = $req_uri;
}
$this->request = $request;
// Look for matches.
$request_match = $request;
if ( empty( $request_match ) ) {
// An empty request could only match against ^$ regex
if ( isset( $rewrite['$'] ) ) {
$this->matched_rule = '$';
$query = $rewrite['$'];
$matches = array('');
}
} else {
foreach ( (array) $rewrite as $match => $query ) {
// If the requesting file is the anchor of the match, prepend it to the path info.
if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request )
$request_match = $req_uri . '/' . $request;
if ( preg_match("#^$match#", $request_match, $matches) ||
preg_match("#^$match#", urldecode($request_match), $matches) ) {
if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
// this is a verbose page match, lets check to be sure about it
if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) )
continue;
}
// Got a match.
$this->matched_rule = $match;
break;
}
}
}
if ( isset( $this->matched_rule ) ) {
// Trim the query of everything up to the '?'.
$query = preg_replace("!^.+\?!", '', $query);
// Substitute the substring matches into the query.
$query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
$this->matched_query = $query;
// Parse the query.
parse_str($query, $perma_query_vars);
// If we're processing a 404 request, clear the error var since we found something.
if ( '404' == $error )
unset( $error, $_GET['error'] );
}
// If req_uri is empty or if it is a request for ourself, unset error.
if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
unset( $error, $_GET['error'] );
if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
unset( $perma_query_vars );
$this->did_permalink = false;
}
}
$this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);
foreach ( $GLOBALS['wp_post_types'] as $post_type => $t )
if ( $t->query_var )
$post_type_query_vars[$t->query_var] = $post_type;
foreach ( $this->public_query_vars as $wpvar ) {
if ( isset( $this->extra_query_vars[$wpvar] ) )
$this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
elseif ( isset( $_POST[$wpvar] ) )
$this->query_vars[$wpvar] = $_POST[$wpvar];
elseif ( isset( $_GET[$wpvar] ) )
$this->query_vars[$wpvar] = $_GET[$wpvar];
elseif ( isset( $perma_query_vars[$wpvar] ) )
$this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
if ( !empty( $this->query_vars[$wpvar] ) ) {
if ( ! is_array( $this->query_vars[$wpvar] ) ) {
$this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
} else {
foreach ( $this->query_vars[$wpvar] as $vkey => $v ) {
if ( !is_object( $v ) ) {
$this->query_vars[$wpvar][$vkey] = (string) $v;
}
}
}
if ( isset($post_type_query_vars[$wpvar] ) ) {
$this->query_vars['post_type'] = $post_type_query_vars[$wpvar];
$this->query_vars['name'] = $this->query_vars[$wpvar];
}
}
}
// Convert urldecoded spaces back into +
foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t )
if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) )
$this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] );
// Limit publicly queried post_types to those that are publicly_queryable
if ( isset( $this->query_vars['post_type']) ) {
$queryable_post_types = get_post_types( array('publicly_queryable' => true) );
if ( ! is_array( $this->query_vars['post_type'] ) ) {
if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
unset( $this->query_vars['post_type'] );
} else {
$this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
}
}
foreach ( (array) $this->private_query_vars as $var) {
if ( isset($this->extra_query_vars[$var]) )
$this->query_vars[$var] = $this->extra_query_vars[$var];
}
if ( isset($error) )
$this->query_vars['error'] = $error;
$this->query_vars = apply_filters('request', $this->query_vars);
do_action_ref_array('parse_request', array(&$this));
}
/**
* Send additional HTTP headers for caching, content type, etc.
*
* Sets the X-Pingback header, 404 status (if 404), Content-type. If showing
* a feed, it will also send last-modified, etag, and 304 status if needed.
*
* @since 2.0.0
*/
function send_headers() {
$headers = array('X-Pingback' => get_bloginfo('pingback_url'));
$status = null;
$exit_required = false;
if ( is_user_logged_in() )
$headers = array_merge($headers, wp_get_nocache_headers());
if ( ! empty( $this->query_vars['error'] ) ) {
$status = (int) $this->query_vars['error'];
if ( 404 === $status ) {
if ( ! is_user_logged_in() )
$headers = array_merge($headers, wp_get_nocache_headers());
$headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
} elseif ( in_array( $status, array( 403, 500, 502, 503 ) ) ) {
$exit_required = true;
}
} else if ( empty($this->query_vars['feed']) ) {
$headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
} else {
// We're showing a feed, so WP is indeed the only thing that last changed
if ( !empty($this->query_vars['withcomments'])
|| ( empty($this->query_vars['withoutcomments'])
&& ( !empty($this->query_vars['p'])
|| !empty($this->query_vars['name'])
|| !empty($this->query_vars['page_id'])
|| !empty($this->query_vars['pagename'])
|| !empty($this->query_vars['attachment'])
|| !empty($this->query_vars['attachment_id'])
)
)
)
$wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
else
$wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
$wp_etag = '"' . md5($wp_last_modified) . '"';
$headers['Last-Modified'] = $wp_last_modified;
$headers['ETag'] = $wp_etag;
// Support for Conditional GET
if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
$client_etag = stripslashes(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
else $client_etag = false;
$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
// If string is empty, return 0. If not, attempt to parse into a timestamp
$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
// Make a timestamp for our most recent modification...
$wp_modified_timestamp = strtotime($wp_last_modified);
if ( ($client_last_modified && $client_etag) ?
(($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
(($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
$status = 304;
$exit_required = true;
}
}
$headers = apply_filters('wp_headers', $headers, $this);
if ( ! empty( $status ) )
status_header( $status );
// If Last-Modified is set to false, it should not be sent (no-cache situation).
if ( isset( $headers['Last-Modified'] ) && false === $headers['Last-Modified'] ) {
unset( $headers['Last-Modified'] );
// In PHP 5.3+, make sure we are not sending a Last-Modified header.
if ( function_exists( 'header_remove' ) ) {
@header_remove( 'Last-Modified' );
} else {
// In PHP 5.2, send an empty Last-Modified header, but only as a
// last resort to override a header already sent. #WP23021
foreach ( headers_list() as $header ) {
if ( 0 === stripos( $header, 'Last-Modified' ) ) {
$headers['Last-Modified'] = '';
break;
}
}
}
}
foreach( (array) $headers as $name => $field_value )
@header("{$name}: {$field_value}");
if ( $exit_required )
exit();
do_action_ref_array('send_headers', array(&$this));
}
/**
* Sets the query string property based off of the query variable property.
*
* The 'query_string' filter is deprecated, but still works. Plugins should
* use the 'request' filter instead.
*
* @since 2.0.0
*/
function build_query_string() {
$this->query_string = '';
foreach ( (array) array_keys($this->query_vars) as $wpvar) {
if ( '' != $this->query_vars[$wpvar] ) {
$this->query_string .= (strlen($this->query_string) < 1) ? '' : '&';
if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars.
continue;
$this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]);
}
}
// query_string filter deprecated. Use request filter instead.
if ( has_filter('query_string') ) { // Don't bother filtering and parsing if no plugins are hooked in.
$this->query_string = apply_filters('query_string', $this->query_string);
parse_str($this->query_string, $this->query_vars);
}
}
/**
* Set up the WordPress Globals.
*
* The query_vars property will be extracted to the GLOBALS. So care should
* be taken when naming global variables that might interfere with the
* WordPress environment.
*
* @global string $query_string Query string for the loop.
* @global int $more Only set, if single page or post.
* @global int $single If single page or post. Only set, if single page or post.
*
* @since 2.0.0
*/
function register_globals() {
global $wp_query;
// Extract updated query vars back into global namespace.
foreach ( (array) $wp_query->query_vars as $key => $value) {
$GLOBALS[$key] = $value;
}
$GLOBALS['query_string'] = $this->query_string;
$GLOBALS['posts'] = & $wp_query->posts;
$GLOBALS['post'] = (isset($wp_query->post)) ? $wp_query->post : null;
$GLOBALS['request'] = $wp_query->request;
if ( is_single() || is_page() ) {
$GLOBALS['more'] = 1;
$GLOBALS['single'] = 1;
}
}
/**
* Set up the current user.
*
* @since 2.0.0
*/
function init() {
wp_get_current_user();
}
/**
* Set up the Loop based on the query variables.
*
* @uses WP::$query_vars
* @since 2.0.0
*/
function query_posts() {
global $wp_the_query;
$this->build_query_string();
$wp_the_query->query($this->query_vars);
}
/**
* Set the Headers for 404, if nothing is found for requested URL.
*
* Issue a 404 if a request doesn't match any posts and doesn't match
* any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already
* issued, and if the request was not a search or the homepage.
*
* Otherwise, issue a 200.
*
* @since 2.0.0
*/
function handle_404() {
global $wp_query;
// If we've already issued a 404, bail.
if ( is_404() )
return;
// Never 404 for the admin, robots, or if we found posts.
if ( is_admin() || is_robots() || $wp_query->posts ) {
status_header( 200 );
return;
}
// We will 404 for paged queries, as no posts were found.
if ( ! is_paged() ) {
// Don't 404 for these queries if they matched an object.
if ( ( is_tag() || is_category() || is_tax() || is_author() || is_post_type_archive() ) && $wp_query->get_queried_object() ) {
status_header( 200 );
return;
}
// Don't 404 for these queries either.
if ( is_home() || is_search() ) {
status_header( 200 );
return;
}
}
// Guess it's time to 404.
$wp_query->set_404();
status_header( 404 );
nocache_headers();
}
/**
* Sets up all of the variables required by the WordPress environment.
*
* The action 'wp' has one parameter that references the WP object. It
* allows for accessing the properties and methods to further manipulate the
* object.
*
* @since 2.0.0
*
* @param string|array $query_args Passed to {@link parse_request()}
*/
function main($query_args = '') {
$this->init();
$this->parse_request($query_args);
$this->send_headers();
$this->query_posts();
$this->handle_404();
$this->register_globals();
do_action_ref_array('wp', array(&$this));
}
}
/**
* Helper class to remove the need to use eval to replace $matches[] in query strings.
*
* @since 2.9.0
*/
class WP_MatchesMapRegex {
/**
* store for matches
*
* @access private
* @var array
*/
var $_matches;
/**
* store for mapping result
*
* @access public
* @var string
*/
var $output;
/**
* subject to perform mapping on (query string containing $matches[] references
*
* @access private
* @var string
*/
var $_subject;
/**
* regexp pattern to match $matches[] references
*
* @var string
*/
var $_pattern = '(\$matches\[[1-9]+[0-9]*\])'; // magic number
/**
* constructor
*
* @param string $subject subject if regex
* @param array $matches data to use in map
* @return self
*/
function WP_MatchesMapRegex($subject, $matches) {
$this->_subject = $subject;
$this->_matches = $matches;
$this->output = $this->_map();
}
/**
* Substitute substring matches in subject.
*
* static helper function to ease use
*
* @access public
* @param string $subject subject
* @param array $matches data used for substitution
* @return string
*/
public static function apply($subject, $matches) {
$oSelf = new WP_MatchesMapRegex($subject, $matches);
return $oSelf->output;
}
/**
* do the actual mapping
*
* @access private
* @return string
*/
function _map() {
$callback = array($this, 'callback');
return preg_replace_callback($this->_pattern, $callback, $this->_subject);
}
/**
* preg_replace_callback hook
*
* @access public
* @param array $matches preg_replace regexp matches
* @return string
*/
function callback($matches) {
$index = intval(substr($matches[0], 9, -1));
return ( isset( $this->_matches[$index] ) ? urlencode($this->_matches[$index]) : '' );
}
}

View File

@ -0,0 +1,261 @@
<?php
/**
* BackPress Scripts enqueue.
*
* These classes were refactored from the WordPress WP_Scripts and WordPress
* script enqueue API.
*
* @package BackPress
* @since r74
*/
/**
* BackPress enqueued dependiences class.
*
* @package BackPress
* @uses _WP_Dependency
* @since r74
*/
class WP_Dependencies {
var $registered = array();
var $queue = array();
var $to_do = array();
var $done = array();
var $args = array();
var $groups = array();
var $group = 0;
/**
* Do the dependencies
*
* Process the items passed to it or the queue. Processes all dependencies.
*
* @param mixed $handles (optional) items to be processed. (void) processes queue, (string) process that item, (array of strings) process those items
* @return array Items that have been processed
*/
function do_items( $handles = false, $group = false ) {
// Print the queue if nothing is passed. If a string is passed, print that script. If an array is passed, print those scripts.
$handles = false === $handles ? $this->queue : (array) $handles;
$this->all_deps( $handles );
foreach( $this->to_do as $key => $handle ) {
if ( !in_array($handle, $this->done, true) && isset($this->registered[$handle]) ) {
if ( ! $this->registered[$handle]->src ) { // Defines a group.
$this->done[] = $handle;
continue;
}
if ( $this->do_item( $handle, $group ) )
$this->done[] = $handle;
unset( $this->to_do[$key] );
}
}
return $this->done;
}
function do_item( $handle ) {
return isset($this->registered[$handle]);
}
/**
* Determines dependencies
*
* Recursively builds array of items to process taking dependencies into account. Does NOT catch infinite loops.
*
*
* @param mixed $handles Accepts (string) dep name or (array of strings) dep names
* @param bool $recursion Used internally when function calls itself
*/
function all_deps( $handles, $recursion = false, $group = false ) {
if ( !$handles = (array) $handles )
return false;
foreach ( $handles as $handle ) {
$handle_parts = explode('?', $handle);
$handle = $handle_parts[0];
$queued = in_array($handle, $this->to_do, true);
if ( in_array($handle, $this->done, true) ) // Already done
continue;
$moved = $this->set_group( $handle, $recursion, $group );
if ( $queued && !$moved ) // already queued and in the right group
continue;
$keep_going = true;
if ( !isset($this->registered[$handle]) )
$keep_going = false; // Script doesn't exist
elseif ( $this->registered[$handle]->deps && array_diff($this->registered[$handle]->deps, array_keys($this->registered)) )
$keep_going = false; // Script requires deps which don't exist (not a necessary check. efficiency?)
elseif ( $this->registered[$handle]->deps && !$this->all_deps( $this->registered[$handle]->deps, true, $group ) )
$keep_going = false; // Script requires deps which don't exist
if ( !$keep_going ) { // Either script or its deps don't exist.
if ( $recursion )
return false; // Abort this branch.
else
continue; // We're at the top level. Move on to the next one.
}
if ( $queued ) // Already grobbed it and its deps
continue;
if ( isset($handle_parts[1]) )
$this->args[$handle] = $handle_parts[1];
$this->to_do[] = $handle;
}
return true;
}
/**
* Adds item
*
* Adds the item only if no item of that name already exists
*
* @param string $handle Script name
* @param string $src Script url
* @param array $deps (optional) Array of script names on which this script depends
* @param string $ver (optional) Script version (used for cache busting)
* @return array Hierarchical array of dependencies
*/
function add( $handle, $src, $deps = array(), $ver = false, $args = null ) {
if ( isset($this->registered[$handle]) )
return false;
$this->registered[$handle] = new _WP_Dependency( $handle, $src, $deps, $ver, $args );
return true;
}
/**
* Adds extra data
*
* Adds data only if script has already been added.
*
* @param string $handle Script name
* @param string $key
* @param mixed $value
* @return bool success
*/
function add_data( $handle, $key, $value ) {
if ( !isset( $this->registered[$handle] ) )
return false;
return $this->registered[$handle]->add_data( $key, $value );
}
/**
* Get extra data
*
* Gets data associated with a certain handle.
*
* @since WP 3.3
*
* @param string $handle Script name
* @param string $key
* @return mixed
*/
function get_data( $handle, $key ) {
if ( !isset( $this->registered[$handle] ) )
return false;
if ( !isset( $this->registered[$handle]->extra[$key] ) )
return false;
return $this->registered[$handle]->extra[$key];
}
function remove( $handles ) {
foreach ( (array) $handles as $handle )
unset($this->registered[$handle]);
}
function enqueue( $handles ) {
foreach ( (array) $handles as $handle ) {
$handle = explode('?', $handle);
if ( !in_array($handle[0], $this->queue) && isset($this->registered[$handle[0]]) ) {
$this->queue[] = $handle[0];
if ( isset($handle[1]) )
$this->args[$handle[0]] = $handle[1];
}
}
}
function dequeue( $handles ) {
foreach ( (array) $handles as $handle ) {
$handle = explode('?', $handle);
$key = array_search($handle[0], $this->queue);
if ( false !== $key ) {
unset($this->queue[$key]);
unset($this->args[$handle[0]]);
}
}
}
function query( $handle, $list = 'registered' ) {
switch ( $list ) {
case 'registered' :
case 'scripts': // back compat
if ( isset( $this->registered[ $handle ] ) )
return $this->registered[ $handle ];
return false;
case 'enqueued' :
case 'queue' :
return in_array( $handle, $this->queue );
case 'to_do' :
case 'to_print': // back compat
return in_array( $handle, $this->to_do );
case 'done' :
case 'printed': // back compat
return in_array( $handle, $this->done );
}
return false;
}
function set_group( $handle, $recursion, $group ) {
$group = (int) $group;
if ( $recursion )
$group = min($this->group, $group);
else
$this->group = $group;
if ( isset($this->groups[$handle]) && $this->groups[$handle] <= $group )
return false;
$this->groups[$handle] = $group;
return true;
}
}
class _WP_Dependency {
var $handle;
var $src;
var $deps = array();
var $ver = false;
var $args = null;
var $extra = array();
function __construct() {
@list( $this->handle, $this->src, $this->deps, $this->ver, $this->args ) = func_get_args();
if ( ! is_array($this->deps) )
$this->deps = array();
}
function add_data( $name, $data ) {
if ( !is_scalar($name) )
return false;
$this->extra[$name] = $data;
return true;
}
}

View File

@ -0,0 +1,214 @@
<?php
/**
* BackPress Scripts enqueue.
*
* These classes were refactored from the WordPress WP_Scripts and WordPress
* script enqueue API.
*
* @package BackPress
* @since r16
*/
/**
* BackPress Scripts enqueue class.
*
* @package BackPress
* @uses WP_Dependencies
* @since r16
*/
class WP_Scripts extends WP_Dependencies {
var $base_url; // Full URL with trailing slash
var $content_url;
var $default_version;
var $in_footer = array();
var $concat = '';
var $concat_version = '';
var $do_concat = false;
var $print_html = '';
var $print_code = '';
var $ext_handles = '';
var $ext_version = '';
var $default_dirs;
function __construct() {
$this->init();
add_action( 'init', array( $this, 'init' ), 0 );
}
function init() {
do_action_ref_array( 'wp_default_scripts', array(&$this) );
}
/**
* Prints scripts
*
* Prints the scripts passed to it or the print queue. Also prints all necessary dependencies.
*
* @param mixed $handles (optional) Scripts to be printed. (void) prints queue, (string) prints that script, (array of strings) prints those scripts.
* @param int $group (optional) If scripts were queued in groups prints this group number.
* @return array Scripts that have been printed
*/
function print_scripts( $handles = false, $group = false ) {
return $this->do_items( $handles, $group );
}
// Deprecated since 3.3, see print_extra_script()
function print_scripts_l10n( $handle, $echo = true ) {
_deprecated_function( __FUNCTION__, '3.3', 'print_extra_script()' );
return $this->print_extra_script( $handle, $echo );
}
function print_extra_script( $handle, $echo = true ) {
if ( !$output = $this->get_data( $handle, 'data' ) )
return;
if ( !$echo )
return $output;
echo "<script type='text/javascript'>\n"; // CDATA and type='text/javascript' is not needed for HTML 5
echo "/* <![CDATA[ */\n";
echo "$output\n";
echo "/* ]]> */\n";
echo "</script>\n";
return true;
}
function do_item( $handle, $group = false ) {
if ( !parent::do_item($handle) )
return false;
if ( 0 === $group && $this->groups[$handle] > 0 ) {
$this->in_footer[] = $handle;
return false;
}
if ( false === $group && in_array($handle, $this->in_footer, true) )
$this->in_footer = array_diff( $this->in_footer, (array) $handle );
if ( null === $this->registered[$handle]->ver )
$ver = '';
else
$ver = $this->registered[$handle]->ver ? $this->registered[$handle]->ver : $this->default_version;
if ( isset($this->args[$handle]) )
$ver = $ver ? $ver . '&amp;' . $this->args[$handle] : $this->args[$handle];
$src = $this->registered[$handle]->src;
if ( $this->do_concat ) {
$srce = apply_filters( 'script_loader_src', $src, $handle );
if ( $this->in_default_dir($srce) ) {
$this->print_code .= $this->print_extra_script( $handle, false );
$this->concat .= "$handle,";
$this->concat_version .= "$handle$ver";
return true;
} else {
$this->ext_handles .= "$handle,";
$this->ext_version .= "$handle$ver";
}
}
$this->print_extra_script( $handle );
if ( !preg_match('|^(https?:)?//|', $src) && ! ( $this->content_url && 0 === strpos($src, $this->content_url) ) ) {
$src = $this->base_url . $src;
}
if ( !empty($ver) )
$src = add_query_arg('ver', $ver, $src);
$src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );
if ( $this->do_concat )
$this->print_html .= "<script type='text/javascript' src='$src'></script>\n";
else
echo "<script type='text/javascript' src='$src'></script>\n";
return true;
}
/**
* Localizes a script
*
* Localizes only if the script has already been added
*/
function localize( $handle, $object_name, $l10n ) {
if ( is_array($l10n) && isset($l10n['l10n_print_after']) ) { // back compat, preserve the code in 'l10n_print_after' if present
$after = $l10n['l10n_print_after'];
unset($l10n['l10n_print_after']);
}
foreach ( (array) $l10n as $key => $value ) {
if ( !is_scalar($value) )
continue;
$l10n[$key] = html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8');
}
$script = "var $object_name = " . json_encode($l10n) . ';';
if ( !empty($after) )
$script .= "\n$after;";
$data = $this->get_data( $handle, 'data' );
if ( !empty( $data ) )
$script = "$data\n$script";
return $this->add_data( $handle, 'data', $script );
}
function set_group( $handle, $recursion, $group = false ) {
if ( $this->registered[$handle]->args === 1 )
$grp = 1;
else
$grp = (int) $this->get_data( $handle, 'group' );
if ( false !== $group && $grp > $group )
$grp = $group;
return parent::set_group( $handle, $recursion, $grp );
}
function all_deps( $handles, $recursion = false, $group = false ) {
$r = parent::all_deps( $handles, $recursion );
if ( !$recursion )
$this->to_do = apply_filters( 'print_scripts_array', $this->to_do );
return $r;
}
function do_head_items() {
$this->do_items(false, 0);
return $this->done;
}
function do_footer_items() {
$this->do_items(false, 1);
return $this->done;
}
function in_default_dir($src) {
if ( ! $this->default_dirs )
return true;
if ( 0 === strpos( $src, '/wp-includes/js/l10n' ) )
return false;
foreach ( (array) $this->default_dirs as $test ) {
if ( 0 === strpos($src, $test) )
return true;
}
return false;
}
function reset() {
$this->do_concat = false;
$this->print_code = '';
$this->concat = '';
$this->concat_version = '';
$this->print_html = '';
$this->ext_version = '';
$this->ext_handles = '';
}
}

View File

@ -0,0 +1,170 @@
<?php
/**
* BackPress Styles enqueue.
*
* These classes were refactored from the WordPress WP_Scripts and WordPress
* script enqueue API.
*
* @package BackPress
* @since r74
*/
/**
* BackPress Styles enqueue class.
*
* @package BackPress
* @uses WP_Dependencies
* @since r74
*/
class WP_Styles extends WP_Dependencies {
var $base_url;
var $content_url;
var $default_version;
var $text_direction = 'ltr';
var $concat = '';
var $concat_version = '';
var $do_concat = false;
var $print_html = '';
var $print_code = '';
var $default_dirs;
function __construct() {
do_action_ref_array( 'wp_default_styles', array(&$this) );
}
function do_item( $handle ) {
if ( !parent::do_item($handle) )
return false;
$obj = $this->registered[$handle];
if ( null === $obj->ver )
$ver = '';
else
$ver = $obj->ver ? $obj->ver : $this->default_version;
if ( isset($this->args[$handle]) )
$ver = $ver ? $ver . '&amp;' . $this->args[$handle] : $this->args[$handle];
if ( $this->do_concat ) {
if ( $this->in_default_dir($obj->src) && !isset($obj->extra['conditional']) && !isset($obj->extra['alt']) ) {
$this->concat .= "$handle,";
$this->concat_version .= "$handle$ver";
$this->print_code .= $this->get_data( $handle, 'after' );
return true;
}
}
if ( isset($obj->args) )
$media = esc_attr( $obj->args );
else
$media = 'all';
$href = $this->_css_href( $obj->src, $ver, $handle );
$rel = isset($obj->extra['alt']) && $obj->extra['alt'] ? 'alternate stylesheet' : 'stylesheet';
$title = isset($obj->extra['title']) ? "title='" . esc_attr( $obj->extra['title'] ) . "'" : '';
$end_cond = $tag = '';
if ( isset($obj->extra['conditional']) && $obj->extra['conditional'] ) {
$tag .= "<!--[if {$obj->extra['conditional']}]>\n";
$end_cond = "<![endif]-->\n";
}
$tag .= apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-css' $title href='$href' type='text/css' media='$media' />\n", $handle );
if ( 'rtl' === $this->text_direction && isset($obj->extra['rtl']) && $obj->extra['rtl'] ) {
if ( is_bool( $obj->extra['rtl'] ) ) {
$suffix = isset( $obj->extra['suffix'] ) ? $obj->extra['suffix'] : '';
$rtl_href = str_replace( "{$suffix}.css", "-rtl{$suffix}.css", $this->_css_href( $obj->src , $ver, "$handle-rtl" ));
} else {
$rtl_href = $this->_css_href( $obj->extra['rtl'], $ver, "$handle-rtl" );
}
$tag .= apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-rtl-css' $title href='$rtl_href' type='text/css' media='$media' />\n", $handle );
}
$tag .= $end_cond;
if ( $this->do_concat ) {
$this->print_html .= $tag;
$this->print_html .= $this->print_inline_style( $handle, false );
} else {
echo $tag;
$this->print_inline_style( $handle );
}
return true;
}
function add_inline_style( $handle, $code ) {
if ( !$code )
return false;
$after = $this->get_data( $handle, 'after' );
if ( !$after )
$after = array();
$after[] = $code;
return $this->add_data( $handle, 'after', $after );
}
function print_inline_style( $handle, $echo = true ) {
$output = $this->get_data( $handle, 'after' );
if ( empty( $output ) )
return false;
$output = implode( "\n", $output );
if ( !$echo )
return $output;
echo "<style type='text/css'>\n";
echo "$output\n";
echo "</style>\n";
return true;
}
function all_deps( $handles, $recursion = false, $group = false ) {
$r = parent::all_deps( $handles, $recursion );
if ( !$recursion )
$this->to_do = apply_filters( 'print_styles_array', $this->to_do );
return $r;
}
function _css_href( $src, $ver, $handle ) {
if ( !is_bool($src) && !preg_match('|^(https?:)?//|', $src) && ! ( $this->content_url && 0 === strpos($src, $this->content_url) ) ) {
$src = $this->base_url . $src;
}
if ( !empty($ver) )
$src = add_query_arg('ver', $ver, $src);
$src = apply_filters( 'style_loader_src', $src, $handle );
return esc_url( $src );
}
function in_default_dir($src) {
if ( ! $this->default_dirs )
return true;
foreach ( (array) $this->default_dirs as $test ) {
if ( 0 === strpos($src, $test) )
return true;
}
return false;
}
function do_footer_items() { // HTML 5 allows styles in the body, grab late enqueued items and output them in the footer.
$this->do_items(false, 1);
return $this->done;
}
function reset() {
$this->do_concat = false;
$this->concat = '';
$this->concat_version = '';
$this->print_html = '';
}
}

File diff suppressed because it is too large Load Diff

2094
wp-includes/comment.php Normal file

File diff suppressed because it is too large Load Diff

96
wp-includes/compat.php Normal file
View File

@ -0,0 +1,96 @@
<?php
/**
* WordPress implementation for PHP functions either missing from older PHP versions or not included by default.
*
* @package PHP
* @access private
*/
// If gettext isn't available
if ( !function_exists('_') ) {
function _($string) {
return $string;
}
}
if ( !function_exists('mb_substr') ):
function mb_substr( $str, $start, $length=null, $encoding=null ) {
return _mb_substr($str, $start, $length, $encoding);
}
endif;
function _mb_substr( $str, $start, $length=null, $encoding=null ) {
// the solution below, works only for utf-8, so in case of a different
// charset, just use built-in substr
$charset = get_option( 'blog_charset' );
if ( !in_array( $charset, array('utf8', 'utf-8', 'UTF8', 'UTF-8') ) ) {
return is_null( $length )? substr( $str, $start ) : substr( $str, $start, $length);
}
// use the regex unicode support to separate the UTF-8 characters into an array
preg_match_all( '/./us', $str, $match );
$chars = is_null( $length )? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
return implode( '', $chars );
}
if ( !function_exists('hash_hmac') ):
function hash_hmac($algo, $data, $key, $raw_output = false) {
return _hash_hmac($algo, $data, $key, $raw_output);
}
endif;
function _hash_hmac($algo, $data, $key, $raw_output = false) {
$packs = array('md5' => 'H32', 'sha1' => 'H40');
if ( !isset($packs[$algo]) )
return false;
$pack = $packs[$algo];
if (strlen($key) > 64)
$key = pack($pack, $algo($key));
$key = str_pad($key, 64, chr(0));
$ipad = (substr($key, 0, 64) ^ str_repeat(chr(0x36), 64));
$opad = (substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64));
$hmac = $algo($opad . pack($pack, $algo($ipad . $data)));
if ( $raw_output )
return pack( $pack, $hmac );
return $hmac;
}
if ( !function_exists('json_encode') ) {
function json_encode( $string ) {
global $wp_json;
if ( !is_a($wp_json, 'Services_JSON') ) {
require_once( ABSPATH . WPINC . '/class-json.php' );
$wp_json = new Services_JSON();
}
return $wp_json->encodeUnsafe( $string );
}
}
if ( !function_exists('json_decode') ) {
function json_decode( $string, $assoc_array = false ) {
global $wp_json;
if ( !is_a($wp_json, 'Services_JSON') ) {
require_once( ABSPATH . WPINC . '/class-json.php' );
$wp_json = new Services_JSON();
}
$res = $wp_json->decode( $string );
if ( $assoc_array )
$res = _json_decode_object_helper( $res );
return $res;
}
function _json_decode_object_helper($data) {
if ( is_object($data) )
$data = get_object_vars($data);
return is_array($data) ? array_map(__FUNCTION__, $data) : $data;
}
}

414
wp-includes/cron.php Normal file
View File

@ -0,0 +1,414 @@
<?php
/**
* WordPress CRON API
*
* @package WordPress
*/
/**
* Schedules a hook to run only once.
*
* Schedules a hook which will be executed once by the WordPress actions core at
* a time which you specify. The action will fire off when someone visits your
* WordPress site, if the schedule time has passed.
*
* @since 2.1.0
* @link http://codex.wordpress.org/Function_Reference/wp_schedule_single_event
*
* @param int $timestamp Timestamp for when to run the event.
* @param string $hook Action hook to execute when cron is run.
* @param array $args Optional. Arguments to pass to the hook's callback function.
*/
function wp_schedule_single_event( $timestamp, $hook, $args = array()) {
// don't schedule a duplicate if there's already an identical event due in the next 10 minutes
$next = wp_next_scheduled($hook, $args);
if ( $next && $next <= $timestamp + 10 * MINUTE_IN_SECONDS )
return;
$crons = _get_cron_array();
$event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => false, 'args' => $args );
$event = apply_filters('schedule_event', $event);
// A plugin disallowed this event
if ( ! $event )
return false;
$key = md5(serialize($event->args));
$crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args );
uksort( $crons, "strnatcasecmp" );
_set_cron_array( $crons );
}
/**
* Schedule a periodic event.
*
* Schedules a hook which will be executed by the WordPress actions core on a
* specific interval, specified by you. The action will trigger when someone
* visits your WordPress site, if the scheduled time has passed.
*
* Valid values for the recurrence are hourly, daily and twicedaily. These can
* be extended using the cron_schedules filter in wp_get_schedules().
*
* Use wp_next_scheduled() to prevent duplicates
*
* @since 2.1.0
*
* @param int $timestamp Timestamp for when to run the event.
* @param string $recurrence How often the event should recur.
* @param string $hook Action hook to execute when cron is run.
* @param array $args Optional. Arguments to pass to the hook's callback function.
* @return bool|null False on failure, null when complete with scheduling event.
*/
function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) {
$crons = _get_cron_array();
$schedules = wp_get_schedules();
if ( !isset( $schedules[$recurrence] ) )
return false;
$event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => $recurrence, 'args' => $args, 'interval' => $schedules[$recurrence]['interval'] );
$event = apply_filters('schedule_event', $event);
// A plugin disallowed this event
if ( ! $event )
return false;
$key = md5(serialize($event->args));
$crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args, 'interval' => $event->interval );
uksort( $crons, "strnatcasecmp" );
_set_cron_array( $crons );
}
/**
* Reschedule a recurring event.
*
* @since 2.1.0
*
* @param int $timestamp Timestamp for when to run the event.
* @param string $recurrence How often the event should recur.
* @param string $hook Action hook to execute when cron is run.
* @param array $args Optional. Arguments to pass to the hook's callback function.
* @return bool|null False on failure. Null when event is rescheduled.
*/
function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array()) {
$crons = _get_cron_array();
$schedules = wp_get_schedules();
$key = md5(serialize($args));
$interval = 0;
// First we try to get it from the schedule
if ( 0 == $interval )
$interval = $schedules[$recurrence]['interval'];
// Now we try to get it from the saved interval in case the schedule disappears
if ( 0 == $interval )
$interval = $crons[$timestamp][$hook][$key]['interval'];
// Now we assume something is wrong and fail to schedule
if ( 0 == $interval )
return false;
$now = time();
if ( $timestamp >= $now )
$timestamp = $now + $interval;
else
$timestamp = $now + ($interval - (($now - $timestamp) % $interval));
wp_schedule_event( $timestamp, $recurrence, $hook, $args );
}
/**
* Unschedule a previously scheduled cron job.
*
* The $timestamp and $hook parameters are required, so that the event can be
* identified.
*
* @since 2.1.0
*
* @param int $timestamp Timestamp for when to run the event.
* @param string $hook Action hook, the execution of which will be unscheduled.
* @param array $args Arguments to pass to the hook's callback function.
* Although not passed to a callback function, these arguments are used
* to uniquely identify the scheduled event, so they should be the same
* as those used when originally scheduling the event.
*/
function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
$crons = _get_cron_array();
$key = md5(serialize($args));
unset( $crons[$timestamp][$hook][$key] );
if ( empty($crons[$timestamp][$hook]) )
unset( $crons[$timestamp][$hook] );
if ( empty($crons[$timestamp]) )
unset( $crons[$timestamp] );
_set_cron_array( $crons );
}
/**
* Unschedule all cron jobs attached to a specific hook.
*
* @since 2.1.0
*
* @param string $hook Action hook, the execution of which will be unscheduled.
* @param array $args Optional. Arguments that were to be pass to the hook's callback function.
*/
function wp_clear_scheduled_hook( $hook, $args = array() ) {
// Backward compatibility
// Previously this function took the arguments as discrete vars rather than an array like the rest of the API
if ( !is_array($args) ) {
_deprecated_argument( __FUNCTION__, '3.0', __('This argument has changed to an array to match the behavior of the other cron functions.') );
$args = array_slice( func_get_args(), 1 );
}
while ( $timestamp = wp_next_scheduled( $hook, $args ) )
wp_unschedule_event( $timestamp, $hook, $args );
}
/**
* Retrieve the next timestamp for a cron event.
*
* @since 2.1.0
*
* @param string $hook Action hook to execute when cron is run.
* @param array $args Optional. Arguments to pass to the hook's callback function.
* @return bool|int The UNIX timestamp of the next time the scheduled event will occur.
*/
function wp_next_scheduled( $hook, $args = array() ) {
$crons = _get_cron_array();
$key = md5(serialize($args));
if ( empty($crons) )
return false;
foreach ( $crons as $timestamp => $cron ) {
if ( isset( $cron[$hook][$key] ) )
return $timestamp;
}
return false;
}
/**
* Send request to run cron through HTTP request that doesn't halt page loading.
*
* @since 2.1.0
*
* @return null Cron could not be spawned, because it is not needed to run.
*/
function spawn_cron( $gmt_time = 0 ) {
if ( ! $gmt_time )
$gmt_time = microtime( true );
if ( defined('DOING_CRON') || isset($_GET['doing_wp_cron']) )
return;
/*
* multiple processes on multiple web servers can run this code concurrently
* try to make this as atomic as possible by setting doing_cron switch
*/
$lock = get_transient('doing_cron');
if ( $lock > $gmt_time + 10 * MINUTE_IN_SECONDS )
$lock = 0;
// don't run if another process is currently running it or more than once every 60 sec.
if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
return;
//sanity check
$crons = _get_cron_array();
if ( !is_array($crons) )
return;
$keys = array_keys( $crons );
if ( isset($keys[0]) && $keys[0] > $gmt_time )
return;
if ( defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON ) {
if ( !empty($_POST) || defined('DOING_AJAX') )
return;
$doing_wp_cron = sprintf( '%.22F', $gmt_time );
set_transient( 'doing_cron', $doing_wp_cron );
ob_start();
wp_redirect( add_query_arg('doing_wp_cron', $doing_wp_cron, stripslashes($_SERVER['REQUEST_URI'])) );
echo ' ';
// flush any buffers and send the headers
while ( @ob_end_flush() );
flush();
WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
return;
}
$doing_wp_cron = sprintf( '%.22F', $gmt_time );
set_transient( 'doing_cron', $doing_wp_cron );
$cron_request = apply_filters( 'cron_request', array(
'url' => site_url( 'wp-cron.php?doing_wp_cron=' . $doing_wp_cron ),
'key' => $doing_wp_cron,
'args' => array( 'timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters( 'https_local_ssl_verify', true ) )
) );
wp_remote_post( $cron_request['url'], $cron_request['args'] );
}
/**
* Run scheduled callbacks or spawn cron for all scheduled events.
*
* @since 2.1.0
*
* @return null When doesn't need to run Cron.
*/
function wp_cron() {
// Prevent infinite loops caused by lack of wp-cron.php
if ( strpos($_SERVER['REQUEST_URI'], '/wp-cron.php') !== false || ( defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ) )
return;
if ( false === $crons = _get_cron_array() )
return;
$gmt_time = microtime( true );
$keys = array_keys( $crons );
if ( isset($keys[0]) && $keys[0] > $gmt_time )
return;
$schedules = wp_get_schedules();
foreach ( $crons as $timestamp => $cronhooks ) {
if ( $timestamp > $gmt_time ) break;
foreach ( (array) $cronhooks as $hook => $args ) {
if ( isset($schedules[$hook]['callback']) && !call_user_func( $schedules[$hook]['callback'] ) )
continue;
spawn_cron( $gmt_time );
break 2;
}
}
}
/**
* Retrieve supported and filtered Cron recurrences.
*
* The supported recurrences are 'hourly' and 'daily'. A plugin may add more by
* hooking into the 'cron_schedules' filter. The filter accepts an array of
* arrays. The outer array has a key that is the name of the schedule or for
* example 'weekly'. The value is an array with two keys, one is 'interval' and
* the other is 'display'.
*
* The 'interval' is a number in seconds of when the cron job should run. So for
* 'hourly', the time is 3600 or 60*60. For weekly, the value would be
* 60*60*24*7 or 604800. The value of 'interval' would then be 604800.
*
* The 'display' is the description. For the 'weekly' key, the 'display' would
* be <code>__('Once Weekly')</code>.
*
* For your plugin, you will be passed an array. you can easily add your
* schedule by doing the following.
* <code>
* // filter parameter variable name is 'array'
* $array['weekly'] = array(
* 'interval' => 604800,
* 'display' => __('Once Weekly')
* );
* </code>
*
* @since 2.1.0
*
* @return array
*/
function wp_get_schedules() {
$schedules = array(
'hourly' => array( 'interval' => HOUR_IN_SECONDS, 'display' => __( 'Once Hourly' ) ),
'twicedaily' => array( 'interval' => 12 * HOUR_IN_SECONDS, 'display' => __( 'Twice Daily' ) ),
'daily' => array( 'interval' => DAY_IN_SECONDS, 'display' => __( 'Once Daily' ) ),
);
return array_merge( apply_filters( 'cron_schedules', array() ), $schedules );
}
/**
* Retrieve Cron schedule for hook with arguments.
*
* @since 2.1.0
*
* @param string $hook Action hook to execute when cron is run.
* @param array $args Optional. Arguments to pass to the hook's callback function.
* @return string|bool False, if no schedule. Schedule on success.
*/
function wp_get_schedule($hook, $args = array()) {
$crons = _get_cron_array();
$key = md5(serialize($args));
if ( empty($crons) )
return false;
foreach ( $crons as $timestamp => $cron ) {
if ( isset( $cron[$hook][$key] ) )
return $cron[$hook][$key]['schedule'];
}
return false;
}
//
// Private functions
//
/**
* Retrieve cron info array option.
*
* @since 2.1.0
* @access private
*
* @return array CRON info array.
*/
function _get_cron_array() {
$cron = get_option('cron');
if ( ! is_array($cron) )
return false;
if ( !isset($cron['version']) )
$cron = _upgrade_cron_array($cron);
unset($cron['version']);
return $cron;
}
/**
* Updates the CRON option with the new CRON array.
*
* @since 2.1.0
* @access private
*
* @param array $cron Cron info array from {@link _get_cron_array()}.
*/
function _set_cron_array($cron) {
$cron['version'] = 2;
update_option( 'cron', $cron );
}
/**
* Upgrade a Cron info array.
*
* This function upgrades the Cron info array to version 2.
*
* @since 2.1.0
* @access private
*
* @param array $cron Cron info array from {@link _get_cron_array()}.
* @return array An upgraded Cron info array.
*/
function _upgrade_cron_array($cron) {
if ( isset($cron['version']) && 2 == $cron['version'])
return $cron;
$new_cron = array();
foreach ( (array) $cron as $timestamp => $hooks) {
foreach ( (array) $hooks as $hook => $args ) {
$key = md5(serialize($args['args']));
$new_cron[$timestamp][$hook][$key] = $args;
}
}
$new_cron['version'] = 2;
update_option( 'cron', $new_cron );
return $new_cron;
}

View File

@ -0,0 +1,201 @@
#wpadminbar * {
font-family: Tahoma, Arial, Helvetica, sans-serif;
}
#wpadminbar {
direction: rtl;
font-family: Tahoma, Arial, Helvetica, sans-serif;
left: auto;
right: 0;
}
#wpadminbar .quicklinks ul {
text-align: right;
}
#wpadminbar li {
float: right;
}
#wpadminbar .quicklinks > ul > li {
border-right: 0;
border-left: 1px solid #555;
}
#wpadminbar .quicklinks > ul > li > a,
#wpadminbar .quicklinks > ul > li > .ab-empty-item {
border-right: 0;
border-left: 1px solid #333;
}
#wpadminbar .quicklinks .ab-top-secondary > li {
border-left: 0;
border-right: 1px solid #333;
float: left;
}
#wpadminbar .quicklinks .ab-top-secondary > li > a,
#wpadminbar .quicklinks .ab-top-secondary > li > .ab-empty-item {
border-right: 1px solid #555;
border-left: 0;
}
#wpadminbar .menupop .ab-sub-wrapper,
#wpadminbar .shortlink-input {
margin: 0 -1px 0 0;
}
#wpadminbar.ie7 .menupop .ab-sub-wrapper,
#wpadminbar.ie7 .shortlink-input {
left: auto;
right: 0;
}
#wpadminbar .ab-top-secondary .menupop .ab-sub-wrapper {
right: auto;
left: 0;
margin: 0 0 0 -1px;
}
#wpadminbar .menupop li:hover > .ab-sub-wrapper,
#wpadminbar .menupop li.hover > .ab-sub-wrapper {
margin-left: 0px;
margin-right: 100%;
}
#wpadminbar .ab-top-secondary .menupop li:hover > .ab-sub-wrapper,
#wpadminbar .ab-top-secondary .menupop li.hover > .ab-sub-wrapper {
margin-left: inherit;
margin-right: 0;
left: 100%;
right: inherit;
}
#wpadminbar .menupop .menupop > .ab-item {
background-position: 5% -46px;
padding-left: 2em;
padding-right: 1em;
}
#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item {
background-position: 95% -20px;
padding-left: 1em;
padding-right: 2em;
}
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary {
right: 0;
left: auto;
}
#wpadminbar .ab-top-secondary {
float: left;
right: auto;
left: 0;
}
#wpadminbar ul li:last-child,
#wpadminbar ul li:last-child .ab-item {
border-left: 0;
}
#wpadminbar .screen-reader-shortcut:focus {
left: auto;
right: 6px;
}
/**
* My Account
*/
#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions > li {
margin-right: 88px;
margin-left: 16px;
}
#wp-admin-bar-user-actions > li > .ab-item {
padding-left: 0;
padding-right: 8px;
}
#wp-admin-bar-user-info .avatar {
left: auto;
right: -72px;
}
#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
margin-left: -1px;
margin-right: 4px
}
/*
* My Sites
*/
#wpadminbar .quicklinks li .blavatar {
margin-right: 0px;
margin-left: 4px;
}
/*
* Search
*/
#wpadminbar #adminbarsearch .adminbar-input {
font-family: Tahoma, Arial, Helvetica, sans-serif;
padding: 0 24px 0 3px;
margin: 0;
background-position: 50% 2px;
}
#wpadminbar #adminbarsearch .adminbar-input:focus,
#wpadminbar.ie7 #adminbarsearch .adminbar-input {
background-position: 99% 2px;
}
/**
* Comments icon
*/
#wpadminbar .ab-icon {
float: right;
}
.ie7 #wp-admin-bar-wp-logo > .ab-item .ab-icon {
position: static;
}
#wpadminbar.ie7 .ab-icon {
float: left;
left: 12px;
}
#wpadminbar .ab-label {
margin-left: 0px;
margin-right: 4px;
float: left;
}
#wpadminbar.ie7 .ab-label {
margin-right: 0;
}
#wpadminbar.ie7 #wp-admin-bar-comments > a {
min-width: 25px;
}
#wpadminbar a:hover .ab-comments-icon-arrow {
border-right-color: #bbb;
}
#wpadminbar .menupop .ab-sub-wrapper,
#wpadminbar .shortlink-input {
right: 0;
}
#wpadminbar .quicklinks .menupop ul li a {
position: relative;
}
/**
* IE 6-targeted rules
*/
* html #wpadminbar .quicklinks ul li a {
float: right;
}

1
wp-includes/css/admin-bar-rtl.min.css vendored Normal file
View File

@ -0,0 +1 @@
#wpadminbar *{font-family:Tahoma,Arial,Helvetica,sans-serif}#wpadminbar{direction:rtl;font-family:Tahoma,Arial,Helvetica,sans-serif;left:auto;right:0}#wpadminbar .quicklinks ul{text-align:right}#wpadminbar li{float:right}#wpadminbar .quicklinks>ul>li{border-right:0;border-left:1px solid #555}#wpadminbar .quicklinks>ul>li>a,#wpadminbar .quicklinks>ul>li>.ab-empty-item{border-right:0;border-left:1px solid #333}#wpadminbar .quicklinks .ab-top-secondary>li{border-left:0;border-right:1px solid #333;float:left}#wpadminbar .quicklinks .ab-top-secondary>li>a,#wpadminbar .quicklinks .ab-top-secondary>li>.ab-empty-item{border-right:1px solid #555;border-left:0}#wpadminbar .menupop .ab-sub-wrapper,#wpadminbar .shortlink-input{margin:0 -1px 0 0}#wpadminbar.ie7 .menupop .ab-sub-wrapper,#wpadminbar.ie7 .shortlink-input{left:auto;right:0}#wpadminbar .ab-top-secondary .menupop .ab-sub-wrapper{right:auto;left:0;margin:0 0 0 -1px}#wpadminbar .menupop li:hover>.ab-sub-wrapper,#wpadminbar .menupop li.hover>.ab-sub-wrapper{margin-left:0;margin-right:100%}#wpadminbar .ab-top-secondary .menupop li:hover>.ab-sub-wrapper,#wpadminbar .ab-top-secondary .menupop li.hover>.ab-sub-wrapper{margin-left:inherit;margin-right:0;left:100%;right:inherit}#wpadminbar .menupop .menupop>.ab-item{background-position:5% -46px;padding-left:2em;padding-right:1em}#wpadminbar .ab-top-secondary .menupop .menupop>.ab-item{background-position:95% -20px;padding-left:1em;padding-right:2em}#wpadminbar .quicklinks .menupop ul.ab-sub-secondary{right:0;left:auto}#wpadminbar .ab-top-secondary{float:left;right:auto;left:0}#wpadminbar ul li:last-child,#wpadminbar ul li:last-child .ab-item{border-left:0}#wpadminbar .screen-reader-shortcut:focus{left:auto;right:6px}#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions>li{margin-right:88px;margin-left:16px}#wp-admin-bar-user-actions>li>.ab-item{padding-left:0;padding-right:8px}#wp-admin-bar-user-info .avatar{left:auto;right:-72px}#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar>a img{margin-left:-1px;margin-right:4px}#wpadminbar .quicklinks li .blavatar{margin-right:0;margin-left:4px}#wpadminbar #adminbarsearch .adminbar-input{font-family:Tahoma,Arial,Helvetica,sans-serif;padding:0 24px 0 3px;margin:0;background-position:50% 2px}#wpadminbar #adminbarsearch .adminbar-input:focus,#wpadminbar.ie7 #adminbarsearch .adminbar-input{background-position:99% 2px}#wpadminbar .ab-icon{float:right}.ie7 #wp-admin-bar-wp-logo>.ab-item .ab-icon{position:static}#wpadminbar.ie7 .ab-icon{float:left;left:12px}#wpadminbar .ab-label{margin-left:0;margin-right:4px;float:left}#wpadminbar.ie7 .ab-label{margin-right:0}#wpadminbar.ie7 #wp-admin-bar-comments>a{min-width:25px}#wpadminbar a:hover .ab-comments-icon-arrow{border-right-color:#bbb}#wpadminbar .menupop .ab-sub-wrapper,#wpadminbar .shortlink-input{right:0}#wpadminbar .quicklinks .menupop ul li a{position:relative}* html #wpadminbar .quicklinks ul li a{float:right}

View File

@ -0,0 +1,685 @@
#wpadminbar * {
height: auto;
width: auto;
margin: 0;
padding: 0;
position: static;
text-transform: none;
letter-spacing: normal;
line-height: 1;
font: normal 13px/28px sans-serif;
color: #ccc;
text-shadow: #444 0px -1px 0px;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
#wpadminbar ul li:before,
#wpadminbar ul li:after {
content: normal;
}
#wpadminbar a,
#wpadminbar a:hover,
#wpadminbar a img,
#wpadminbar a img:hover {
outline: none;
border: none;
text-decoration: none;
background: none;
}
#wpadminbar a:focus,
#wpadminbar a:active,
#wpadminbar input[type="text"],
#wpadminbar input[type="password"],
#wpadminbar input[type="number"],
#wpadminbar input[type="search"],
#wpadminbar input[type="email"],
#wpadminbar input[type="url"],
#wpadminbar select,
#wpadminbar textarea,
#wpadminbar div {
outline: none;
}
#wpadminbar {
direction: ltr;
color: #ccc;
font: normal 13px/28px sans-serif;
height: 28px;
position: fixed;
top: 0;
left: 0;
width: 100%;
min-width: 600px; /* match the min-width of the body in wp-admin.css */
z-index: 99999;
background: #464646;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #373737), color-stop(18%, #464646));
background-image: -webkit-linear-gradient(bottom, #373737 0, #464646 5px);
background-image: -moz-linear-gradient(bottom, #373737 0, #464646 5px);
background-image: -o-linear-gradient(bottom, #373737 0, #464646 5px);
background-image: linear-gradient(to top, #373737 0, #464646 5px);
}
#wpadminbar .ab-sub-wrapper,
#wpadminbar ul,
#wpadminbar ul li {
background: none;
clear: none;
list-style: none;
margin: 0;
padding: 0;
position: relative;
text-indent: 0;
z-index: 99999;
}
#wpadminbar .quicklinks {
border-left: 1px solid transparent;
}
#wpadminbar .quicklinks ul {
text-align: left;
}
#wpadminbar li {
float: left;
}
#wpadminbar .ab-empty-item {
outline: none;
}
#wpadminbar .quicklinks > ul > li {
border-right: 1px solid #555;
}
#wpadminbar .quicklinks > ul > li > a,
#wpadminbar .quicklinks > ul > li > .ab-empty-item {
border-right: 1px solid #333;
}
#wpadminbar .quicklinks .ab-top-secondary > li {
border-left: 1px solid #333;
border-right: 0;
float: right;
}
#wpadminbar .quicklinks .ab-top-secondary > li > a,
#wpadminbar .quicklinks .ab-top-secondary > li > .ab-empty-item {
border-left: 1px solid #555;
border-right: 0;
}
#wpadminbar .quicklinks a,
#wpadminbar .quicklinks .ab-empty-item,
#wpadminbar .shortlink-input {
height: 28px;
display: block;
padding: 0 12px;
margin: 0;
}
#wpadminbar .menupop .ab-sub-wrapper,
#wpadminbar .shortlink-input {
margin: 0 0 0 -1px;
padding: 0;
-webkit-box-shadow: 0 4px 4px rgba(0,0,0,0.2);
box-shadow: 0 4px 4px rgba(0,0,0,0.2);
background: #fff;
display: none;
position: absolute;
float: none;
border-width: 0 1px 1px 1px;
border-style: solid;
border-color: #dfdfdf;
}
#wpadminbar.ie7 .menupop .ab-sub-wrapper,
#wpadminbar.ie7 .shortlink-input {
top: 28px;
left: 0;
}
#wpadminbar .ab-top-menu > .menupop > .ab-sub-wrapper {
min-width: 100%;
}
#wpadminbar .ab-top-secondary .menupop .ab-sub-wrapper {
right: 0;
left: auto;
margin: 0 -1px 0 0;
}
#wpadminbar .ab-sub-wrapper > .ab-submenu:first-child {
border-top: none;
}
#wpadminbar .ab-submenu {
padding: 6px 0;
border-top: 1px solid #dfdfdf;
}
#wpadminbar .selected .shortlink-input {
display: block;
}
#wpadminbar .quicklinks .menupop ul li {
float: none;
}
#wpadminbar .quicklinks .menupop ul li a strong {
font-weight: bold;
}
#wpadminbar .quicklinks .menupop ul li .ab-item,
#wpadminbar .quicklinks .menupop ul li a strong,
#wpadminbar .quicklinks .menupop.hover ul li .ab-item,
#wpadminbar.nojs .quicklinks .menupop:hover ul li .ab-item,
#wpadminbar .shortlink-input {
line-height: 26px;
height: 26px;
text-shadow: none;
white-space: nowrap;
min-width: 140px;
}
#wpadminbar .shortlink-input {
width: 200px;
}
#wpadminbar.nojs li:hover > .ab-sub-wrapper,
#wpadminbar li.hover > .ab-sub-wrapper {
display: block;
}
#wpadminbar .menupop li:hover > .ab-sub-wrapper,
#wpadminbar .menupop li.hover > .ab-sub-wrapper {
margin-left: 100%;
margin-top: -33px;
border-width: 1px;
}
#wpadminbar .ab-top-secondary .menupop li:hover > .ab-sub-wrapper,
#wpadminbar .ab-top-secondary .menupop li.hover > .ab-sub-wrapper {
margin-left: 0;
left: inherit;
right: 100%;
}
#wpadminbar .ab-top-menu > li:hover > .ab-item,
#wpadminbar .ab-top-menu > li.hover > .ab-item,
#wpadminbar .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus {
color: #fafafa;
background: #222;
background-image: -webkit-gradient(linear, left bottom, left top, from(#3a3a3a), to(#222));
background-image: -webkit-linear-gradient(bottom, #3a3a3a, #222);
background-image: -moz-linear-gradient(bottom, #3a3a3a, #222);
background-image: -o-linear-gradient(bottom, #3a3a3a, #222);
background-image: linear-gradient(to top, #3a3a3a, #222);
}
#wpadminbar.nojs .ab-top-menu > li.menupop:hover > .ab-item,
#wpadminbar .ab-top-menu > li.menupop.hover > .ab-item {
background: #fff;
color: #333;
text-shadow: none;
border-right-color: transparent;
border-left-color: transparent;
}
#wpadminbar .hover .ab-label,
#wpadminbar.nojq .ab-item:focus .ab-label {
color: #fafafa;
}
#wpadminbar .menupop.hover .ab-label {
color: #333;
text-shadow: none;
}
#wpadminbar .menupop li:hover,
#wpadminbar .menupop li.hover,
#wpadminbar .quicklinks .menupop .ab-item:focus,
#wpadminbar .quicklinks .ab-top-menu .menupop .ab-item:focus {
background-color: #eaf2fa;
}
#wpadminbar .ab-submenu .ab-item {
color: #333;
text-shadow: none;
}
#wpadminbar .quicklinks .menupop ul li a,
#wpadminbar .quicklinks .menupop ul li a strong,
#wpadminbar .quicklinks .menupop.hover ul li a,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a {
color: #21759B;
}
#wpadminbar .menupop .menupop > .ab-item {
display: block;
background-image: url(../images/admin-bar-sprite.png?d=20120830);
background-position: 95% -20px;
background-repeat: no-repeat;
padding-right: 2em;
}
#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item {
background-image: url(../images/admin-bar-sprite.png?d=20120830);
background-position: 5% -46px;
background-repeat: no-repeat;
padding-left: 2em;
padding-right: 1em;
}
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary {
display: block;
position: relative;
right: auto;
margin: 0;
background: #eee;
-webkit-box-shadow: none;
box-shadow: none;
}
#wpadminbar .quicklinks .menupop .ab-sub-secondary > li:hover,
#wpadminbar .quicklinks .menupop .ab-sub-secondary > li.hover,
#wpadminbar .quicklinks .menupop .ab-sub-secondary > li .ab-item:focus {
background-color: #dfdfdf;
}
#wpadminbar .quicklinks a span#ab-updates {
background: #eee;
color: #333;
text-shadow: none;
display: inline;
padding: 2px 5px;
font-size: 10px;
font-weight: bold;
-webkit-border-radius: 10px;
border-radius: 10px;
}
#wpadminbar .quicklinks a:hover span#ab-updates {
background: #fff;
color: #000;
}
#wpadminbar .ab-top-secondary {
float: right;
background: #464646;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #373737), color-stop(18%, #464646));
background-image: -webkit-linear-gradient(bottom, #373737 0, #464646 5px);
background-image: -moz-linear-gradient(bottom, #373737 0, #464646 5px);
background-image: -o-linear-gradient(bottom, #373737 0, #464646 5px);
background-image: linear-gradient(to top, #373737 0, #464646 5px);
}
#wpadminbar ul li:last-child,
#wpadminbar ul li:last-child .ab-item {
border-right: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
/**
* My Account
*/
#wp-admin-bar-my-account > ul {
min-width: 198px;
}
#wp-admin-bar-my-account.with-avatar > ul {
min-width: 270px;
}
#wpadminbar #wp-admin-bar-user-actions > li {
margin-left: 16px;
margin-right: 16px;
}
#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions > li {
margin-left: 88px;
}
#wp-admin-bar-user-actions > li > .ab-item {
padding-left: 8px;
}
#wpadminbar #wp-admin-bar-user-info {
margin-top: 6px;
margin-bottom: 15px;
height: auto;
background: none;
}
#wp-admin-bar-user-info .avatar {
position: absolute;
left: -72px;
top: 4px;
width: 64px;
height: 64px;
}
#wpadminbar #wp-admin-bar-user-info a {
background: none;
height: auto;
}
#wpadminbar #wp-admin-bar-user-info span {
background: none;
padding: 0;
height: 18px;
}
#wpadminbar #wp-admin-bar-user-info .display-name,
#wpadminbar #wp-admin-bar-user-info .username {
text-shadow: none;
display: block;
}
#wpadminbar #wp-admin-bar-user-info .display-name {
color: #333;
}
#wpadminbar #wp-admin-bar-user-info .username {
color: #999;
font-size: 11px;
}
#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
width: 16px;
height: 16px;
border: 1px solid #999;
padding: 0;
background: #eee;
line-height: 24px;
vertical-align: middle;
margin: -3px 0 0 6px;
float: none;
display: inline;
}
/*
* My Sites
*/
#wpadminbar .quicklinks li .blavatar {
vertical-align: middle;
margin: -3px 4px 0 0;
padding: 0;
}
#wpadminbar .quicklinks li div.blavatar {
background: url('../images/wpmini-blue.png') no-repeat;
height: 16px;
width: 16px;
display: inline-block;
}
/**
* Search
*/
#wpadminbar #wp-admin-bar-search .ab-item {
padding: 0;
}
#wpadminbar #wp-admin-bar-search .ab-item {
/* default background */
background: transparent;
}
#wpadminbar #adminbarsearch {
height: 28px;
padding: 0 2px;
}
#wpadminbar #adminbarsearch .adminbar-input {
font: 13px/24px sans-serif;
height: 24px;
width: 24px;
border: none;
padding: 0 3px 0 23px;
margin: 0;
color: #ccc;
text-shadow: #444 0px -1px 0px;
background-color: rgba( 255, 255, 255, 0 );
background-image: url(../images/admin-bar-sprite.png?d=20120830);
background-position: 3px 2px;
background-repeat: no-repeat;
outline: none;
cursor: pointer;
-webkit-border-radius: 3px;
border-radius: 3px;
-webkit-box-shadow: none;
box-shadow: none;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
-webkit-transition-duration: 400ms;
-webkit-transition-property: width, background;
-webkit-transition-timing-function: ease;
-moz-transition-duration: 400ms;
-moz-transition-property: width, background;
-moz-transition-timing-function: ease;
-o-transition-duration: 400ms;
-o-transition-property: width, background;
-o-transition-timing-function: ease;
}
#wpadminbar.ie7 #adminbarsearch .adminbar-input {
margin-top: 1px;
width: 120px;
}
#wpadminbar #adminbarsearch .adminbar-input:focus {
color: #555;
text-shadow: 0 1px 0 #fff;
width: 200px;
background-color: rgba( 255, 255, 255, 0.9 );
cursor: text;
}
#wpadminbar.ie8 #adminbarsearch .adminbar-input {
background-color: #464646;
}
#wpadminbar.ie8 #adminbarsearch .adminbar-input:focus {
background-color: #fff;
}
/* Two rules to ensure browser recognition */
#wpadminbar #adminbarsearch .adminbar-input::-webkit-input-placeholder {
color: #ddd;
}
#wpadminbar #adminbarsearch .adminbar-input:-moz-placeholder {
color: #ddd;
}
#wpadminbar #adminbarsearch .adminbar-button {
display: none;
}
/**
* Site Menu
*/
#wpadminbar #wp-admin-bar-appearance {
border-top: none;
margin-top: -12px;
}
/**
* Site Menu
*/
#wpadminbar #wp-admin-bar-appearance {
border-top: none;
margin-top: -12px;
}
/**
* ICONS
*/
#wpadminbar .ab-icon {
position: relative;
float: left;
width: 16px;
height: 16px;
margin-top: 6px;
}
#wpadminbar .ab-label {
margin-left: 4px;
}
/**
* WP Logo icon
*/
#wp-admin-bar-wp-logo > .ab-item .ab-icon {
width: 20px;
height: 20px;
margin-top: 4px;
background-image: url(../images/admin-bar-sprite.png?d=20120830);
background-position: 0 -76px;
background-repeat: no-repeat;
}
#wpadminbar.nojs #wp-admin-bar-wp-logo:hover > .ab-item .ab-icon,
#wpadminbar #wp-admin-bar-wp-logo.hover > .ab-item .ab-icon {
background-position: 0 -104px;
}
/**
* Updates icon
*/
#wp-admin-bar-updates > .ab-item .ab-icon {
background-image: url(../images/admin-bar-sprite.png?d=20120830);
background-position: -2px -159px;
background-repeat: no-repeat;
}
/**
* Comments icon
*/
#wp-admin-bar-comments > .ab-item .ab-icon {
background-image: url(../images/admin-bar-sprite.png?d=20120830);
background-position: -1px -134px;
background-repeat: no-repeat;
}
#wpadminbar span.count-0 {
display: none;
}
/**
* Add New icon
*/
#wpadminbar #wp-admin-bar-new-content > .ab-item .ab-icon {
background-image: url(../images/admin-bar-sprite.png?d=20120830);
background-position: -2px -182px;
background-repeat: no-repeat;
}
/**
* Add New icon
*/
#wpadminbar.nojs #wp-admin-bar-new-content:hover > .ab-item .ab-icon,
#wpadminbar #wp-admin-bar-new-content.hover > .ab-item .ab-icon {
background-position: -2px -203px;
}
/**
* Customize support classes
*/
.no-customize-support .hide-if-no-customize,
.customize-support .hide-if-customize,
.no-customize-support.wp-core-ui .hide-if-no-customize,
.no-customize-support .wp-core-ui .hide-if-no-customize,
.customize-support.wp-core-ui .hide-if-customize,
.customize-support .wp-core-ui .hide-if-customize {
display: none;
}
/**
* Retina display 2x icons
*/
@media print,
(-o-min-device-pixel-ratio: 5/4),
(-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
#wpadminbar .menupop .menupop > .ab-item,
#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item,
#wpadminbar #adminbarsearch .adminbar-input,
#wp-admin-bar-wp-logo > .ab-item .ab-icon,
#wp-admin-bar-updates > .ab-item .ab-icon,
#wp-admin-bar-comments > .ab-item .ab-icon,
#wpadminbar #wp-admin-bar-new-content > .ab-item .ab-icon {
background-image: url(../images/admin-bar-sprite-2x.png?d=20120830);
background-size: 20px 220px;
}
#wpadminbar .quicklinks li div.blavatar {
background: url('../images/wpmini-blue-2x.png') no-repeat;
background-size: 16px 16px;
}
}
/* Skip link */
#wpadminbar .screen-reader-text,
#wpadminbar .screen-reader-text span {
position: absolute;
left: -1000em;
top: -1000em;
height: 1px;
width: 1px;
overflow: hidden;
}
#wpadminbar .screen-reader-shortcut {
position: absolute;
top: -1000em;
}
#wpadminbar .screen-reader-shortcut:focus {
left: 6px;
top: 7px;
height: auto;
width: auto;
display: block;
font-size: 14px;
font-weight: bold;
padding: 15px 23px 14px;
background: #f1f1f1;
color: #21759b;
text-shadow: none;
border-radius: 3px;
z-index: 100000;
line-height: normal;
-webkit-box-shadow: 0 0 2px 2px rgba(0,0,0,.6);
box-shadow: 0 0 2px 2px rgba(0,0,0,.6);
text-decoration: none;
}
/**
* IE 6-targeted rules
*/
* html #wpadminbar {
overflow: hidden;
position: absolute;
}
* html #wpadminbar .quicklinks ul li a {
float: left;
}
* html #wpadminbar .menupop a span {
background-image: none;
}

1
wp-includes/css/admin-bar.min.css vendored Normal file

File diff suppressed because one or more lines are too long

288
wp-includes/css/buttons.css Normal file
View File

@ -0,0 +1,288 @@
/* ----------------------------------------------------------------------------
WordPress-style Buttons
=======================
Create a button by adding the `.button` class to an element. For backwards
compatibility, we support several other classes (such as `.button-secondary`),
but these will *not* work with the stackable classes described below.
Button Styles
-------------
To display a primary button style, add the `.button-primary` class to a button.
Button Sizes
------------
Adjust a button's size by adding the `.button-large` or `.button-small` class.
Button States
-------------
Lock the state of a button by adding the name of the pseudoclass as
an actual class (e.g. `.hover` for `:hover`).
TABLE OF CONTENTS:
------------------
1.0 - Button Layouts
2.0 - Default Button Style
3.0 - Primary Button Style
4.0 - Button Groups
---------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------------
1.0 - Button Layouts
---------------------------------------------------------------------------- */
.wp-core-ui .button,
.wp-core-ui .button-primary,
.wp-core-ui .button-secondary {
display: inline-block;
text-decoration: none;
font-size: 12px;
line-height: 23px;
height: 24px;
margin: 0;
padding: 0 10px 1px;
cursor: pointer;
border-width: 1px;
border-style: solid;
-webkit-border-radius: 3px;
-webkit-appearance: none;
border-radius: 3px;
white-space: nowrap;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* Remove the dotted border on :focus and the extra padding in Firefox */
.wp-core-ui button::-moz-focus-inner,
.wp-core-ui input[type="reset"]::-moz-focus-inner,
.wp-core-ui input[type="button"]::-moz-focus-inner,
.wp-core-ui input[type="submit"]::-moz-focus-inner {
border-width: 1px 0;
border-style: solid none;
border-color: transparent;
padding: 0;
}
.wp-core-ui .button.button-large,
.wp-core-ui .button-group.button-large .button {
height: 30px;
line-height: 28px;
padding: 0 12px 2px;
}
.wp-core-ui .button.button-small,
.wp-core-ui .button-group.button-small .button {
height: 21px;
line-height: 20px;
padding: 0 8px 1px;
}
.wp-core-ui .button.button-hero,
.wp-core-ui .button-group.button-hero .button {
font-size: 14px;
height: 46px;
line-height: 44px;
padding: 0 36px;
}
.wp-core-ui .button:active {
outline: none;
}
.wp-core-ui .button.hidden {
display: none;
}
/* ----------------------------------------------------------------------------
2.0 - Default Button Style
---------------------------------------------------------------------------- */
.wp-core-ui .button,
.wp-core-ui .button-secondary {
background: #f3f3f3;
background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#f4f4f4));
background-image: -webkit-linear-gradient(top, #fefefe, #f4f4f4);
background-image: -moz-linear-gradient(top, #fefefe, #f4f4f4);
background-image: -o-linear-gradient(top, #fefefe, #f4f4f4);
background-image: linear-gradient(to bottom, #fefefe, #f4f4f4);
border-color: #bbb;
color: #333;
text-shadow: 0 1px 0 #fff;
}
.wp-core-ui .button.hover,
.wp-core-ui .button:hover,
.wp-core-ui .button-secondary:hover,
.wp-core-ui .button.focus,
.wp-core-ui .button:focus,
.wp-core-ui .button-secondary:focus {
background: #f3f3f3;
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f3f3f3));
background-image: -webkit-linear-gradient(top, #fff, #f3f3f3);
background-image: -moz-linear-gradient(top, #fff, #f3f3f3);
background-image: -ms-linear-gradient(top, #fff, #f3f3f3);
background-image: -o-linear-gradient(top, #fff, #f3f3f3);
background-image: linear-gradient(to bottom, #fff, #f3f3f3);
border-color: #999;
color: #222;
}
.wp-core-ui .button.focus,
.wp-core-ui .button:focus,
.wp-core-ui .button-secondary:focus {
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
box-shadow: 1px 1px 1px rgba(0,0,0,.2);
}
.wp-core-ui .button.active,
.wp-core-ui .button.active:hover,
.wp-core-ui .button.active:focus,
.wp-core-ui .button:active,
.wp-core-ui .button-secondary:active {
background: #eee;
background-image: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#fefefe));
background-image: -webkit-linear-gradient(top, #f4f4f4, #fefefe);
background-image: -moz-linear-gradient(top, #f4f4f4, #fefefe);
background-image: -ms-linear-gradient(top, #f4f4f4, #fefefe);
background-image: -o-linear-gradient(top, #f4f4f4, #fefefe);
background-image: linear-gradient(to bottom, #f4f4f4, #fefefe);
border-color: #999;
color: #333;
text-shadow: 0 -1px 0 #fff;
-webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
}
.wp-core-ui .button[disabled],
.wp-core-ui .button:disabled,
.wp-core-ui .button-secondary[disabled],
.wp-core-ui .button-secondary:disabled,
.wp-core-ui .button-disabled {
color: #aaa !important;
border-color: #ddd !important;
background-image: -webkit-gradient(linear, left top, left bottom, from(#f9f9f9), to(#f4f4f4)) !important;
background-image: -webkit-linear-gradient(top, #f9f9f9, #f4f4f4) !important;
background-image: -moz-linear-gradient(top, #f9f9f9, #f4f4f4) !important;
background-image: -ms-linear-gradient(top, #f9f9f9, #f4f4f4) !important;
background-image: -o-linear-gradient(top, #f9f9f9, #f4f4f4) !important;
background-image: linear-gradient(to bottom, #f9f9f9, #f4f4f4) !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
text-shadow: 0 1px 0 #fff !important;
cursor: default;
}
/* ----------------------------------------------------------------------------
3.0 - Primary Button Style
---------------------------------------------------------------------------- */
.wp-core-ui .button-primary {
background-color: #21759b;
background-image: -webkit-gradient(linear, left top, left bottom, from(#2a95c5), to(#21759b));
background-image: -webkit-linear-gradient(top, #2a95c5, #21759b);
background-image: -moz-linear-gradient(top, #2a95c5, #21759b);
background-image: -ms-linear-gradient(top, #2a95c5, #21759b);
background-image: -o-linear-gradient(top, #2a95c5, #21759b);
background-image: linear-gradient(to bottom, #2a95c5, #21759b);
border-color: #21759b;
border-bottom-color: #1e6a8d;
-webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.5);
box-shadow: inset 0 1px 0 rgba(120,200,230,0.5);
color: #fff;
text-decoration: none;
text-shadow: 0 1px 0 rgba(0,0,0,0.1);
}
.wp-core-ui .button-primary.hover,
.wp-core-ui .button-primary:hover,
.wp-core-ui .button-primary.focus,
.wp-core-ui .button-primary:focus {
background-color: #278ab7;
background-image: -webkit-gradient(linear, left top, left bottom, from(#2e9fd2), to(#21759b));
background-image: -webkit-linear-gradient(top, #2e9fd2, #21759b);
background-image: -moz-linear-gradient(top, #2e9fd2, #21759b);
background-image: -ms-linear-gradient(top, #2e9fd2, #21759b);
background-image: -o-linear-gradient(top, #2e9fd2, #21759b);
background-image: linear-gradient(to bottom, #2e9fd2, #21759b);
border-color: #1b607f;
-webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.6);
box-shadow: inset 0 1px 0 rgba(120,200,230,0.6);
color: #fff;
text-shadow: 0 -1px 0 rgba(0,0,0,0.3);
}
.wp-core-ui .button-primary.focus,
.wp-core-ui .button-primary:focus {
border-color: #0e3950;
-webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.6), 1px 1px 2px rgba(0,0,0,0.4);
box-shadow: inset 0 1px 0 rgba(120,200,230,0.6), 1px 1px 2px rgba(0,0,0,0.4);
}
.wp-core-ui .button-primary.active,
.wp-core-ui .button-primary.active:hover,
.wp-core-ui .button-primary.active:focus,
.wp-core-ui .button-primary:active {
background: #1b607f;
background-image: -webkit-gradient(linear, left top, left bottom, from(#21759b), to(#278ab7));
background-image: -webkit-linear-gradient(top, #21759b, #278ab7);
background-image: -moz-linear-gradient(top, #21759b, #278ab7);
background-image: -ms-linear-gradient(top, #21759b, #278ab7);
background-image: -o-linear-gradient(top, #21759b, #278ab7);
background-image: linear-gradient(to bottom, #21759b, #278ab7);
border-color: #124560 #2382ae #2382ae #2382ae;
color: rgba(255,255,255,0.95);
-webkit-box-shadow: inset 0 1px 0 rgba(0,0,0,0.1);
box-shadow: inset 0 1px 0 rgba(0,0,0,0.1);
text-shadow: 0 1px 0 rgba(0,0,0,0.1);
}
.wp-core-ui .button-primary[disabled],
.wp-core-ui .button-primary:disabled,
.wp-core-ui .button-primary-disabled {
color: #94cde7 !important;
background: #298cba !important;
border-color: #1b607f !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
text-shadow: 0 -1px 0 rgba(0,0,0,0.1) !important;
cursor: default;
}
/* ----------------------------------------------------------------------------
4.0 - Button Groups
---------------------------------------------------------------------------- */
.wp-core-ui .button-group {
position: relative;
display: inline-block;
white-space: nowrap;
font-size: 0;
vertical-align: middle;
}
.wp-core-ui .button-group > .button {
display: inline-block;
border-radius: 0;
margin-right: -1px;
z-index: 10;
}
.wp-core-ui .button-group > .button-primary {
z-index: 100;
}
.wp-core-ui .button-group > .button:hover {
z-index: 20;
}
.wp-core-ui .button-group > .button:first-child {
border-radius: 3px 0 0 3px;
}
.wp-core-ui .button-group > .button:last-child {
border-radius: 0 3px 3px 0;
}

1
wp-includes/css/buttons.min.css vendored Normal file

File diff suppressed because one or more lines are too long

2116
wp-includes/css/editor.css Normal file

File diff suppressed because it is too large Load Diff

1
wp-includes/css/editor.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,139 @@
/*
* jQuery UI CSS Framework @VERSION
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
* jQuery UI Resizable
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Resizable#theming
*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
/*
* jQuery UI Dialog
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Dialog#theming
*/
.wp-dialog { position: absolute; width: 300px; overflow: hidden; }
.wp-dialog .ui-dialog-titlebar { position: relative; }
.wp-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.wp-dialog .ui-dialog-content { position: relative; border: 0; padding: 0; background: none; overflow: auto; zoom: 1; }
.wp-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.wp-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
.wp-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
.wp-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
/* WP jQuery Dialog Theme */
.wp-dialog {
border: 1px solid #999;
-webkit-box-shadow: 0px 0px 16px rgba( 0,0,0,0.3 );
box-shadow: 0px 0px 16px rgba( 0,0,0,0.3 );
}
.wp-dialog .ui-dialog-title {
display: block;
text-align: center;
padding: 1px 0 2px;
}
.wp-dialog .ui-dialog-titlebar {
padding: 0 1em;
background-color: #444;
font-weight: bold;
font-size: 11px;
line-height: 18px;
color: #e5e5e5;
}
.wp-dialog {
background-color: #f5f5f5;
-webkit-border-top-left-radius: 4px;
border-top-left-radius: 4px;
-webkit-border-top-right-radius: 4px;
border-top-right-radius: 4px;
}
.wp-dialog .ui-dialog-titlebar {
-webkit-border-top-left-radius: 3px;
border-top-left-radius: 3px;
-webkit-border-top-right-radius: 3px;
border-top-right-radius: 3px;
}
.wp-dialog .ui-dialog-titlebar-close {
position: absolute;
width: 29px;
height: 16px;
top: 2px;
right: 6px;
background: url('../js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif') no-repeat -87px -16px;
padding: 0;
}
.wp-dialog .ui-dialog-titlebar-close:hover,
.wp-dialog .ui-dialog-titlebar-close:focus {
background-position: -87px -32px;
}
.ui-widget-overlay {
background-color: #000;
opacity: 0.6;
filter: alpha(opacity=60);
}

View File

@ -0,0 +1 @@
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{position:absolute;left:-99999999px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ui-helper-clearfix{display:inline-block}/*\*/* html .ui-helper-clearfix{height:1%}.ui-helper-clearfix{display:block}/**/.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:.1px;z-index:99999;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.wp-dialog{position:absolute;width:300px;overflow:hidden}.wp-dialog .ui-dialog-titlebar{position:relative}.wp-dialog .ui-dialog-titlebar-close span{display:block;margin:1px}.wp-dialog .ui-dialog-content{position:relative;border:0;padding:0;background:0;overflow:auto;zoom:1}.wp-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin:.5em 0 0 0;padding:.3em 1em .5em .4em}.wp-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.wp-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.wp-dialog .ui-resizable-se{width:14px;height:14px;right:3px;bottom:3px}.ui-draggable .ui-dialog-titlebar{cursor:move}.wp-dialog{border:1px solid #999;-webkit-box-shadow:0 0 16px rgba(0,0,0,0.3);box-shadow:0 0 16px rgba(0,0,0,0.3)}.wp-dialog .ui-dialog-title{display:block;text-align:center;padding:1px 0 2px}.wp-dialog .ui-dialog-titlebar{padding:0 1em;background-color:#444;font-weight:bold;font-size:11px;line-height:18px;color:#e5e5e5}.wp-dialog{background-color:#f5f5f5;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-webkit-border-top-right-radius:4px;border-top-right-radius:4px}.wp-dialog .ui-dialog-titlebar{-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-top-right-radius:3px;border-top-right-radius:3px}.wp-dialog .ui-dialog-titlebar-close{position:absolute;width:29px;height:16px;top:2px;right:6px;background:url('../js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif') no-repeat -87px -16px;padding:0}.wp-dialog .ui-dialog-titlebar-close:hover,.wp-dialog .ui-dialog-titlebar-close:focus{background-position:-87px -32px}.ui-widget-overlay{background-color:#000;opacity:.6;filter:alpha(opacity=60)}

View File

@ -0,0 +1,303 @@
/**
* Modal
*/
.media-modal-close {
right: auto;
left: 7px;
}
/**
* Toolbar
*/
.media-toolbar-primary {
float: left;
}
.media-toolbar-secondary {
float: right;
}
.media-toolbar-primary > .media-button,
.media-toolbar-primary > .media-button-group {
margin-left: 0;
margin-right: 10px;
float: right;
}
.media-toolbar-secondary > .media-button,
.media-toolbar-secondary > .media-button-group {
margin-right: 0;
margin-left: 10px;
float: right;
}
/**
* Sidebar
*/
.media-sidebar {
right: auto;
left: 0;
border-left: 0;
border-right: 1px solid #dfdfdf;
}
.media-sidebar .setting {
float: right;
}
.media-sidebar .setting span {
margin-right: 0;
margin-left: 4%;
}
.media-sidebar .setting span,
.compat-item label span {
float: right;
text-align: left;
}
.media-sidebar .setting input,
.media-sidebar .setting textarea {
float: left;
}
.compat-item {
float: right;
}
.compat-item .label {
margin-right: 0;
margin-left: 4%;
float: right;
text-align: left;
}
.compat-item .field {
float: left;
padding-right: 0;
padding-left: 1px;
}
/**
* Menu
*/
.media-menu {
border-right: 0;
border-left: 1px solid #d9d9d9;
box-shadow: inset 6px 0 6px -6px rgba( 0, 0, 0, 0.2 )
}
/**
* Router
*/
.media-router > a {
float: right;
border-right: 0;
border-left: 1px solid #dfdfdf;
}
.media-router > a:last-child {
border-left: 0;
}
/**
* Frame
*/
.media-frame-menu {
left: auto;
right: 0;
}
.media-frame-title,
.media-frame-router,
.media-frame-content,
.media-frame-toolbar {
left: 0;
right: 200px;
}
.media-frame.hide-menu .media-frame-title,
.media-frame.hide-menu .media-frame-router,
.media-frame.hide-menu .media-frame-toolbar,
.media-frame.hide-menu .media-frame-content {
right: 0;
}
.media-frame.hide-menu .media-frame-menu {
left: auto;
right: -200px;
}
/**
* Attachment Browser Filters
*/
.media-frame select.attachment-filters {
margin-right: 0;
margin-left: 10px;
}
/**
* Search
*/
.media-toolbar-secondary .search {
margin-right: 0;
margin-left: 16px;
}
/**
* Attachments
*/
.attachments {
padding-right: 0;
padding-left: 16px;
}
/**
* Attachment
*/
.attachment {
float: right;
}
.attachment .thumbnail {
left: auto;
right: 0;
}
.attachment .close {
right: auto;
left: 5px;
}
.attachment .check {
right: auto;
left: -7px;
}
/**
* Attachments Browser
*/
.attachments-browser .media-toolbar {
right: 0;
left: 300px;
}
.attachments-browser .attachments,
.attachments-browser .uploader-inline {
right: 0;
left: 300px;
}
/**
* Progress Bar
*/
.attachment-preview .media-progress-bar {
left: auto;
right: 15%;
}
.media-sidebar .media-uploader-status .upload-dismiss-errors {
right: auto;
left: 0;
}
.upload-errors .upload-error-label {
margin-right: 0;
margin-left: 8px;
float: right;
margin-top: -3px;
}
/**
* Selection
*/
.media-selection {
right: 0;
left: 350px;
padding: 0 16px 0 0;
}
.media-selection .selection-info {
margin-right: 0;
margin-left: 10px;
}
.media-selection .selection-info a {
float: right;
border-right: 0;
border-left: 1px solid #dfdfdf;
margin: 1px -8px 1px 8px;
}
.media-selection .selection-info a:last-child {
border-right: 1px;
border-left: 0;
margin-left: 0;
margin-right: -8px;
}
.media-selection:after {
right: auto;
left: 0;
background-image: -webkit-gradient(linear, left top, right top, from( rgba( 255, 255, 255, 1 ) ), to( rgba( 255, 255, 255, 0 ) ));
background-image: -webkit-linear-gradient(left, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
background-image: -moz-linear-gradient(left, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
background-image: -o-linear-gradient(left, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
background-image: linear-gradient(to right, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
}
/**
* Attachment Details
*/
.attachment-info .thumbnail {
float: right;
margin-right: 0;
margin-left: 10px;
}
.attachment-info .details {
float: right;
}
/**
* Attachment Display Settings
*/
.attachment-display-settings {
float: right;
}
/**
* Embed from URL
*/
.embed-url span {
display: block;
padding: 4px 2px 6px 0;
}
.media-embed .thumbnail {
float: right;
}
.media-embed .setting {
float: right;
}
/**
* Responsive layout
*/
@media only screen and (max-width: 900px) {
.media-frame-title,
.media-frame-router,
.media-frame-content,
.media-frame-toolbar {
left: 0;
right: 140px;
}
.attachments-browser .attachments,
.attachments-browser .uploader-inline,
.attachments-browser .media-toolbar {
right: 0;
left: 180px;
}
}

View File

@ -0,0 +1 @@
.media-modal-close{right:auto;left:7px}.media-toolbar-primary{float:left}.media-toolbar-secondary{float:right}.media-toolbar-primary>.media-button,.media-toolbar-primary>.media-button-group{margin-left:0;margin-right:10px;float:right}.media-toolbar-secondary>.media-button,.media-toolbar-secondary>.media-button-group{margin-right:0;margin-left:10px;float:right}.media-sidebar{right:auto;left:0;border-left:0;border-right:1px solid #dfdfdf}.media-sidebar .setting{float:right}.media-sidebar .setting span{margin-right:0;margin-left:4%}.media-sidebar .setting span,.compat-item label span{float:right;text-align:left}.media-sidebar .setting input,.media-sidebar .setting textarea{float:left}.compat-item{float:right}.compat-item .label{margin-right:0;margin-left:4%;float:right;text-align:left}.compat-item .field{float:left;padding-right:0;padding-left:1px}.media-menu{border-right:0;border-left:1px solid #d9d9d9;box-shadow:inset 6px 0 6px -6px rgba(0,0,0,0.2)}.media-router>a{float:right;border-right:0;border-left:1px solid #dfdfdf}.media-router>a:last-child{border-left:0}.media-frame-menu{left:auto;right:0}.media-frame-title,.media-frame-router,.media-frame-content,.media-frame-toolbar{left:0;right:200px}.media-frame.hide-menu .media-frame-title,.media-frame.hide-menu .media-frame-router,.media-frame.hide-menu .media-frame-toolbar,.media-frame.hide-menu .media-frame-content{right:0}.media-frame.hide-menu .media-frame-menu{left:auto;right:-200px}.media-frame select.attachment-filters{margin-right:0;margin-left:10px}.media-toolbar-secondary .search{margin-right:0;margin-left:16px}.attachments{padding-right:0;padding-left:16px}.attachment{float:right}.attachment .thumbnail{left:auto;right:0}.attachment .close{right:auto;left:5px}.attachment .check{right:auto;left:-7px}.attachments-browser .media-toolbar{right:0;left:300px}.attachments-browser .attachments,.attachments-browser .uploader-inline{right:0;left:300px}.attachment-preview .media-progress-bar{left:auto;right:15%}.media-sidebar .media-uploader-status .upload-dismiss-errors{right:auto;left:0}.upload-errors .upload-error-label{margin-right:0;margin-left:8px;float:right;margin-top:-3px}.media-selection{right:0;left:350px;padding:0 16px 0 0}.media-selection .selection-info{margin-right:0;margin-left:10px}.media-selection .selection-info a{float:right;border-right:0;border-left:1px solid #dfdfdf;margin:1px -8px 1px 8px}.media-selection .selection-info a:last-child{border-right:1px;border-left:0;margin-left:0;margin-right:-8px}.media-selection:after{right:auto;left:0;background-image:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,1)),to(rgba(255,255,255,0)));background-image:-webkit-linear-gradient(left,rgba(255,255,255,1),rgba(255,255,255,0));background-image:-moz-linear-gradient(left,rgba(255,255,255,1),rgba(255,255,255,0));background-image:-o-linear-gradient(left,rgba(255,255,255,1),rgba(255,255,255,0));background-image:linear-gradient(to right,rgba(255,255,255,1),rgba(255,255,255,0))}.attachment-info .thumbnail{float:right;margin-right:0;margin-left:10px}.attachment-info .details{float:right}.attachment-display-settings{float:right}.embed-url span{display:block;padding:4px 2px 6px 0}.media-embed .thumbnail{float:right}.media-embed .setting{float:right}@media only screen and (max-width:900px){.media-frame-title,.media-frame-router,.media-frame-content,.media-frame-toolbar{left:0;right:140px}.attachments-browser .attachments,.attachments-browser .uploader-inline,.attachments-browser .media-toolbar{right:0;left:180px}}

File diff suppressed because it is too large Load Diff

1
wp-includes/css/media-views.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,228 @@
.wp-pointer {
}
.wp-pointer-content {
padding: 0 0 10px;
position: relative;
font-size: 13px;
background: #fff;
border-style: solid;
border-width: 1px;
/* Fallback for non-rgba-compliant browsers */
border-color: #dfdfdf;
/* Use rgba to look better against non-white backgrounds. */
border-color: rgba(0,0,0,.125);
-webkit-border-radius: 3px;
border-radius: 3px;
-webkit-box-shadow: 0 2px 4px rgba(0,0,0,.19);
box-shadow: 0 2px 4px rgba(0,0,0,.19);
}
.wp-pointer-content h3 {
position: relative;
margin: 0 0 5px;
padding: 15px 18px 14px 60px;
line-height: 1.4em;
font-size: 14px;
color: #fff;
border-radius: 3px 3px 0 0;
text-shadow: 0 -1px 0 rgba(0,0,0,0.3);
background: #8cc1e9;
background-image: -webkit-gradient(linear, left bottom, left top, from(#72a7cf), to(#8cc1e9));
background-image: -webkit-linear-gradient(bottom, #72a7cf, #8cc1e9);
background-image: -moz-linear-gradient(bottom, #72a7cf, #8cc1e9);
background-image: -o-linear-gradient(bottom, #72a7cf, #8cc1e9);
background-image: linear-gradient(to top, #72a7cf, #8cc1e9);
}
.wp-pointer-content h3:before {
position: absolute;
top: 0;
left: 15px;
content: ' ';
width: 36px;
height: 100%;
background: url('../images/icon-pointer-flag.png') 0 50% no-repeat;
}
.wp-pointer-content p {
padding: 0 15px;
}
.wp-pointer-buttons {
margin: 0;
padding: 5px 15px;
overflow: auto;
}
.wp-pointer-buttons a {
float: right;
display: inline-block;
text-decoration: none;
}
.wp-pointer-buttons a.close {
padding-left:3px;
position: relative;
}
.wp-pointer-buttons a.close:before {
content: ' ';
width:10px;
height:100%;
position:absolute;
left:-10px;
background:url('../images/xit.gif') 0 50% no-repeat;
}
.wp-pointer-buttons a.close:hover:before {
background-position:100% 50%;
}
/* The arrow base class must take up no space, even with transparent borders. */
.wp-pointer-arrow,
.wp-pointer-arrow-inner {
position: absolute;
width: 0;
height: 0;
}
.wp-pointer-arrow {
z-index: 10;
background:url('../images/arrow-pointer-blue.png') 0 0 no-repeat;
}
.wp-pointer-arrow-inner {
z-index: 20;
}
/* Make Room for the Arrow! */
.wp-pointer-top,
.wp-pointer-undefined {
padding-top: 13px;
}
.wp-pointer-bottom {
padding-bottom: 13px;
}
.wp-pointer-left {
padding-left: 13px;
}
.wp-pointer-right {
padding-right: 13px;
}
/* Base Size & Positioning */
.wp-pointer-top .wp-pointer-arrow,
.wp-pointer-bottom .wp-pointer-arrow,
.wp-pointer-undefined .wp-pointer-arrow {
left: 50px;
width: 30px;
height: 14px;
}
.wp-pointer-left .wp-pointer-arrow,
.wp-pointer-right .wp-pointer-arrow {
top: 50%;
margin-top: -15px;
width: 14px;
height: 30px;
}
/* Arrow Sprite */
.wp-pointer-top .wp-pointer-arrow,
.wp-pointer-undefined .wp-pointer-arrow {
top: 0;
background-position: 0 0;
}
.wp-pointer-bottom .wp-pointer-arrow {
bottom: 0;
background-position: 0 -46px;
}
.wp-pointer-left .wp-pointer-arrow {
left: 0;
background-position: 0 -15px;
}
.wp-pointer-right .wp-pointer-arrow {
right:0;
background-position:-16px -15px;
}
/* - RTL
------------------------------------------------------------------------------*/
.rtl .wp-pointer-content h3 {
padding-right: 60px;
padding-left: 18px;
}
.rtl .wp-pointer-content h3:before {
right: 15px;
}
.rtl .wp-pointer-buttons a {
float: left;
}
.rtl .wp-pointer-buttons a.close {
padding-right:3px;
padding-left: 0;
}
.rtl .wp-pointer-buttons a.close:before {
right:-10px;
}
.rtl .wp-pointer-top .wp-pointer-arrow,
.rtl .wp-pointer-bottom .wp-pointer-arrow,
.rtl .wp-pointer-undefined .wp-pointer-arrow {
right: 50px;
}
/**
* HiDPI Displays
*/
@media print,
(-o-min-device-pixel-ratio: 5/4),
(-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
.wp-pointer-buttons a.close:before {
background-image: url('../images/xit-2x.gif');
background-size: 20px auto;
}
.wp-pointer-content h3:before {
background-image: url('../images/icon-pointer-flag-2x.png');
background-size: 36px auto;
}
.wp-pointer-arrow {
background: url('../images/arrow-pointer-blue-2x.png') 0 0 no-repeat;
background-size: 30px 60px;
}
.wp-pointer-top .wp-pointer-arrow,
.wp-pointer-undefined .wp-pointer-arrow {
background-position: 0 1px;
}
.wp-pointer-bottom .wp-pointer-arrow {
background-position: 0 -47px;
}
.wp-pointer-left .wp-pointer-arrow {
background-position: 1px -15px;
}
.wp-pointer-right .wp-pointer-arrow {
background-position:-17px -15px;
}
}

1
wp-includes/css/wp-pointer.min.css vendored Normal file
View File

@ -0,0 +1 @@
.wp-pointer-content{padding:0 0 10px;position:relative;font-size:13px;background:#fff;border-style:solid;border-width:1px;border-color:#dfdfdf;border-color:rgba(0,0,0,.125);-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 2px 4px rgba(0,0,0,.19);box-shadow:0 2px 4px rgba(0,0,0,.19)}.wp-pointer-content h3{position:relative;margin:0 0 5px;padding:15px 18px 14px 60px;line-height:1.4em;font-size:14px;color:#fff;border-radius:3px 3px 0 0;text-shadow:0 -1px 0 rgba(0,0,0,0.3);background:#8cc1e9;background-image:-webkit-gradient(linear,left bottom,left top,from(#72a7cf),to(#8cc1e9));background-image:-webkit-linear-gradient(bottom,#72a7cf,#8cc1e9);background-image:-moz-linear-gradient(bottom,#72a7cf,#8cc1e9);background-image:-o-linear-gradient(bottom,#72a7cf,#8cc1e9);background-image:linear-gradient(to top,#72a7cf,#8cc1e9)}.wp-pointer-content h3:before{position:absolute;top:0;left:15px;content:' ';width:36px;height:100%;background:url('../images/icon-pointer-flag.png') 0 50% no-repeat}.wp-pointer-content p{padding:0 15px}.wp-pointer-buttons{margin:0;padding:5px 15px;overflow:auto}.wp-pointer-buttons a{float:right;display:inline-block;text-decoration:none}.wp-pointer-buttons a.close{padding-left:3px;position:relative}.wp-pointer-buttons a.close:before{content:' ';width:10px;height:100%;position:absolute;left:-10px;background:url('../images/xit.gif') 0 50% no-repeat}.wp-pointer-buttons a.close:hover:before{background-position:100% 50%}.wp-pointer-arrow,.wp-pointer-arrow-inner{position:absolute;width:0;height:0}.wp-pointer-arrow{z-index:10;background:url('../images/arrow-pointer-blue.png') 0 0 no-repeat}.wp-pointer-arrow-inner{z-index:20}.wp-pointer-top,.wp-pointer-undefined{padding-top:13px}.wp-pointer-bottom{padding-bottom:13px}.wp-pointer-left{padding-left:13px}.wp-pointer-right{padding-right:13px}.wp-pointer-top .wp-pointer-arrow,.wp-pointer-bottom .wp-pointer-arrow,.wp-pointer-undefined .wp-pointer-arrow{left:50px;width:30px;height:14px}.wp-pointer-left .wp-pointer-arrow,.wp-pointer-right .wp-pointer-arrow{top:50%;margin-top:-15px;width:14px;height:30px}.wp-pointer-top .wp-pointer-arrow,.wp-pointer-undefined .wp-pointer-arrow{top:0;background-position:0 0}.wp-pointer-bottom .wp-pointer-arrow{bottom:0;background-position:0 -46px}.wp-pointer-left .wp-pointer-arrow{left:0;background-position:0 -15px}.wp-pointer-right .wp-pointer-arrow{right:0;background-position:-16px -15px}.rtl .wp-pointer-content h3{padding-right:60px;padding-left:18px}.rtl .wp-pointer-content h3:before{right:15px}.rtl .wp-pointer-buttons a{float:left}.rtl .wp-pointer-buttons a.close{padding-right:3px;padding-left:0}.rtl .wp-pointer-buttons a.close:before{right:-10px}.rtl .wp-pointer-top .wp-pointer-arrow,.rtl .wp-pointer-bottom .wp-pointer-arrow,.rtl .wp-pointer-undefined .wp-pointer-arrow{right:50px}@media print,(-o-min-device-pixel-ratio:5/4),(-webkit-min-device-pixel-ratio:1.25),(min-resolution:120dpi){.wp-pointer-buttons a.close:before{background-image:url('../images/xit-2x.gif');background-size:20px auto}.wp-pointer-content h3:before{background-image:url('../images/icon-pointer-flag-2x.png');background-size:36px auto}.wp-pointer-arrow{background:url('../images/arrow-pointer-blue-2x.png') 0 0 no-repeat;background-size:30px 60px}.wp-pointer-top .wp-pointer-arrow,.wp-pointer-undefined .wp-pointer-arrow{background-position:0 1px}.wp-pointer-bottom .wp-pointer-arrow{background-position:0 -47px}.wp-pointer-left .wp-pointer-arrow{background-position:1px -15px}.wp-pointer-right .wp-pointer-arrow{background-position:-17px -15px}}

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