Files
server/usr/share/psa-pear/pear/php/Horde/Pack.php
2026-01-07 20:52:11 +01:00

196 lines
5.8 KiB
PHP

<?php
/**
* Copyright 2013-2016 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @copyright 2013-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Pack
*/
/**
* A replacement for serialize()/json_encode() that will automatically
* use the most efficient serialization available based on the input.
*
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @copyright 2013-2016 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Pack
*/
class Horde_Pack
{
/* Default compress length (in bytes). */
const DEFAULT_COMPRESS = 128;
/* Mask for compressed data. */
const COMPRESS_MASK = 64;
/**
* Instance of Horde_Compress_Fast shared between all instances.
*
* @var Horde_Compress_Fast
*/
protected static $_compress;
/**
* Drivers. Shared between all instances.
*
* @var array
*/
protected static $_drivers = array();
/**
* Constructor.
*/
public function __construct()
{
if (empty(self::$_drivers)) {
$fi = new FilesystemIterator(__DIR__ . '/Pack/Driver');
$class_prefix = __CLASS__ . '_Driver_';
foreach ($fi as $val) {
if ($val->isFile()) {
$cname = $class_prefix . $val->getBasename('.php');
if (class_exists($cname) && $cname::supported()) {
$ob = new $cname();
self::$_drivers[$ob->id] = $ob;
}
}
}
krsort(self::$_drivers, SORT_NUMERIC);
self::$_compress = new Horde_Compress_Fast();
}
}
/**
*/
public function __sleep()
{
throw new LogicException('Object can not be serialized.');
}
/**
* Pack a string.
*
* @param mixed $data The data to pack.
* @param array $opts Additional options:
* <pre>
* - compress: (mixed) If false, don't use compression. If true, uses
* default compress length (DEFAULT). If 0, always compress.
* All other integer values: compress only if data is
* greater than this string length.
* - drivers: (array) Only use these drivers to pack. By default, driver
* to use is auto-determined.
* - phpob: (boolean) If true, the data contains PHP serializable
* objects (i.e. objects that have a PHP-specific serialized
* representation). If false, the data does not contain any of
* these objects. If not present, will auto-determine
* existence of these objects.
* </pre>
*
* @return string The packed string.
* @throws Horde_Pack_Exception
*/
public function pack($data, array $opts = array())
{
$opts = array_merge(array(
'compress' => true
), $opts);
if (!isset($opts['phpob'])) {
$auto = new Horde_Pack_Autodetermine($data);
$opts['phpob'] = $auto->phpob;
}
foreach (self::$_drivers as $key => $val) {
if (!empty($opts['phpob']) && !$val->phpob) {
continue;
}
if (isset($opts['drivers'])) {
if (!in_array(get_class($val), $opts['drivers'])) {
continue;
}
}
/* Format of data:
* First-byte:
* 1,2,4,8,16,32 - Reserved for pack format.
* 64 - Packed data has been compressed.
* 128 - RESERVED for future use (if set, indicates that initial
* byte will extend into next byte).
* Packed (and compressed data) follows this byte. */
try {
$packed = $val->pack($data);
} catch (Horde_Pack_Exception $e) {
continue;
}
if ($opts['compress'] !== false) {
if ($opts['compress'] === 0) {
$compress = true;
} else {
if ($opts['compress'] === true) {
$opts['compress'] = self::DEFAULT_COMPRESS;
}
$compress = strlen($packed) > $opts['compress'];
}
if ($compress) {
$packed = self::$_compress->compress($packed);
$key |= self::COMPRESS_MASK;
}
}
return pack('C', $key) . $packed;
}
throw new Horde_Pack_Exception('Could not pack data.');
}
/**
* Unpack a string.
*
* @param string $data The packed string.
*
* @return mixed The unpacked data.
* @throws Horde_Pack_Exception
*/
public function unpack($data)
{
if (!$data) {
return $data;
}
if (is_string($data)) {
$mask = unpack('C*', $data[0]);
$mask = reset($mask);
$data = substr($data, 1);
if ($mask & self::COMPRESS_MASK) {
$data = self::$_compress->decompress($data);
$mask ^= self::COMPRESS_MASK;
}
if (isset(self::$_drivers[$mask])) {
try {
return self::$_drivers[$mask]->unpack($data);
} catch (Horde_Pack_Exception $e) {
throw $e;
} catch (Exception $e) {
/* Unknown exceptions are handled with the throw below. */
}
}
}
throw new Horde_Pack_Exception('Could not unpack data');
}
}