Autoría | Ultima modificación | Ver Log |
<?php/*** LICENSE** This file is part of CFPropertyList.** The PHP implementation of Apple's PropertyList can handle XML PropertyLists* as well as binary PropertyLists. It offers functionality to easily convert* data between worlds, e.g. recalculating timestamps from unix epoch to apple* epoch and vice versa. A feature to automagically create (guess) the plist* structure from a normal PHP data structure will help you dump your data to* plist in no time.** Copyright (c) 2018 Teclib'** Permission is hereby granted, free of charge, to any person obtaining a copy* of this software and associated documentation files (the "Software"), to deal* in the Software without restriction, including without limitation the rights* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell* copies of the Software, and to permit persons to whom the Software is* furnished to do so, subject to the following conditions:** The above copyright notice and this permission notice shall be included in all* copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE* SOFTWARE.** ------------------------------------------------------------------------------* @author Rodney Rehm <rodney.rehm@medialize.de>* @author Christian Kruse <cjk@wwwtech.de>* @copyright Copyright © 2018 Teclib* @package plist* @license MIT* @link https://github.com/TECLIB/CFPropertyList/* @link http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html Property Lists* ------------------------------------------------------------------------------*/namespace CFPropertyList;use DateTime;use Iterator;use stdClass;/*** CFTypeDetector* Interface for converting native PHP data structures to CFPropertyList objects.* @author Rodney Rehm <rodney.rehm@medialize.de>* @author Christian Kruse <cjk@wwwtech.de>* @package plist* @subpackage plist.types* @example example-create-02.php Using CFTypeDetector* @example example-create-03.php Using CFTypeDetector with CFDate and CFData* @example example-create-04.php Using and extended CFTypeDetector*/class CFTypeDetector{/*** flag stating if all arrays should automatically be converted to CFDictionary* @var boolean*/protected $autoDictionary = false;/*** flag stating if exceptions should be suppressed or thrown* @var boolean*/protected $suppressExceptions = false;/*** name of a method that will be used for array to object conversations* @var callable*/protected $objectToArrayMethod = null;/*** flag stating if "123.23" should be converted to float (true) or preserved as string (false)* @var boolean*/protected $castNumericStrings = true;/*** Create new CFTypeDetector* @param array $options Configuration for casting values [autoDictionary, suppressExceptions, objectToArrayMethod, castNumericStrings]*/public function __construct(array $options = array()){//$autoDicitionary=false,$suppressExceptions=false,$objectToArrayMethod=nullforeach ($options as $key => $value) {if (property_exists($this, $key)) {$this->$key = $value;}}}/*** Determine if an array is associative or numerical.* Numerical Arrays have incrementing index-numbers that don't contain gaps.* @param array $value Array to check indexes of* @return boolean true if array is associative, false if array has numeric indexes*/protected function isAssociativeArray($value){$numericKeys = true;$i = 0;foreach ($value as $key => $v) {if ($i !== $key) {$numericKeys = false;break;}$i++;}return !$numericKeys;}/*** Get the default value* @return CFType the default value to return if no suitable type could be determined*/protected function defaultValue(){return new CFString();}/*** Create CFType-structure by guessing the data-types.* CFArray, {@link CFDictionary}, {@link CFBoolean}, {@link CFNumber} and {@link CFString} can be created, {@link CFDate} and {@link CFData} cannot.* <br /><b>Note:</b>Distinguishing between {@link CFArray} and {@link CFDictionary} is done by examining the keys.* Keys must be strictly incrementing integers to evaluate to a {@link CFArray}.* Since PHP does not offer a function to test for associative arrays,* this test causes the input array to be walked twice and thus work rather slow on large collections.* If you work with large arrays and can live with all arrays evaluating to {@link CFDictionary},* feel free to set the appropriate flag.* <br /><b>Note:</b> If $value is an instance of CFType it is simply returned.* <br /><b>Note:</b> If $value is neither a CFType, array, numeric, boolean nor string, it is omitted.* @param mixed $value Value to convert to CFType* @return CFType CFType based on guessed type* @uses isAssociativeArray() to check if an array only has numeric indexes*/public function toCFType($value){switch (true) {case $value instanceof CFType:return $value;break;case is_object($value):// DateTime should be CFDateif ($value instanceof DateTime) {return new CFDate($value->getTimestamp());}// convert possible objects to arrays, arrays will be arraysif ($this->objectToArrayMethod && is_callable(array($value, $this->objectToArrayMethod))) {$value = call_user_func(array( $value, $this->objectToArrayMethod ));} else if ($value instanceof stdClass) {$value = (array) $value;}if (!is_array($value)) {if ($this->suppressExceptions) {return $this->defaultValue();}throw new PListException('Could not determine CFType for object of type '. get_class($value));}/* break; omitted */case $value instanceof Iterator:case is_array($value):// test if $value is simple or associative arrayif (!$this->autoDictionary) {if (!$this->isAssociativeArray($value)) {$t = new CFArray();foreach ($value as $v) {$t->add($this->toCFType($v));}return $t;}}$t = new CFDictionary();foreach ($value as $k => $v) {$t->add($k, $this->toCFType($v));}return $t;break;case is_bool($value):return new CFBoolean($value);break;case is_null($value):return new CFString();break;case is_resource($value):if ($this->suppressExceptions) {return $this->defaultValue();}throw new PListException('Could not determine CFType for resource of type '. get_resource_type($value));break;case is_numeric($value):if (!$this->castNumericStrings && is_string($value)) {return new CFString($value);}return new CFNumber($value);break;case is_string($value):if (strpos($value, "\x00") !== false) {return new CFData($value);}return new CFString($value);break;default:if ($this->suppressExceptions) {return $this->defaultValue();}throw new PListException('Could not determine CFType for '. gettype($value));break;}}}