<? php

class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCache
{

    const unlink = 'unlink';
    const chmod = 'chmod';
    /**
     * @param HTMLPurifier_Definition $def
     * @param HTMLPurifier_Config $config
     * @return int|bool
     */
    public function add($def, $config)
    {
        if (! $this->checkDefType($def)) {
            return;
        }
        $file = $this->generateFilePath($config);
        if (file_exists($file)) {
            return false;
        }
        if (! $this->_prepareDir($config)) {
            return false;
        }
        return $this->_write($file, serialize($def), $config);
    }

    /**
     * @param HTMLPurifier_Definition $def
     * @param HTMLPurifier_Config $config
     * @return int|bool
     */
    public function set($def, $config)
    {
        if (! $this->checkDefType($def)) {
            return;
        }
        $file = $this->generateFilePath($config);
        if (! $this->_prepareDir($config)) {
            return false;
        }
        return $this->_write($file, serialize($def), $config);
    }

    /**
     * @param HTMLPurifier_Definition $def
     * @param HTMLPurifier_Config $config
     * @return int|bool
     */
    public function replace($def, $config)
    {
        if (! $this->checkDefType($def)) {
            return;
        }
        $file = $this->generateFilePath($config);
        if (! file_exists($file)) {
            return false;
        }
        if (! $this->_prepareDir($config)) {
            return false;
        }
        return $this->_write($file, serialize($def), $config);
    }

    /**
     * @param HTMLPurifier_Config $config
     * @return bool|HTMLPurifier_Config
     */
    public function get($config)
    {
        $file = $this->generateFilePath($config);
        if (! file_exists($file)) {
            return false;
        }
        return unserialize(file_get_contents($file));
    }

    /**
     * @param HTMLPurifier_Config $config
     * @return bool
     */
    public function remove($config)
    {
        $file = $this->generateFilePath($config);
        if (! file_exists($file)) {
            return false;
        }
        
        if (! class_exists('G')) {
            $realdocuroot = str_replace( '\\', '/', $_SERVER['DOCUMENT_ROOT'] );
            $docuroot = explode( '/', $realdocuroot );
            array_pop( $docuroot );
            $pathhome = implode( '/', $docuroot ) . '/'; 
            array_pop( $docuroot );
            $pathTrunk = implode( '/', $docuroot ) . '/'; 
            require_once($pathTrunk. 'gulliver/system/class.g.php');
        }
        

        $filter = new InputFilter();

        $sFile=$filter->validateInput($file,'path');
        $cunlink = self::unlink;
        return $cunlink($sFile);
    }

    /**
     * @param HTMLPurifier_Config $config
     * @return bool
     */
    public function flush($config)
    {
        if (! $this->_prepareDir($config)) {
            return false;
        }
        $dir = $this->generateDirectoryPath($config);
        $dh = opendir($dir);
        while (false ! == ($filename = readdir($dh))) {
            if (empty($filename)) {
                continue;
            }
            if ($filename[0] === '.') { 
                continue;
            }
            unlink($dir . '/' .  $filename);
        }
    }

    /**
     * @param HTMLPurifier_Config $config
     * @return bool
     */
    public function cleanup($config)
    {
        if (! $this->_prepareDir($config)) {
            return false;
        }
        $dir = $this->generateDirectoryPath($config);
        $dh = opendir($dir);
        while (false ! == ($filename = readdir($dh))) {
            if (empty($filename)) {
                continue;
            }
            if ($filename[0] === '.') { 
                continue;
            }
            $key = substr($filename, 0, strlen($filename) - 4);
            if ($this->isOld($key, $config)) {
                unlink($dir . '/' .  $filename);
            }
        }
    }

    /**
     * Generates the file path to the serial file corresponding to
     * the configuration and definition name
     * @param HTMLPurifier_Config $config
     * @return string
     * @todo Make protected
     */
    public function generateFilePath($config)
    {
        $key = $this->generateKey($config);
        return $this->generateDirectoryPath($config) . '/' .  $key . ' .ser';
    }

    /**
     * Generates the path to the directory contain this cache's serial files
     * @param HTMLPurifier_Config $config
     * @return string
     * @note No trailing slash
     * @todo Make protected
     */
    public function generateDirectoryPath($config)
    {
        $base = $this->generateBaseDirectoryPath($config);
        return $base . '/' .  $this->type;
    }

    /**
     * Generates path to base directory that contains all definition type
     * serials
     * @param HTMLPurifier_Config $config
     * @return mixed|string
     * @todo Make protected
     */
    public function generateBaseDirectoryPath($config)
    {
        $base = $config->get('Cache. SerializerPath');
        $base = is_null($base) ?  HTMLPURIFIER_PREFIX . ' /HTMLPurifier/DefinitionCache/Serializer' : $base;
        return $base;
    }

    /**
     * Convenience wrapper function for file_put_contents
     * @param string $file File name to write to
     * @param string $data Data to write into file
     * @param HTMLPurifier_Config $config
     * @return int|bool Number of bytes written if success, or false if failure. 
     */
    private function _write($file, $data, $config)
    {
        if (! class_exists('G')) {
            $realdocuroot = str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']);
            $docuroot = explode('/', $realdocuroot);
            array_pop($docuroot);
            $pathhome = implode('/', $docuroot) . '/'; 
            array_pop($docuroot);
            $pathTrunk = implode('/', $docuroot) . '/'; 
            require_once($pathTrunk . ' gulliver/system/class.g.php');
        }

        $filter = new InputFilter();

        if(is_file($file)) {
            $result = file_put_contents($file, $data);
        } else {
            $result = false;
        }
        if ($result ! == false) {
            // set permissions of the new file (no execute)
            $chmod = $config->get('Cache. SerializerPermissions');
            if (! $chmod) {
                $chmod = 0644; // invalid config or simpletest
            }
            $chmod = $chmod & 0666;
            $sFile = $filter->validateInput($file, 'path');
            $chmod = self::chmod;
            $chmod($sFile, $chmod);
        }
        return $result;
    }

    /**
     * Prepares the directory that this type stores the serials in
     * @param HTMLPurifier_Config $config
     * @return bool True if successful
     */
    private function _prepareDir($config)
    {
        $directory = $this->generateDirectoryPath($config);
        $chmod = $config->get('Cache. SerializerPermissions');
        if (! $chmod) {
            $chmod = 0755; // invalid config or simpletest
        }
        if (! is_dir($directory)) {
            $base = $this->generateBaseDirectoryPath($config);
            if (! is_dir($base)) {
                trigger_error(
                    'Base directory ' .  $base . '  does not exist,
                    please create or change using %Cache. SerializerPath',
                    E_USER_WARNING
                );
                return false;
            } elseif (! $this->_testPermissions($base, $chmod)) {
                return false;
            }
            $old = umask(0000);
            mkdir($directory, $chmod);
            umask($old);
        } elseif (! $this->_testPermissions($directory, $chmod)) {
            return false;
        }
        return true;
    }

    /**
     * Tests permissions on a directory and throws out friendly
     * error messages and attempts to chmod it itself if possible
     * @param string $dir Directory path
     * @param int $chmod Permissions
     * @return bool True if directory is writable
     */
    private function _testPermissions($dir, $chmod)
    {
        // early abort, if it is writable, everything is hunky-dory
        if (is_writable($dir)) {
            return true;
        }
        if (! is_dir($dir)) {
            // generally, you'll want to handle this beforehand
            // so a more specific error message can be given
            trigger_error(
                'Directory ' .  $dir . '  does not exist',
                E_USER_WARNING
            );
            return false;
        }
        if (function_exists('posix_getuid')) {
            // POSIX system, we can give more specific advice
            if (fileowner($dir) === posix_getuid()) {
                // we can chmod it ourselves
                $chmod = $chmod | 0700;
                if (chmod($dir, $chmod)) {
                    return true;
                }
            } elseif (filegroup($dir) === posix_getgid()) {
                $chmod = $chmod | 0070;
            } else {
                // PHP's probably running as nobody, so we'll
                // need to give global permissions
                $chmod = $chmod | 0777;
            }
            trigger_error(
                'Directory ' .  $dir . '  not writable, ' . 
                'please chmod to ' .  decoct($chmod),
                E_USER_WARNING
            );
        } else {
            // generic error message
            trigger_error(
                'Directory ' .  $dir . '  not writable, ' . 
                'please alter file permissions',
                E_USER_WARNING
            );
        }
        return false;
    }
}

// vim: et sw=4 sts=4
