[ Index ]

PHP Cross Reference of phool

title

Body

[close]

/Phool/ -> Persistent.php (source)

   1  <?php
   2  //============================================================================
   3  // This program is free software: you can redistribute it and/or modify
   4  // it under the terms of the GNU Lesser General Public License (LGPL) as
   5  // published by the Free Software Foundation, either version 3 of the License,
   6  // or (at your option) any later version.
   7  //
   8  // This program is distributed in the hope that it will be useful,
   9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11  // GNU Lesser General Public License for more details.
  12  //
  13  // You should have received a copy of the GNU Lesser General Public License
  14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
  15  //============================================================================
  16  //=============================================================================
  17  /**
  18  * @copyright Francois Laupretre <phool@tekwire.net>
  19  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, V 2.0
  20  * @category phool
  21  * @package phool
  22  */
  23  //============================================================================
  24  
  25  namespace Phool;
  26  
  27  //============================================================================
  28  /**
  29  * This abstract class implements an object which can be saved and retrieved
  30  * to/from a file on  disk.
  31  *
  32  * It exposes the {@link load()} and {@link save()} methods.
  33  *
  34  * It also provides a checksum mechanism transparent to the descendant
  35  * class. Everytime an object is read from storage, its checksum is computed
  36  *  and compared to the value that was stored at save() time.
  37  *
  38  * The descendant class must define two methods named serialize and
  39  * unserialize to transmit/retrieve the data to save.
  40  *
  41  * Note: Late static binding would allow to access the descendant class
  42  * properties and get the magic string from the toplevel class at runtime.
  43  * Unfortunately, it is implemented in versions of PHP >= 5.3, which is too
  44  * restrictive. So, we use another way.
  45  */
  46  
  47  //----------------------------------------------------------------------------
  48  
  49  abstract class Persistent extends Modifiable
  50  {
  51  // @var string The magic string to write and check
  52  
  53  private $magic;
  54  
  55  // @var string The last loaded path. Allows to call save() without argument.
  56  
  57  private $path=null;
  58  
  59  //----------------------------------------------------------------------------
  60  /**
  61  * Return the properties to save as a string
  62  *
  63  * @return string
  64  */
  65  
  66  abstract protected function serialize();
  67  
  68  //----------------------------------------------------------------------------
  69  /**
  70  * Restore data from the result of a previous {@link __serialize()} execution
  71  *
  72  * @param mixed $data The data returned by a previous {@link __serialize()}
  73  * execution
  74  *
  75  * @return void
  76  */
  77  
  78  abstract protected function unserialize($data);
  79  
  80  //----------------------------------------------------------------------------
  81  /**
  82  * Class constructor
  83  *
  84  * @param string $magic The magic string to use when writing/reading a file
  85  * @param string|null $path A file to load if not null
  86  * @return void
  87  */
  88  
  89  protected function __construct($magic,$path=null)
  90  {
  91  $this->magic=$magic;
  92  parent::__construct();
  93  if (!is_null($path)) $this->load($path);
  94  }
  95  
  96  //----------------------------------------------------------------------------
  97  /**
  98  * Records a path
  99  *
 100  * @param string $path
 101  * @return void
 102  */
 103  
 104  public function setPath($path)
 105  {
 106  $this->path=$path;
 107  }
 108  
 109  //----------------------------------------------------------------------------
 110  /**
 111  * Restore data from a save()d file
 112  *
 113  * @param string $path Path of the file to load
 114  * @return void
 115  * @throws Exception if file cannot be loaded
 116  */
 117  
 118  public function load($path)
 119  {
 120  if (!file_exists($path)) throw new \Exception("$path: File does not exist");
 121  
 122  try
 123      {
 124      $buf=file_get_contents($path);
 125      if ($buf===false) throw new \Exception("$path: Cannot get file contents");
 126      //-- Check magic
 127      if (substr($buf,0,strlen($this->magic))!==$this->magic)
 128          throw new \Exception("Bad magic string");
 129      //-- Skip magic string
 130      $buf=substr($buf,strlen($this->magic));
 131      //-- Unserialize toplevel array
 132      $a=unserialize($buf);
 133      if ((!is_array($a))
 134          ||(!array_key_exists('crc',$a))
 135          ||(!array_key_exists('data',$a)))
 136          throw new \Exception('Invalid format');
 137  
 138      $data=$a['data'];
 139      if (crc32($data) !== $a['crc'])
 140          throw new \Exception('Wrong checksum');
 141  
 142      $this->unserialize($data);
 143      }
 144  catch (\Exception $e)
 145      {
 146      throw new \Exception("$path: Cannot load file: ".$e->getMessage());
 147      }
 148  
 149  $this->setPath($path);
 150  }
 151  
 152  //----------------------------------------------------------------------------
 153  /**
 154  * Save data to a file on disk
 155  *
 156  * @param string|null $path Path to save or null if same as load()
 157  * @return void
 158  * @throws Exception if write failed or path cannot be determined
 159  */
 160  
 161  public function save($path=null)
 162  {
 163  if (is_null($path))
 164      {
 165      if (is_null($this->path))
 166          throw new \Exception('Save path cannot be determined');
 167      $path=$this->path;
 168      }
 169  
 170  $value=$this->serialize(); // Call toplevel method
 171  $data=serialize(array(
 172      'crc' => crc32($value),
 173      'data' => $value
 174      ));
 175  
 176  if (file_put_contents($path,$this->magic.$data)===false)
 177      throw new \Exception("$path: Cannot write file");
 178  
 179  //-- Write is OK. Now we can clear the 'modified' flag
 180  
 181  parent::clearModified();
 182  }
 183  
 184  //----------------------------------------------------------------------------
 185  /**
 186  * Save object to a file if it was modified since last load() or save()
 187  *
 188  * @param string|null $path Path to save or null if same as load()
 189  * @return void
 190  * @throws Exception if write failed
 191  */
 192  
 193  public function saveIfModified($path=null)
 194  {
 195  if ($this->modified()) $this->save($path);
 196  }
 197  
 198  } // End of class
 199  ?>


Generated: Thu Jun 4 19:17:11 2015 Cross-referenced by PHPXref 0.7.1