<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4                                                        |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group                                |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license,      |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license@php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Authors: Tomas V.V.Cox <cox@idecnet.com>                             |
// |          Stig Bakken <ssb@fast.no>                                   |
// +----------------------------------------------------------------------+
//
// $Id: Dependency.php,v 1.5.2.1 2002/04/09 19:04:22 ssb Exp $

/**
* Methods for dependencies check. Based on Stig's dependencies RFC
* at http://cvs.php.net/cvs.php/pearweb/rfc
* (requires php >= 4.1)
*/

require_once "PEAR.php";

class PEAR_Dependency
{
    function PEAR_Dependency(&$registry)
    {
        $this->registry = &$registry;
    }
    /**
    * This method maps the xml dependency definition to the
    * PEAR_dependecy one
    *
    * $opts => Array
    *    (
    *        [type] => pkg
    *        [rel] => ge
    *        [version] => 3.4
    *        [name] => HTML_Common
    *    )
    */
    function callCheckMethod($opts)
    {
        $rel = isset($opts['rel']) ? $opts['rel'] : 'has';
        if (isset($opts['version'])) {
            $req = $opts['version'];
            $rel = 'v.' . $rel;
        } else {
            $req = null;
        }
        $name = isset($opts['name']) ? $opts['name'] : null;
        switch ($opts['type']) {
            case 'pkg':
                return $this->checkPackage($name, $req, $rel);
                break;
            case 'ext':
                return $this->checkExtension($name, $req, $rel);
                break;
            case 'php':
                return $this->checkPHP($req, $rel);
                break;
            case 'prog':
                return $this->checkProgram($name);
                break;
            case 'os':
                return $this->checkOS($name);
                break;
            case 'sapi':
                return $this->checkSAPI($name);
                break;
            default:
                return "'{$opts['type']}' dependencie type not supported";
        }
    }

    /**
     * Package dependencies check method
     *
     * @param string $name      Name of the package to test
     * @param string $version   The package version required
     * @param string $relation  How to compare versions with eachother
     *
     * @return mixed bool false if no error or the error string
     */
    function checkPackage($name, $req = null, $relation = 'has')
    {
        if (!$this->registry->packageExists($name)) {
            return "'$name' PEAR package is not installed";
        }
        if (substr($relation, 0, 2) == 'v.') {
            $pkg_ver = $this->registry->packageInfo($name, 'version');
            $operator = substr($relation, 2);
            if (!version_compare($pkg_ver, $req, $operator)) {
                return "'$name' PEAR package version " .
                        $this->signOperator($operator) . " $req is required";
            }
            return false;
        }
        return "Relation '$relation' with requirement '$req' is not supported";
    }

    /**
     * Extension dependencies check method
     *
     * @param string $name        Name of the extension to test
     * @param string $req_ext_ver Required extension version to compare with
     * @param string $relation    How to compare versions with eachother
     *
     * @return mixed bool false if no error or the error string
     */
    function checkExtension($name, $req = null, $relation = 'has')
    {
        // XXX (ssb): could we avoid loading the extension here?
        if (!extension_loaded($name)) {
            $dlext = OS_WINDOWS ? '.dll' : '.so';
            if (!@dl($name . $dlext)) {
                return "'$name' PHP extension is not installed";
            }
        }
        if ($relation == 'has') {
            return false;
        }
        if (substr($relation, 0, 2) == 'v.') {
            $ext_ver = phpversion($name);
            $operator = substr($relation, 2);
            if (!version_compare($ext_ver, $req, $operator)) {
                return "'$name' PHP extension version " .
                        $this->signOperator($operator) . " $req is required";
            }
        }
        return false;
    }

    /**
     * Operating system  dependencies check method
     *
     * @param string $os  Name of the operating system
     *
     * @return mixed bool false if no error or the error string
     */
    function checkOS($os)
    {
        // XXX Fixme: Implement a more flexible way, like
        // comma separated values or something similar to PEAR_OS

        // only 'has' relation is supported
        if ($os == PHP_OS) {
            return false;
        }
        return "'$os' operating system not supported";
    }

    /**
     * PHP version check method
     *
     * @param string $req   which version to compare
     * @param string $relation  how to compare the version
     *
     * @return mixed bool false if no error or the error string
     */
    function checkPHP($req, $relation = 'v.ge')
    {
        if (substr($relation, 0, 2) == 'v.') {
            $php_ver = phpversion();
            $operator = substr($relation, 2);
            if (!version_compare($php_ver, $req, $operator)) {
                return "PHP version " . $this->signOperator($operator) .
                       " $req is required";
            }
        }
        return false;
    }

    /**
     * External program check method.  Looks for executable files in
     * directories listed in the PATH environment variable.
     *
     * @param string $program   which program to look for
     *
     * @return mixed bool false if no error or the error string
     */
    function checkProgram($program)
    {
        // XXX FIXME honor safe mode
        $path_delim = OS_WINDOWS ? ';' : ':';
        $exe_suffix = OS_WINDOWS ? '.exe' : '';
        $path_elements = explode($path_delim, getenv('PATH'));
        foreach ($path_elements as $dir) {
            $file = $dir . DIRECTORY_SEPARATOR . $program . $exe_suffix;
            if (@file_exists($file) && @is_executable($file)) {
                return false;
            }
        }
        return "'$program' program is not present in the PATH";
    }

    /**
     * SAPI backend check method.  Version comparison is not yet
     * available here.
     *
     * @param string $name      name of SAPI backend
     * @param string $req   which version to compare
     * @param string $relation  how to compare versions (currently
     *                          hardcoded to 'has')
     * @return mixed bool false if no error or the error string
     */
    function checkSAPI($name, $req = null, $relation = 'has')
    {
        // XXX Fixme: There is no way to know if the user has or
        // not other SAPI backends installed than the installer one

        $sapi_backend = php_sapi_name();
        // Version comparisons not supported, sapi backends don't have
        // version information yet.
        if ($sapi_backend == $name) {
            return false;
        }
        return "'$sapi_backend' SAPI backend not supported";
    }

    /**
    * Converts text comparing operators to them sign equivalents
    * ex: 'ge' to '>='
    */
    function signOperator($operator)
    {
        switch($operator) {
            case 'lt': return '<';
            case 'le': return '<=';
            case 'gt': return '>';
            case 'ge': return '>=';
            case 'eq': return '==';
            case 'ne': return '!=';
            default:
                return $operator;
        }
    }
}

?>