/libs/Chat/src/containers/file.class.php
PHP | 301 lines | 209 code | 44 blank | 48 comment | 47 complexity | 79af252cc3a55b8d1d2f5d7281650ec7 MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0
- <?php
- /**
- * file.class.php
- *
- * Copyright ??? 2006 Stephane Gully <stephane.gully@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
- require_once dirname(__FILE__)."/../pfccontainerinterface.class.php";
- /**
- * pfcContainer_File is a concret container which stock data into files
- *
- * @author Stephane Gully <stephane.gully@gmail.com>
- */
- class pfcContainer_File extends pfcContainerInterface
- {
- var $_users = array("nickid" => array(),
- "timestamp" => array());
- var $_meta = array();
-
- function pfcContainer_File()
- {
- pfcContainerInterface::pfcContainerInterface();
- }
-
- function loadPaths(&$c)
- {
- if (!isset($c->container_cfg_chat_dir) || $c->container_cfg_chat_dir == '')
- $c->container_cfg_chat_dir = $c->data_private_path."_chat";
- if (!isset($c->container_cfg_server_dir) || $c->container_cfg_server_dir == '')
- $c->container_cfg_server_dir = $c->container_cfg_chat_dir."_s_".$c->serverid;
- }
-
- function getDefaultConfig()
- {
- $cfg = pfcContainerInterface::getDefaultConfig();
- $cfg["chat_dir"] = ''; // will be generated from the other parameters into the init step
- $cfg["server_dir"] = ''; // will be generated from the other parameters into the init step
- return $cfg;
- }
-
- function init(&$c)
- {
- $errors = pfcContainerInterface::init($c);
- // generate the container parameters from other config parameters
- $this->loadPaths($c);
-
- $errors = array_merge($errors, @test_writable_dir($c->container_cfg_chat_dir, "container_cfg_chat_dir"));
- $errors = array_merge($errors, @test_writable_dir($c->container_cfg_server_dir, "container_cfg_chat_dir/serverid"));
- // test the filemtime php function because it doesn't work on special filesystem
- // example : NFS, VZFS
- $filename = $c->data_private_path.'_filemtime.test';
- $timetowait = 2;
- if (is_writable(dirname($filename)))
- {
- file_put_contents($filename,'some-data1-'.time());
- clearstatcache();
- $time1 = filemtime($filename);
- sleep($timetowait);
- file_put_contents($filename,'some-data2-'.time());
- clearstatcache();
- $time2 = filemtime($filename);
- unlink($filename);
- if ($time2-$time1 != $timetowait)
- $errors[] = "filemtime php fuction is not usable on your filesystem. Please do not use the 'file' container (try the 'mysql' container) or swith to another filesystem type.";
- }
- // test the LOCK_EX feature because it doesn't work on special filsystem like NFS
- $filename = $c->data_private_path.'_filemtime.test';
- if (is_writable(dirname($filename)))
- {
- $data1 = time();
- file_put_contents($filename, $data1, LOCK_EX);
- $data2 = file_get_contents($filename);
- if ($data1 != $data2)
- $errors[] = "LOCK_EX feature is not usable on your filesystem. Please do not use the 'file' container (try the 'mysql' container) or swith to another filesystem type.";
- }
- return $errors;
- }
- function setMeta($group, $subgroup, $leaf, $leafvalue = NULL)
- {
- $c =& pfcGlobalConfig::Instance();
- // create directories
- $dir_base = $c->container_cfg_server_dir;
- $dir = $dir_base.'/'.$group.'/'.$subgroup;
- if (!is_dir($dir)) mkdir_r($dir);
-
- // create or replace metadata file
- $leaffilename = $dir."/".$leaf;
- $leafexists = file_exists($leaffilename);
- if ($leafvalue == NULL)
- {
- @unlink($leaffilename);
- touch($leaffilename);
- }
- else
- {
- file_put_contents($leaffilename, $leafvalue, LOCK_EX);
- }
- // store the value in the memory cache
- //@todo
- // $this->_meta[$enc_type][$enc_subtype][$enc_key] = $value;
- if ($leafexists)
- return 1; // value overwritten
- else
- return 0; // value created
- }
- function getMeta($group, $subgroup = null, $leaf = null, $withleafvalue = false)
- {
- $c =& pfcGlobalConfig::Instance();
-
- // read data from metadata file
- $ret = array();
- $ret["timestamp"] = array();
- $ret["value"] = array();
- $dir_base = $c->container_cfg_server_dir;
- $dir = $dir_base.'/'.$group;
- if ($subgroup == NULL)
- {
- if (is_dir($dir))
- {
- $dh = opendir($dir);
- while (false !== ($file = readdir($dh)))
- {
- if ($file == "." || $file == "..") continue; // skip . and .. generic files
- $ret["timestamp"][] = filemtime($dir.'/'.$file);
- $ret["value"][] = $file;
- }
- closedir($dh);
- }
- return $ret;
- }
-
- $dir .= '/'.$subgroup;
- if ($leaf == NULL)
- {
- if (is_dir($dir))
- {
- $dh = opendir($dir);
- while (false !== ($file = readdir($dh)))
- {
- if ($file == "." || $file == "..") continue; // skip . and .. generic files
- $ret["timestamp"][] = filemtime($dir.'/'.$file);
- $ret["value"][] = $file;
- }
- closedir($dh);
- }
- return $ret;
- }
-
- $leaffilename = $dir."/".$leaf;
- if (!file_exists($leaffilename)) return $ret;
- if ($withleafvalue)
- $ret["value"][] = file_get_contents_flock($leaffilename);
- else
- $ret["value"][] = NULL;
- $ret["timestamp"][] = filemtime($leaffilename);
- return $ret;
- }
- function incMeta($group, $subgroup, $leaf)
- {
- $c =& pfcGlobalConfig::Instance();
- // create directories
- $dir_base = $c->container_cfg_server_dir;
- $dir = $dir_base.'/'.$group.'/'.$subgroup;
- if (!is_dir($dir)) mkdir_r($dir);
-
- // create or replace metadata file
- $leaffilename = $dir."/".$leaf;
- // create return array
- $ret = array();
- $ret["timestamp"] = array();
- $ret["value"] = array();
- // read and increment data from metadata file
- clearstatcache();
- if (file_exists($leaffilename))
- {
- $fh = fopen($leaffilename, 'r+');
- for($i = 0; $i < 10; $i++) // Try 10 times until an exclusive lock can be obtained
- {
- if (flock($fh, LOCK_EX))
- {
- $leafvalue = chop(fread($fh, filesize($leaffilename)));
- $leafvalue++;
- rewind($fh);
- fwrite($fh, $leafvalue);
- fflush($fh);
- ftruncate($fh, ftell($fh));
- flock($fh, LOCK_UN);
- break;
- }
- // If flock is working properly, this will never be reached
- $delay = rand(0, pow(2, ($i+1)) - 1) * 5000; // Exponential backoff
- usleep($delay);
- }
- fclose($fh);
- }
- else
- {
- $leafvalue="1";
- file_put_contents($leaffilename, $leafvalue, LOCK_EX);
- }
-
- $ret["value"][] = $leafvalue;
- $ret["timestamp"][] = filemtime($leaffilename);
- return $ret;
- }
- function rmMeta($group, $subgroup = null, $leaf = null)
- {
- $c =& pfcGlobalConfig::Instance();
-
- $dir = $c->container_cfg_server_dir;
- if ($group == NULL)
- {
- rm_r($dir);
- return true;
- }
- $dir .= '/'.$group;
- if ($subgroup == NULL)
- {
- rm_r($dir);
- return true;
- }
-
- $dir .= '/'.$subgroup;
- if ($leaf == NULL)
- {
- rm_r($dir);
- return true;
- }
-
- $leaffilename = $dir.'/'.$leaf;
- if (!file_exists($leaffilename)) return false;
- unlink($leaffilename);
-
- // check that the directory is empty or not
- // remove it if it doesn't contains anything
- $dh = opendir($dir);
- readdir($dh); readdir($dh); // skip . and .. directories
- $isnotempty = readdir($dh);
- closedir($dh);
- if ($isnotempty === false) rmdir($dir);
-
- return true;
- }
- /**
- * Used to encode UTF8 strings to ASCII filenames
- */
- function encode($str)
- {
- return urlencode($str);
- }
-
- /**
- * Used to decode ASCII filenames to UTF8 strings
- */
- function decode($str)
- {
- return urldecode($str);
- }
- }
- ?>