Commit 05af75541f61a446c199ce55d0bce2d502b728de
1 parent
ce5876ea
basic graphviz support.
git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5998 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing
3 changed files
with
1363 additions
and
0 deletions
thirdparty/pear/Console/Getopt.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/* vim: set expandtab tabstop=4 shiftwidth=4: */ | ||
| 3 | +// +----------------------------------------------------------------------+ | ||
| 4 | +// | PHP Version 4 | | ||
| 5 | +// +----------------------------------------------------------------------+ | ||
| 6 | +// | Copyright (c) 1997-2003 The PHP Group | | ||
| 7 | +// +----------------------------------------------------------------------+ | ||
| 8 | +// | This source file is subject to version 3.0 of the PHP license, | | ||
| 9 | +// | that is bundled with this package in the file LICENSE, and is | | ||
| 10 | +// | available through the world-wide-web at the following url: | | ||
| 11 | +// | http://www.php.net/license/3_0.txt. | | ||
| 12 | +// | If you did not receive a copy of the PHP license and are unable to | | ||
| 13 | +// | obtain it through the world-wide-web, please send a note to | | ||
| 14 | +// | license@php.net so we can mail you a copy immediately. | | ||
| 15 | +// +----------------------------------------------------------------------+ | ||
| 16 | +// | Author: Andrei Zmievski <andrei@php.net> | | ||
| 17 | +// +----------------------------------------------------------------------+ | ||
| 18 | +// | ||
| 19 | +// $Id: Getopt.php,v 1.21.4.7 2003/12/05 21:57:01 andrei Exp $ | ||
| 20 | + | ||
| 21 | +require_once 'PEAR.php'; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * Command-line options parsing class. | ||
| 25 | + * | ||
| 26 | + * @author Andrei Zmievski <andrei@php.net> | ||
| 27 | + * | ||
| 28 | + */ | ||
| 29 | +class Console_Getopt { | ||
| 30 | + /** | ||
| 31 | + * Parses the command-line options. | ||
| 32 | + * | ||
| 33 | + * The first parameter to this function should be the list of command-line | ||
| 34 | + * arguments without the leading reference to the running program. | ||
| 35 | + * | ||
| 36 | + * The second parameter is a string of allowed short options. Each of the | ||
| 37 | + * option letters can be followed by a colon ':' to specify that the option | ||
| 38 | + * requires an argument, or a double colon '::' to specify that the option | ||
| 39 | + * takes an optional argument. | ||
| 40 | + * | ||
| 41 | + * The third argument is an optional array of allowed long options. The | ||
| 42 | + * leading '--' should not be included in the option name. Options that | ||
| 43 | + * require an argument should be followed by '=', and options that take an | ||
| 44 | + * option argument should be followed by '=='. | ||
| 45 | + * | ||
| 46 | + * The return value is an array of two elements: the list of parsed | ||
| 47 | + * options and the list of non-option command-line arguments. Each entry in | ||
| 48 | + * the list of parsed options is a pair of elements - the first one | ||
| 49 | + * specifies the option, and the second one specifies the option argument, | ||
| 50 | + * if there was one. | ||
| 51 | + * | ||
| 52 | + * Long and short options can be mixed. | ||
| 53 | + * | ||
| 54 | + * Most of the semantics of this function are based on GNU getopt_long(). | ||
| 55 | + * | ||
| 56 | + * @param array $args an array of command-line arguments | ||
| 57 | + * @param string $short_options specifies the list of allowed short options | ||
| 58 | + * @param array $long_options specifies the list of allowed long options | ||
| 59 | + * | ||
| 60 | + * @return array two-element array containing the list of parsed options and | ||
| 61 | + * the non-option arguments | ||
| 62 | + * | ||
| 63 | + * @access public | ||
| 64 | + * | ||
| 65 | + */ | ||
| 66 | + function getopt2($args, $short_options, $long_options = null) | ||
| 67 | + { | ||
| 68 | + return Console_Getopt::doGetopt(2, $args, $short_options, $long_options); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * This function expects $args to start with the script name (POSIX-style). | ||
| 73 | + * Preserved for backwards compatibility. | ||
| 74 | + * @see getopt2() | ||
| 75 | + */ | ||
| 76 | + function getopt($args, $short_options, $long_options = null) | ||
| 77 | + { | ||
| 78 | + return Console_Getopt::doGetopt(1, $args, $short_options, $long_options); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + /** | ||
| 82 | + * The actual implementation of the argument parsing code. | ||
| 83 | + */ | ||
| 84 | + function doGetopt($version, $args, $short_options, $long_options = null) | ||
| 85 | + { | ||
| 86 | + // in case you pass directly readPHPArgv() as the first arg | ||
| 87 | + if (PEAR::isError($args)) { | ||
| 88 | + return $args; | ||
| 89 | + } | ||
| 90 | + if (empty($args)) { | ||
| 91 | + return array(array(), array()); | ||
| 92 | + } | ||
| 93 | + $opts = array(); | ||
| 94 | + $non_opts = array(); | ||
| 95 | + | ||
| 96 | + settype($args, 'array'); | ||
| 97 | + | ||
| 98 | + if ($long_options) { | ||
| 99 | + sort($long_options); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + /* | ||
| 103 | + * Preserve backwards compatibility with callers that relied on | ||
| 104 | + * erroneous POSIX fix. | ||
| 105 | + */ | ||
| 106 | + if ($version < 2) { | ||
| 107 | + if (isset($args[0]{0}) && $args[0]{0} != '-') { | ||
| 108 | + array_shift($args); | ||
| 109 | + } | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + reset($args); | ||
| 113 | + while (list($i, $arg) = each($args)) { | ||
| 114 | + | ||
| 115 | + /* The special element '--' means explicit end of | ||
| 116 | + options. Treat the rest of the arguments as non-options | ||
| 117 | + and end the loop. */ | ||
| 118 | + if ($arg == '--') { | ||
| 119 | + $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); | ||
| 120 | + break; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) { | ||
| 124 | + $non_opts = array_merge($non_opts, array_slice($args, $i)); | ||
| 125 | + break; | ||
| 126 | + } elseif (strlen($arg) > 1 && $arg{1} == '-') { | ||
| 127 | + $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args); | ||
| 128 | + if (PEAR::isError($error)) | ||
| 129 | + return $error; | ||
| 130 | + } else { | ||
| 131 | + $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args); | ||
| 132 | + if (PEAR::isError($error)) | ||
| 133 | + return $error; | ||
| 134 | + } | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + return array($opts, $non_opts); | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + /** | ||
| 141 | + * @access private | ||
| 142 | + * | ||
| 143 | + */ | ||
| 144 | + function _parseShortOption($arg, $short_options, &$opts, &$args) | ||
| 145 | + { | ||
| 146 | + for ($i = 0; $i < strlen($arg); $i++) { | ||
| 147 | + $opt = $arg{$i}; | ||
| 148 | + $opt_arg = null; | ||
| 149 | + | ||
| 150 | + /* Try to find the short option in the specifier string. */ | ||
| 151 | + if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') | ||
| 152 | + { | ||
| 153 | + return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt"); | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + if (strlen($spec) > 1 && $spec{1} == ':') { | ||
| 157 | + if (strlen($spec) > 2 && $spec{2} == ':') { | ||
| 158 | + if ($i + 1 < strlen($arg)) { | ||
| 159 | + /* Option takes an optional argument. Use the remainder of | ||
| 160 | + the arg string if there is anything left. */ | ||
| 161 | + $opts[] = array($opt, substr($arg, $i + 1)); | ||
| 162 | + break; | ||
| 163 | + } | ||
| 164 | + } else { | ||
| 165 | + /* Option requires an argument. Use the remainder of the arg | ||
| 166 | + string if there is anything left. */ | ||
| 167 | + if ($i + 1 < strlen($arg)) { | ||
| 168 | + $opts[] = array($opt, substr($arg, $i + 1)); | ||
| 169 | + break; | ||
| 170 | + } else if (list(, $opt_arg) = each($args)) | ||
| 171 | + /* Else use the next argument. */; | ||
| 172 | + else | ||
| 173 | + return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + $opts[] = array($opt, $opt_arg); | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + /** | ||
| 182 | + * @access private | ||
| 183 | + * | ||
| 184 | + */ | ||
| 185 | + function _parseLongOption($arg, $long_options, &$opts, &$args) | ||
| 186 | + { | ||
| 187 | + @list($opt, $opt_arg) = explode('=', $arg); | ||
| 188 | + $opt_len = strlen($opt); | ||
| 189 | + | ||
| 190 | + for ($i = 0; $i < count($long_options); $i++) { | ||
| 191 | + $long_opt = $long_options[$i]; | ||
| 192 | + $opt_start = substr($long_opt, 0, $opt_len); | ||
| 193 | + | ||
| 194 | + /* Option doesn't match. Go on to the next one. */ | ||
| 195 | + if ($opt_start != $opt) | ||
| 196 | + continue; | ||
| 197 | + | ||
| 198 | + $opt_rest = substr($long_opt, $opt_len); | ||
| 199 | + | ||
| 200 | + /* Check that the options uniquely matches one of the allowed | ||
| 201 | + options. */ | ||
| 202 | + if ($opt_rest != '' && $opt{0} != '=' && | ||
| 203 | + $i + 1 < count($long_options) && | ||
| 204 | + $opt == substr($long_options[$i+1], 0, $opt_len)) { | ||
| 205 | + return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous"); | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + if (substr($long_opt, -1) == '=') { | ||
| 209 | + if (substr($long_opt, -2) != '==') { | ||
| 210 | + /* Long option requires an argument. | ||
| 211 | + Take the next argument if one wasn't specified. */; | ||
| 212 | + if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { | ||
| 213 | + return PEAR::raiseError("Console_Getopt: option --$opt requires an argument"); | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + } else if ($opt_arg) { | ||
| 217 | + return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument"); | ||
| 218 | + } | ||
| 219 | + | ||
| 220 | + $opts[] = array('--' . $opt, $opt_arg); | ||
| 221 | + return; | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + return PEAR::raiseError("Console_Getopt: unrecognized option --$opt"); | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + /** | ||
| 228 | + * Safely read the $argv PHP array across different PHP configurations. | ||
| 229 | + * Will take care on register_globals and register_argc_argv ini directives | ||
| 230 | + * | ||
| 231 | + * @access public | ||
| 232 | + * @return mixed the $argv PHP array or PEAR error if not registered | ||
| 233 | + */ | ||
| 234 | + function readPHPArgv() | ||
| 235 | + { | ||
| 236 | + global $argv; | ||
| 237 | + if (!is_array($argv)) { | ||
| 238 | + if (!@is_array($_SERVER['argv'])) { | ||
| 239 | + if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { | ||
| 240 | + return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)"); | ||
| 241 | + } | ||
| 242 | + return $GLOBALS['HTTP_SERVER_VARS']['argv']; | ||
| 243 | + } | ||
| 244 | + return $_SERVER['argv']; | ||
| 245 | + } | ||
| 246 | + return $argv; | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +?> |
thirdparty/pear/GraphViz.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ | ||
| 3 | + | ||
| 4 | +/** | ||
| 5 | + * Image_GraphViz | ||
| 6 | + * | ||
| 7 | + * Copyright (c) 2001-2006, Dr. Volker Göbbels <vmg@arachnion.de> and | ||
| 8 | + * Sebastian Bergmann <sb@sebastian-bergmann.de>. All rights reserved. | ||
| 9 | + * | ||
| 10 | + * LICENSE: This source file is subject to version 3.0 of the PHP license | ||
| 11 | + * that is available through the world-wide-web at the following URI: | ||
| 12 | + * http://www.php.net/license/3_0.txt. If you did not receive a copy of | ||
| 13 | + * the PHP License and are unable to obtain it through the web, please | ||
| 14 | + * send a note to license@php.net so we can mail you a copy immediately. | ||
| 15 | + * | ||
| 16 | + * @category Image | ||
| 17 | + * @package GraphViz | ||
| 18 | + * @author Dr. Volker Göbbels <vmg@arachnion.de> | ||
| 19 | + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> | ||
| 20 | + * @author Karsten Dambekalns <k.dambekalns@fishfarm.de> | ||
| 21 | + * @author Michael Lively Jr. <mlively@ft11.net> | ||
| 22 | + * @copyright 2001-2006 Sebastian Bergmann <sb@sebastian-bergmann.de> | ||
| 23 | + * @license http://www.php.net/license/3_0.txt PHP License 3.0 | ||
| 24 | + * @version CVS: $Id: GraphViz.php,v 1.25 2006/05/16 15:49:19 sebastian Exp $ | ||
| 25 | + * @link http://pear.php.net/package/Image_GraphViz | ||
| 26 | + * @since File available since Release 0.1 | ||
| 27 | + */ | ||
| 28 | + | ||
| 29 | +require_once 'System.php'; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * Interface to AT&T's GraphViz tools. | ||
| 33 | + * | ||
| 34 | + * The GraphViz class allows for the creation of and the work with directed | ||
| 35 | + * and undirected graphs and their visualization with AT&T's GraphViz tools. | ||
| 36 | + * | ||
| 37 | + * <code> | ||
| 38 | + * <?php | ||
| 39 | + * require_once 'Image/GraphViz.php'; | ||
| 40 | + * | ||
| 41 | + * $graph = new Image_GraphViz(); | ||
| 42 | + * | ||
| 43 | + * $graph->addNode( | ||
| 44 | + * 'Node1', | ||
| 45 | + * array( | ||
| 46 | + * 'URL' => 'http://link1', | ||
| 47 | + * 'label' => 'This is a label', | ||
| 48 | + * 'shape' => 'box' | ||
| 49 | + * ) | ||
| 50 | + * ); | ||
| 51 | + * | ||
| 52 | + * $graph->addNode( | ||
| 53 | + * 'Node2', | ||
| 54 | + * array( | ||
| 55 | + * 'URL' => 'http://link2', | ||
| 56 | + * 'fontsize' => '14' | ||
| 57 | + * ) | ||
| 58 | + * ); | ||
| 59 | + * | ||
| 60 | + * $graph->addNode( | ||
| 61 | + * 'Node3', | ||
| 62 | + * array( | ||
| 63 | + * 'URL' => 'http://link3', | ||
| 64 | + * 'fontsize' => '20' | ||
| 65 | + * ) | ||
| 66 | + * ); | ||
| 67 | + * | ||
| 68 | + * $graph->addEdge( | ||
| 69 | + * array( | ||
| 70 | + * 'Node1' => 'Node2' | ||
| 71 | + * ), | ||
| 72 | + * array( | ||
| 73 | + * 'label' => 'Edge Label' | ||
| 74 | + * ) | ||
| 75 | + * ); | ||
| 76 | + * | ||
| 77 | + * $graph->addEdge( | ||
| 78 | + * array( | ||
| 79 | + * 'Node1' => 'Node2' | ||
| 80 | + * ), | ||
| 81 | + * array( | ||
| 82 | + * 'color' => 'red' | ||
| 83 | + * ) | ||
| 84 | + * ); | ||
| 85 | + * | ||
| 86 | + * $graph->image(); | ||
| 87 | + * ?> | ||
| 88 | + * </code> | ||
| 89 | + * | ||
| 90 | + * @category Image | ||
| 91 | + * @package GraphViz | ||
| 92 | + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> | ||
| 93 | + * @author Dr. Volker Göbbels <vmg@arachnion.de> | ||
| 94 | + * @author Karsten Dambekalns <k.dambekalns@fishfarm.de> | ||
| 95 | + * @author Michael Lively Jr. <mlively@ft11.net> | ||
| 96 | + * @copyright Copyright © 2001-2006 Dr. Volker Göbbels <vmg@arachnion.de> and Sebastian Bergmann <sb@sebastian-bergmann.de> | ||
| 97 | + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 | ||
| 98 | + * @version Release: @package_version@ | ||
| 99 | + * @link http://pear.php.net/package/Image_GraphViz | ||
| 100 | + * @since Class available since Release 0.1 | ||
| 101 | + */ | ||
| 102 | +class Image_GraphViz | ||
| 103 | +{ | ||
| 104 | + /** | ||
| 105 | + * Path to GraphViz/dot command | ||
| 106 | + * | ||
| 107 | + * @var string | ||
| 108 | + */ | ||
| 109 | + var $dotCommand = 'dot'; | ||
| 110 | + | ||
| 111 | + /** | ||
| 112 | + * Path to GraphViz/neato command | ||
| 113 | + * | ||
| 114 | + * @var string | ||
| 115 | + */ | ||
| 116 | + var $neatoCommand = 'neato'; | ||
| 117 | + | ||
| 118 | + /** | ||
| 119 | + * Representation of the graph | ||
| 120 | + * | ||
| 121 | + * @var array | ||
| 122 | + */ | ||
| 123 | + var $graph; | ||
| 124 | + | ||
| 125 | + /** | ||
| 126 | + * Constructor. | ||
| 127 | + * | ||
| 128 | + * Setting the name of the Graph is useful for including multiple image maps on | ||
| 129 | + * one page. If not set, the graph will be named 'G'. | ||
| 130 | + * | ||
| 131 | + * @param boolean $directed Directed (TRUE) or undirected (FALSE) graph. | ||
| 132 | + * @param array $attributes Attributes of the graph | ||
| 133 | + * @param string $name Name of the Graph | ||
| 134 | + * @access public | ||
| 135 | + */ | ||
| 136 | + function Image_GraphViz($directed = TRUE, $attributes = array(), $name = NULL) | ||
| 137 | + { | ||
| 138 | + $this->setDirected($directed); | ||
| 139 | + $this->setAttributes($attributes); | ||
| 140 | + $this->graph['name'] = $name; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + /** | ||
| 144 | + * Output image of the graph in a given format. | ||
| 145 | + * | ||
| 146 | + * @param string Format of the output image. | ||
| 147 | + * This may be one of the formats supported by GraphViz. | ||
| 148 | + * @access public | ||
| 149 | + */ | ||
| 150 | + function image($format = 'svg') | ||
| 151 | + { | ||
| 152 | + if ($data = $this->fetch($format)) { | ||
| 153 | + $sendContentLengthHeader = TRUE; | ||
| 154 | + | ||
| 155 | + switch ($format) { | ||
| 156 | + case 'gif': | ||
| 157 | + case 'png': | ||
| 158 | + case 'wbmp': { | ||
| 159 | + header('Content-Type: image/' . $format); | ||
| 160 | + } | ||
| 161 | + break; | ||
| 162 | + | ||
| 163 | + case 'jpg': { | ||
| 164 | + header('Content-Type: image/jpeg'); | ||
| 165 | + } | ||
| 166 | + break; | ||
| 167 | + | ||
| 168 | + case 'pdf': { | ||
| 169 | + header('Content-Type: application/pdf'); | ||
| 170 | + } | ||
| 171 | + break; | ||
| 172 | + | ||
| 173 | + case 'svg': { | ||
| 174 | + header('Content-Type: image/svg+xml'); | ||
| 175 | + } | ||
| 176 | + break; | ||
| 177 | + | ||
| 178 | + default: { | ||
| 179 | + $sendContentLengthHeader = FALSE; | ||
| 180 | + } | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + if ($sendContentLengthHeader) { | ||
| 184 | + header('Content-Length: ' . strlen($data)); | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + echo $data; | ||
| 188 | + } | ||
| 189 | + } | ||
| 190 | + | ||
| 191 | + /** | ||
| 192 | + * Return image (data) of the graph in a given format. | ||
| 193 | + * | ||
| 194 | + * @param string Format of the output image. | ||
| 195 | + * This may be one of the formats supported by GraphViz. | ||
| 196 | + * @return string The image (data) created by GraphViz. | ||
| 197 | + * @access public | ||
| 198 | + * @since Method available since Release 1.1.0 | ||
| 199 | + */ | ||
| 200 | + function fetch($format = 'svg') | ||
| 201 | + { | ||
| 202 | + if ($file = $this->saveParsedGraph()) { | ||
| 203 | + $outputfile = $file . '.' . $format; | ||
| 204 | + $command = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand; | ||
| 205 | + $command .= ' -T' . escapeshellarg($format) . ' -o' . escapeshellarg($outputfile) . ' ' . escapeshellarg($file); | ||
| 206 | + | ||
| 207 | + @`$command`; | ||
| 208 | + @unlink($file); | ||
| 209 | + | ||
| 210 | + $fp = fopen($outputfile, 'rb'); | ||
| 211 | + | ||
| 212 | + if ($fp) { | ||
| 213 | + $data = fread($fp, filesize($outputfile)); | ||
| 214 | + fclose($fp); | ||
| 215 | + @unlink($outputfile); | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + return $data; | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + return FALSE; | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + /** | ||
| 225 | + * Render a given dot file into another format. | ||
| 226 | + * | ||
| 227 | + * @param string The absolute path of the dot file to use. | ||
| 228 | + * @param string The absolute path of the file to save to. | ||
| 229 | + * @param string Format of the output image. | ||
| 230 | + * This may be one of the formats supported by GraphViz. | ||
| 231 | + * @return bool True if the file was saved, false otherwise. | ||
| 232 | + * @access public | ||
| 233 | + */ | ||
| 234 | + function renderDotFile($dotfile, $outputfile, $format = 'svg') | ||
| 235 | + { | ||
| 236 | + if (file_exists($dotfile)) { | ||
| 237 | + $oldmtime = file_exists($outputfile) ? filemtime($outputfile) : 0; | ||
| 238 | + | ||
| 239 | + $command = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand; | ||
| 240 | + $command .= ' -T' . escapeshellarg($format) . ' -o' . escapeshellarg($outputfile) . ' ' . escapeshellarg($dotfile); | ||
| 241 | + | ||
| 242 | + @`$command`; | ||
| 243 | + | ||
| 244 | + if (file_exists($outputfile) && filemtime($outputfile) > $oldmtime) { | ||
| 245 | + return TRUE; | ||
| 246 | + } | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + return FALSE; | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + /** | ||
| 253 | + * Add a cluster to the graph. | ||
| 254 | + * | ||
| 255 | + * @param string ID. | ||
| 256 | + * @param array Title. | ||
| 257 | + * @param array Attributes of the cluster. | ||
| 258 | + * @access public | ||
| 259 | + */ | ||
| 260 | + function addCluster($id, $title, $attributes = array()) | ||
| 261 | + { | ||
| 262 | + $this->graph['clusters'][$id]['title'] = $title; | ||
| 263 | + $this->graph['clusters'][$id]['attributes'] = $attributes; | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + /** | ||
| 267 | + * Add a note to the graph. | ||
| 268 | + * | ||
| 269 | + * @param string Name of the node. | ||
| 270 | + * @param array Attributes of the node. | ||
| 271 | + * @param string Group of the node. | ||
| 272 | + * @access public | ||
| 273 | + */ | ||
| 274 | + function addNode($name, $attributes = array(), $group = 'default') | ||
| 275 | + { | ||
| 276 | + $this->graph['nodes'][$group][$name] = $attributes; | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + /** | ||
| 280 | + * Remove a node from the graph. | ||
| 281 | + * | ||
| 282 | + * @param Name of the node to be removed. | ||
| 283 | + * @access public | ||
| 284 | + */ | ||
| 285 | + function removeNode($name, $group = 'default') | ||
| 286 | + { | ||
| 287 | + if (isset($this->graph['nodes'][$group][$name])) { | ||
| 288 | + unset($this->graph['nodes'][$group][$name]); | ||
| 289 | + } | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + /** | ||
| 293 | + * Add an edge to the graph. | ||
| 294 | + * | ||
| 295 | + * Caveat! This cannot handle multiple identical edges. If you use non-numeric | ||
| 296 | + * IDs for the nodes, this will not do (too much) harm. For numeric IDs the | ||
| 297 | + * array_merge() that is used will change the keys when merging arrays, leading | ||
| 298 | + * to new nodes appearing in the graph. | ||
| 299 | + * | ||
| 300 | + * @param array Start and End node of the edge. | ||
| 301 | + * @param array Attributes of the edge. | ||
| 302 | + * @access public | ||
| 303 | + */ | ||
| 304 | + function addEdge($edge, $attributes = array()) | ||
| 305 | + { | ||
| 306 | + if (is_array($edge)) { | ||
| 307 | + $from = key($edge); | ||
| 308 | + $to = $edge[$from]; | ||
| 309 | + $id = $from . '_' . $to; | ||
| 310 | + | ||
| 311 | + if (!isset($this->graph['edges'][$id])) { | ||
| 312 | + $this->graph['edges'][$id] = $edge; | ||
| 313 | + } else { | ||
| 314 | + $this->graph['edges'][$id] = array_merge( | ||
| 315 | + $this->graph['edges'][$id], | ||
| 316 | + $edge | ||
| 317 | + ); | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + if (is_array($attributes)) { | ||
| 321 | + if (!isset($this->graph['edgeAttributes'][$id])) { | ||
| 322 | + $this->graph['edgeAttributes'][$id] = $attributes; | ||
| 323 | + } else { | ||
| 324 | + $this->graph['edgeAttributes'][$id] = array_merge( | ||
| 325 | + $this->graph['edgeAttributes'][$id], | ||
| 326 | + $attributes | ||
| 327 | + ); | ||
| 328 | + } | ||
| 329 | + } | ||
| 330 | + } | ||
| 331 | + } | ||
| 332 | + | ||
| 333 | + /** | ||
| 334 | + * Remove an edge from the graph. | ||
| 335 | + * | ||
| 336 | + * @param array Start and End node of the edge to be removed. | ||
| 337 | + * @access public | ||
| 338 | + */ | ||
| 339 | + function removeEdge($edge) | ||
| 340 | + { | ||
| 341 | + if (is_array($edge)) { | ||
| 342 | + $from = key($edge); | ||
| 343 | + $to = $edge[$from]; | ||
| 344 | + $id = $from . '_' . $to; | ||
| 345 | + | ||
| 346 | + if (isset($this->graph['edges'][$id])) { | ||
| 347 | + unset($this->graph['edges'][$id]); | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + if (isset($this->graph['edgeAttributes'][$id])) { | ||
| 351 | + unset($this->graph['edgeAttributes'][$id]); | ||
| 352 | + } | ||
| 353 | + } | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + /** | ||
| 357 | + * Add attributes to the graph. | ||
| 358 | + * | ||
| 359 | + * @param array Attributes to be added to the graph. | ||
| 360 | + * @access public | ||
| 361 | + */ | ||
| 362 | + function addAttributes($attributes) | ||
| 363 | + { | ||
| 364 | + if (is_array($attributes)) { | ||
| 365 | + $this->graph['attributes'] = array_merge( | ||
| 366 | + $this->graph['attributes'], | ||
| 367 | + $attributes | ||
| 368 | + ); | ||
| 369 | + } | ||
| 370 | + } | ||
| 371 | + | ||
| 372 | + /** | ||
| 373 | + * Set attributes of the graph. | ||
| 374 | + * | ||
| 375 | + * @param array Attributes to be set for the graph. | ||
| 376 | + * @access public | ||
| 377 | + */ | ||
| 378 | + function setAttributes($attributes) | ||
| 379 | + { | ||
| 380 | + if (is_array($attributes)) { | ||
| 381 | + $this->graph['attributes'] = $attributes; | ||
| 382 | + } | ||
| 383 | + } | ||
| 384 | + | ||
| 385 | + /** | ||
| 386 | + * Set directed/undirected flag for the graph. | ||
| 387 | + * | ||
| 388 | + * @param boolean Directed (TRUE) or undirected (FALSE) graph. | ||
| 389 | + * @access public | ||
| 390 | + */ | ||
| 391 | + function setDirected($directed) | ||
| 392 | + { | ||
| 393 | + if (is_bool($directed)) { | ||
| 394 | + $this->graph['directed'] = $directed; | ||
| 395 | + } | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + /** | ||
| 399 | + * Load graph from file. | ||
| 400 | + * | ||
| 401 | + * @param string File to load graph from. | ||
| 402 | + * @access public | ||
| 403 | + */ | ||
| 404 | + function load($file) | ||
| 405 | + { | ||
| 406 | + if ($serializedGraph = implode('', @file($file))) { | ||
| 407 | + $this->graph = unserialize($serializedGraph); | ||
| 408 | + } | ||
| 409 | + } | ||
| 410 | + | ||
| 411 | + /** | ||
| 412 | + * Save graph to file. | ||
| 413 | + * | ||
| 414 | + * @param string File to save the graph to. | ||
| 415 | + * @return mixed File the graph was saved to, FALSE on failure. | ||
| 416 | + * @access public | ||
| 417 | + */ | ||
| 418 | + function save($file = '') | ||
| 419 | + { | ||
| 420 | + $serializedGraph = serialize($this->graph); | ||
| 421 | + | ||
| 422 | + if (empty($file)) { | ||
| 423 | + $file = System::mktemp('graph_'); | ||
| 424 | + } | ||
| 425 | + | ||
| 426 | + if ($fp = @fopen($file, 'w')) { | ||
| 427 | + @fputs($fp, $serializedGraph); | ||
| 428 | + @fclose($fp); | ||
| 429 | + | ||
| 430 | + return $file; | ||
| 431 | + } | ||
| 432 | + | ||
| 433 | + return FALSE; | ||
| 434 | + } | ||
| 435 | + | ||
| 436 | + /** | ||
| 437 | + * Parse the graph into GraphViz markup. | ||
| 438 | + * | ||
| 439 | + * @return string GraphViz markup | ||
| 440 | + * @access public | ||
| 441 | + */ | ||
| 442 | + function parse() | ||
| 443 | + { | ||
| 444 | + if (isset($this->graph['name']) && is_string($this->graph['name'])) { | ||
| 445 | + $parsedGraph = "digraph " . $this->graph['name'] . " {\n"; | ||
| 446 | + } else { | ||
| 447 | + $parsedGraph = "digraph G {\n"; | ||
| 448 | + } | ||
| 449 | + | ||
| 450 | + if (isset($this->graph['attributes'])) { | ||
| 451 | + foreach ($this->graph['attributes'] as $key => $value) { | ||
| 452 | + $attributeList[] = $key . '="' . $value . '"'; | ||
| 453 | + } | ||
| 454 | + | ||
| 455 | + if (!empty($attributeList)) { | ||
| 456 | + $parsedGraph .= 'graph [ '.implode(',', $attributeList) . " ];\n"; | ||
| 457 | + } | ||
| 458 | + } | ||
| 459 | + | ||
| 460 | + if (isset($this->graph['nodes'])) { | ||
| 461 | + foreach($this->graph['nodes'] as $group => $nodes) { | ||
| 462 | + if ($group != 'default') { | ||
| 463 | + $parsedGraph .= sprintf( | ||
| 464 | + "subgraph \"cluster_%s\" {\nlabel=\"%s\";\n", | ||
| 465 | + | ||
| 466 | + $group, | ||
| 467 | + isset($this->graph['clusters'][$group]) ? $this->graph['clusters'][$group]['title'] : '' | ||
| 468 | + ); | ||
| 469 | + | ||
| 470 | + if (isset($this->graph['clusters'][$group]['attributes'])) { | ||
| 471 | + unset($attributeList); | ||
| 472 | + | ||
| 473 | + foreach ($this->graph['clusters'][$group]['attributes'] as $key => $value) { | ||
| 474 | + $attributeList[] = $key . '="' . $value . '"'; | ||
| 475 | + } | ||
| 476 | + | ||
| 477 | + if (!empty($attributeList)) { | ||
| 478 | + $parsedGraph .= implode(',', $attributeList) . ";\n"; | ||
| 479 | + } | ||
| 480 | + } | ||
| 481 | + } | ||
| 482 | + | ||
| 483 | + foreach($nodes as $node => $attributes) { | ||
| 484 | + unset($attributeList); | ||
| 485 | + | ||
| 486 | + foreach($attributes as $key => $value) { | ||
| 487 | + $attributeList[] = $key . '="' . $value . '"'; | ||
| 488 | + } | ||
| 489 | + | ||
| 490 | + if (!empty($attributeList)) { | ||
| 491 | + $parsedGraph .= sprintf( | ||
| 492 | + "\"%s\" [ %s ];\n", | ||
| 493 | + addslashes(stripslashes($node)), | ||
| 494 | + implode(',', $attributeList) | ||
| 495 | + ); | ||
| 496 | + } | ||
| 497 | + } | ||
| 498 | + | ||
| 499 | + if ($group != 'default') { | ||
| 500 | + $parsedGraph .= "}\n"; | ||
| 501 | + } | ||
| 502 | + } | ||
| 503 | + } | ||
| 504 | + | ||
| 505 | + if (isset($this->graph['edges'])) { | ||
| 506 | + foreach($this->graph['edges'] as $label => $node) { | ||
| 507 | + unset($attributeList); | ||
| 508 | + | ||
| 509 | + $from = key($node); | ||
| 510 | + $to = $node[$from]; | ||
| 511 | + | ||
| 512 | + foreach($this->graph['edgeAttributes'][$label] as $key => $value) { | ||
| 513 | + $attributeList[] = $key . '="' . $value . '"'; | ||
| 514 | + } | ||
| 515 | + | ||
| 516 | + $parsedGraph .= sprintf( | ||
| 517 | + '"%s" -> "%s"', | ||
| 518 | + addslashes(stripslashes($from)), | ||
| 519 | + addslashes(stripslashes($to)) | ||
| 520 | + ); | ||
| 521 | + | ||
| 522 | + if (!empty($attributeList)) { | ||
| 523 | + $parsedGraph .= sprintf( | ||
| 524 | + ' [ %s ]', | ||
| 525 | + implode(',', $attributeList) | ||
| 526 | + ); | ||
| 527 | + } | ||
| 528 | + | ||
| 529 | + $parsedGraph .= ";\n"; | ||
| 530 | + } | ||
| 531 | + } | ||
| 532 | + | ||
| 533 | + return $parsedGraph . "}\n"; | ||
| 534 | + } | ||
| 535 | + | ||
| 536 | + /** | ||
| 537 | + * Save GraphViz markup to file. | ||
| 538 | + * | ||
| 539 | + * @param string File to write the GraphViz markup to. | ||
| 540 | + * @return mixed File to which the GraphViz markup was | ||
| 541 | + * written, FALSE on failure. | ||
| 542 | + * @access public | ||
| 543 | + */ | ||
| 544 | + function saveParsedGraph($file = '') | ||
| 545 | + { | ||
| 546 | + $parsedGraph = $this->parse(); | ||
| 547 | + | ||
| 548 | + if (!empty($parsedGraph)) { | ||
| 549 | + if (empty($file)) { | ||
| 550 | + $file = System::mktemp('graph_'); | ||
| 551 | + } | ||
| 552 | + | ||
| 553 | + if ($fp = @fopen($file, 'w')) { | ||
| 554 | + @fputs($fp, $parsedGraph); | ||
| 555 | + @fclose($fp); | ||
| 556 | + | ||
| 557 | + return $file; | ||
| 558 | + } | ||
| 559 | + } | ||
| 560 | + | ||
| 561 | + return FALSE; | ||
| 562 | + } | ||
| 563 | +} | ||
| 564 | + | ||
| 565 | +/* | ||
| 566 | + * Local variables: | ||
| 567 | + * tab-width: 4 | ||
| 568 | + * c-basic-offset: 4 | ||
| 569 | + * c-hanging-comment-ender-p: nil | ||
| 570 | + * End: | ||
| 571 | + */ | ||
| 572 | +?> |
thirdparty/pear/System.php
0 → 100644
| 1 | +<?php | ||
| 2 | +// | ||
| 3 | +// +----------------------------------------------------------------------+ | ||
| 4 | +// | PHP Version 5 | | ||
| 5 | +// +----------------------------------------------------------------------+ | ||
| 6 | +// | Copyright (c) 1997-2004 The PHP Group | | ||
| 7 | +// +----------------------------------------------------------------------+ | ||
| 8 | +// | This source file is subject to version 3.0 of the PHP license, | | ||
| 9 | +// | that is bundled with this package in the file LICENSE, and is | | ||
| 10 | +// | available through the world-wide-web at the following url: | | ||
| 11 | +// | http://www.php.net/license/3_0.txt. | | ||
| 12 | +// | If you did not receive a copy of the PHP license and are unable to | | ||
| 13 | +// | obtain it through the world-wide-web, please send a note to | | ||
| 14 | +// | license@php.net so we can mail you a copy immediately. | | ||
| 15 | +// +----------------------------------------------------------------------+ | ||
| 16 | +// | Authors: Tomas V.V.Cox <cox@idecnet.com> | | ||
| 17 | +// +----------------------------------------------------------------------+ | ||
| 18 | +// | ||
| 19 | +// $Id: System.php,v 1.36 2004/06/15 16:33:46 pajoye Exp $ | ||
| 20 | +// | ||
| 21 | + | ||
| 22 | +require_once 'PEAR.php'; | ||
| 23 | +require_once 'Console/Getopt.php'; | ||
| 24 | + | ||
| 25 | +$GLOBALS['_System_temp_files'] = array(); | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | +* System offers cross plattform compatible system functions | ||
| 29 | +* | ||
| 30 | +* Static functions for different operations. Should work under | ||
| 31 | +* Unix and Windows. The names and usage has been taken from its respectively | ||
| 32 | +* GNU commands. The functions will return (bool) false on error and will | ||
| 33 | +* trigger the error with the PHP trigger_error() function (you can silence | ||
| 34 | +* the error by prefixing a '@' sign after the function call). | ||
| 35 | +* | ||
| 36 | +* Documentation on this class you can find in: | ||
| 37 | +* http://pear.php.net/manual/ | ||
| 38 | +* | ||
| 39 | +* Example usage: | ||
| 40 | +* if (!@System::rm('-r file1 dir1')) { | ||
| 41 | +* print "could not delete file1 or dir1"; | ||
| 42 | +* } | ||
| 43 | +* | ||
| 44 | +* In case you need to to pass file names with spaces, | ||
| 45 | +* pass the params as an array: | ||
| 46 | +* | ||
| 47 | +* System::rm(array('-r', $file1, $dir1)); | ||
| 48 | +* | ||
| 49 | +* @package System | ||
| 50 | +* @author Tomas V.V.Cox <cox@idecnet.com> | ||
| 51 | +* @version $Revision: 1.36 $ | ||
| 52 | +* @access public | ||
| 53 | +* @see http://pear.php.net/manual/ | ||
| 54 | +*/ | ||
| 55 | +class System | ||
| 56 | +{ | ||
| 57 | + /** | ||
| 58 | + * returns the commandline arguments of a function | ||
| 59 | + * | ||
| 60 | + * @param string $argv the commandline | ||
| 61 | + * @param string $short_options the allowed option short-tags | ||
| 62 | + * @param string $long_options the allowed option long-tags | ||
| 63 | + * @return array the given options and there values | ||
| 64 | + * @access private | ||
| 65 | + */ | ||
| 66 | + function _parseArgs($argv, $short_options, $long_options = null) | ||
| 67 | + { | ||
| 68 | + if (!is_array($argv) && $argv !== null) { | ||
| 69 | + $argv = preg_split('/\s+/', $argv); | ||
| 70 | + } | ||
| 71 | + return Console_Getopt::getopt2($argv, $short_options); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * Output errors with PHP trigger_error(). You can silence the errors | ||
| 76 | + * with prefixing a "@" sign to the function call: @System::mkdir(..); | ||
| 77 | + * | ||
| 78 | + * @param mixed $error a PEAR error or a string with the error message | ||
| 79 | + * @return bool false | ||
| 80 | + * @access private | ||
| 81 | + */ | ||
| 82 | + function raiseError($error) | ||
| 83 | + { | ||
| 84 | + if (PEAR::isError($error)) { | ||
| 85 | + $error = $error->getMessage(); | ||
| 86 | + } | ||
| 87 | + trigger_error($error, E_USER_WARNING); | ||
| 88 | + return false; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + /** | ||
| 92 | + * Creates a nested array representing the structure of a directory | ||
| 93 | + * | ||
| 94 | + * System::_dirToStruct('dir1', 0) => | ||
| 95 | + * Array | ||
| 96 | + * ( | ||
| 97 | + * [dirs] => Array | ||
| 98 | + * ( | ||
| 99 | + * [0] => dir1 | ||
| 100 | + * ) | ||
| 101 | + * | ||
| 102 | + * [files] => Array | ||
| 103 | + * ( | ||
| 104 | + * [0] => dir1/file2 | ||
| 105 | + * [1] => dir1/file3 | ||
| 106 | + * ) | ||
| 107 | + * ) | ||
| 108 | + * @param string $sPath Name of the directory | ||
| 109 | + * @param integer $maxinst max. deep of the lookup | ||
| 110 | + * @param integer $aktinst starting deep of the lookup | ||
| 111 | + * @return array the structure of the dir | ||
| 112 | + * @access private | ||
| 113 | + */ | ||
| 114 | + | ||
| 115 | + function _dirToStruct($sPath, $maxinst, $aktinst = 0) | ||
| 116 | + { | ||
| 117 | + $struct = array('dirs' => array(), 'files' => array()); | ||
| 118 | + if (($dir = @opendir($sPath)) === false) { | ||
| 119 | + System::raiseError("Could not open dir $sPath"); | ||
| 120 | + return $struct; // XXX could not open error | ||
| 121 | + } | ||
| 122 | + $struct['dirs'][] = $sPath; // XXX don't add if '.' or '..' ? | ||
| 123 | + $list = array(); | ||
| 124 | + while ($file = readdir($dir)) { | ||
| 125 | + if ($file != '.' && $file != '..') { | ||
| 126 | + $list[] = $file; | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + closedir($dir); | ||
| 130 | + sort($list); | ||
| 131 | + if ($aktinst < $maxinst || $maxinst == 0) { | ||
| 132 | + foreach($list as $val) { | ||
| 133 | + $path = $sPath . DIRECTORY_SEPARATOR . $val; | ||
| 134 | + if (is_dir($path)) { | ||
| 135 | + $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1); | ||
| 136 | + $struct = array_merge_recursive($tmp, $struct); | ||
| 137 | + } else { | ||
| 138 | + $struct['files'][] = $path; | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + return $struct; | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + /** | ||
| 146 | + * Creates a nested array representing the structure of a directory and files | ||
| 147 | + * | ||
| 148 | + * @param array $files Array listing files and dirs | ||
| 149 | + * @return array | ||
| 150 | + * @see System::_dirToStruct() | ||
| 151 | + */ | ||
| 152 | + function _multipleToStruct($files) | ||
| 153 | + { | ||
| 154 | + $struct = array('dirs' => array(), 'files' => array()); | ||
| 155 | + settype($files, 'array'); | ||
| 156 | + foreach ($files as $file) { | ||
| 157 | + if (is_dir($file)) { | ||
| 158 | + $tmp = System::_dirToStruct($file, 0); | ||
| 159 | + $struct = array_merge_recursive($tmp, $struct); | ||
| 160 | + } else { | ||
| 161 | + $struct['files'][] = $file; | ||
| 162 | + } | ||
| 163 | + } | ||
| 164 | + return $struct; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + /** | ||
| 168 | + * The rm command for removing files. | ||
| 169 | + * Supports multiple files and dirs and also recursive deletes | ||
| 170 | + * | ||
| 171 | + * @param string $args the arguments for rm | ||
| 172 | + * @return mixed PEAR_Error or true for success | ||
| 173 | + * @access public | ||
| 174 | + */ | ||
| 175 | + function rm($args) | ||
| 176 | + { | ||
| 177 | + $opts = System::_parseArgs($args, 'rf'); // "f" do nothing but like it :-) | ||
| 178 | + if (PEAR::isError($opts)) { | ||
| 179 | + return System::raiseError($opts); | ||
| 180 | + } | ||
| 181 | + foreach($opts[0] as $opt) { | ||
| 182 | + if ($opt[0] == 'r') { | ||
| 183 | + $do_recursive = true; | ||
| 184 | + } | ||
| 185 | + } | ||
| 186 | + $ret = true; | ||
| 187 | + if (isset($do_recursive)) { | ||
| 188 | + $struct = System::_multipleToStruct($opts[1]); | ||
| 189 | + foreach($struct['files'] as $file) { | ||
| 190 | + if (!@unlink($file)) { | ||
| 191 | + $ret = false; | ||
| 192 | + } | ||
| 193 | + } | ||
| 194 | + foreach($struct['dirs'] as $dir) { | ||
| 195 | + if (!@rmdir($dir)) { | ||
| 196 | + $ret = false; | ||
| 197 | + } | ||
| 198 | + } | ||
| 199 | + } else { | ||
| 200 | + foreach ($opts[1] as $file) { | ||
| 201 | + $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; | ||
| 202 | + if (!@$delete($file)) { | ||
| 203 | + $ret = false; | ||
| 204 | + } | ||
| 205 | + } | ||
| 206 | + } | ||
| 207 | + return $ret; | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + /** | ||
| 211 | + * Make directories. Note that we use call_user_func('mkdir') to avoid | ||
| 212 | + * a problem with ZE2 calling System::mkDir instead of the native PHP func. | ||
| 213 | + * | ||
| 214 | + * @param string $args the name of the director(y|ies) to create | ||
| 215 | + * @return bool True for success | ||
| 216 | + * @access public | ||
| 217 | + */ | ||
| 218 | + function mkDir($args) | ||
| 219 | + { | ||
| 220 | + $opts = System::_parseArgs($args, 'pm:'); | ||
| 221 | + if (PEAR::isError($opts)) { | ||
| 222 | + return System::raiseError($opts); | ||
| 223 | + } | ||
| 224 | + $mode = 0777; // default mode | ||
| 225 | + foreach($opts[0] as $opt) { | ||
| 226 | + if ($opt[0] == 'p') { | ||
| 227 | + $create_parents = true; | ||
| 228 | + } elseif($opt[0] == 'm') { | ||
| 229 | + // if the mode is clearly an octal number (starts with 0) | ||
| 230 | + // convert it to decimal | ||
| 231 | + if (strlen($opt[1]) && $opt[1]{0} == '0') { | ||
| 232 | + $opt[1] = octdec($opt[1]); | ||
| 233 | + } else { | ||
| 234 | + // convert to int | ||
| 235 | + $opt[1] += 0; | ||
| 236 | + } | ||
| 237 | + $mode = $opt[1]; | ||
| 238 | + } | ||
| 239 | + } | ||
| 240 | + $ret = true; | ||
| 241 | + if (isset($create_parents)) { | ||
| 242 | + foreach($opts[1] as $dir) { | ||
| 243 | + $dirstack = array(); | ||
| 244 | + while (!@is_dir($dir) && $dir != DIRECTORY_SEPARATOR) { | ||
| 245 | + array_unshift($dirstack, $dir); | ||
| 246 | + $dir = dirname($dir); | ||
| 247 | + } | ||
| 248 | + while ($newdir = array_shift($dirstack)) { | ||
| 249 | + if (!call_user_func('mkdir', $newdir, $mode)) { | ||
| 250 | + $ret = false; | ||
| 251 | + } | ||
| 252 | + } | ||
| 253 | + } | ||
| 254 | + } else { | ||
| 255 | + foreach($opts[1] as $dir) { | ||
| 256 | + if (!@is_dir($dir) && !call_user_func('mkdir', $dir, $mode)) { | ||
| 257 | + $ret = false; | ||
| 258 | + } | ||
| 259 | + } | ||
| 260 | + } | ||
| 261 | + return $ret; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + /** | ||
| 265 | + * Concatenate files | ||
| 266 | + * | ||
| 267 | + * Usage: | ||
| 268 | + * 1) $var = System::cat('sample.txt test.txt'); | ||
| 269 | + * 2) System::cat('sample.txt test.txt > final.txt'); | ||
| 270 | + * 3) System::cat('sample.txt test.txt >> final.txt'); | ||
| 271 | + * | ||
| 272 | + * Note: as the class use fopen, urls should work also (test that) | ||
| 273 | + * | ||
| 274 | + * @param string $args the arguments | ||
| 275 | + * @return boolean true on success | ||
| 276 | + * @access public | ||
| 277 | + */ | ||
| 278 | + function &cat($args) | ||
| 279 | + { | ||
| 280 | + $ret = null; | ||
| 281 | + $files = array(); | ||
| 282 | + if (!is_array($args)) { | ||
| 283 | + $args = preg_split('/\s+/', $args); | ||
| 284 | + } | ||
| 285 | + for($i=0; $i < count($args); $i++) { | ||
| 286 | + if ($args[$i] == '>') { | ||
| 287 | + $mode = 'wb'; | ||
| 288 | + $outputfile = $args[$i+1]; | ||
| 289 | + break; | ||
| 290 | + } elseif ($args[$i] == '>>') { | ||
| 291 | + $mode = 'ab+'; | ||
| 292 | + $outputfile = $args[$i+1]; | ||
| 293 | + break; | ||
| 294 | + } else { | ||
| 295 | + $files[] = $args[$i]; | ||
| 296 | + } | ||
| 297 | + } | ||
| 298 | + if (isset($mode)) { | ||
| 299 | + if (!$outputfd = fopen($outputfile, $mode)) { | ||
| 300 | + $err = System::raiseError("Could not open $outputfile"); | ||
| 301 | + return $err; | ||
| 302 | + } | ||
| 303 | + $ret = true; | ||
| 304 | + } | ||
| 305 | + foreach ($files as $file) { | ||
| 306 | + if (!$fd = fopen($file, 'r')) { | ||
| 307 | + System::raiseError("Could not open $file"); | ||
| 308 | + continue; | ||
| 309 | + } | ||
| 310 | + while ($cont = fread($fd, 2048)) { | ||
| 311 | + if (isset($outputfd)) { | ||
| 312 | + fwrite($outputfd, $cont); | ||
| 313 | + } else { | ||
| 314 | + $ret .= $cont; | ||
| 315 | + } | ||
| 316 | + } | ||
| 317 | + fclose($fd); | ||
| 318 | + } | ||
| 319 | + if (@is_resource($outputfd)) { | ||
| 320 | + fclose($outputfd); | ||
| 321 | + } | ||
| 322 | + return $ret; | ||
| 323 | + } | ||
| 324 | + | ||
| 325 | + /** | ||
| 326 | + * Creates temporary files or directories. This function will remove | ||
| 327 | + * the created files when the scripts finish its execution. | ||
| 328 | + * | ||
| 329 | + * Usage: | ||
| 330 | + * 1) $tempfile = System::mktemp("prefix"); | ||
| 331 | + * 2) $tempdir = System::mktemp("-d prefix"); | ||
| 332 | + * 3) $tempfile = System::mktemp(); | ||
| 333 | + * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); | ||
| 334 | + * | ||
| 335 | + * prefix -> The string that will be prepended to the temp name | ||
| 336 | + * (defaults to "tmp"). | ||
| 337 | + * -d -> A temporary dir will be created instead of a file. | ||
| 338 | + * -t -> The target dir where the temporary (file|dir) will be created. If | ||
| 339 | + * this param is missing by default the env vars TMP on Windows or | ||
| 340 | + * TMPDIR in Unix will be used. If these vars are also missing | ||
| 341 | + * c:\windows\temp or /tmp will be used. | ||
| 342 | + * | ||
| 343 | + * @param string $args The arguments | ||
| 344 | + * @return mixed the full path of the created (file|dir) or false | ||
| 345 | + * @see System::tmpdir() | ||
| 346 | + * @access public | ||
| 347 | + */ | ||
| 348 | + function mktemp($args = null) | ||
| 349 | + { | ||
| 350 | + static $first_time = true; | ||
| 351 | + $opts = System::_parseArgs($args, 't:d'); | ||
| 352 | + if (PEAR::isError($opts)) { | ||
| 353 | + return System::raiseError($opts); | ||
| 354 | + } | ||
| 355 | + foreach($opts[0] as $opt) { | ||
| 356 | + if($opt[0] == 'd') { | ||
| 357 | + $tmp_is_dir = true; | ||
| 358 | + } elseif($opt[0] == 't') { | ||
| 359 | + $tmpdir = $opt[1]; | ||
| 360 | + } | ||
| 361 | + } | ||
| 362 | + $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; | ||
| 363 | + if (!isset($tmpdir)) { | ||
| 364 | + $tmpdir = System::tmpdir(); | ||
| 365 | + } | ||
| 366 | + if (!System::mkDir("-p $tmpdir")) { | ||
| 367 | + return false; | ||
| 368 | + } | ||
| 369 | + $tmp = tempnam($tmpdir, $prefix); | ||
| 370 | + if (isset($tmp_is_dir)) { | ||
| 371 | + unlink($tmp); // be careful possible race condition here | ||
| 372 | + if (!call_user_func('mkdir', $tmp, 0700)) { | ||
| 373 | + return System::raiseError("Unable to create temporary directory $tmpdir"); | ||
| 374 | + } | ||
| 375 | + } | ||
| 376 | + $GLOBALS['_System_temp_files'][] = $tmp; | ||
| 377 | + if ($first_time) { | ||
| 378 | + PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); | ||
| 379 | + $first_time = false; | ||
| 380 | + } | ||
| 381 | + return $tmp; | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + /** | ||
| 385 | + * Remove temporary files created my mkTemp. This function is executed | ||
| 386 | + * at script shutdown time | ||
| 387 | + * | ||
| 388 | + * @access private | ||
| 389 | + */ | ||
| 390 | + function _removeTmpFiles() | ||
| 391 | + { | ||
| 392 | + if (count($GLOBALS['_System_temp_files'])) { | ||
| 393 | + $delete = $GLOBALS['_System_temp_files']; | ||
| 394 | + array_unshift($delete, '-r'); | ||
| 395 | + System::rm($delete); | ||
| 396 | + } | ||
| 397 | + } | ||
| 398 | + | ||
| 399 | + /** | ||
| 400 | + * Get the path of the temporal directory set in the system | ||
| 401 | + * by looking in its environments variables. | ||
| 402 | + * Note: php.ini-recommended removes the "E" from the variables_order setting, | ||
| 403 | + * making unavaible the $_ENV array, that s why we do tests with _ENV | ||
| 404 | + * | ||
| 405 | + * @return string The temporal directory on the system | ||
| 406 | + */ | ||
| 407 | + function tmpdir() | ||
| 408 | + { | ||
| 409 | + if (OS_WINDOWS) { | ||
| 410 | + if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { | ||
| 411 | + return $var; | ||
| 412 | + } | ||
| 413 | + if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { | ||
| 414 | + return $var; | ||
| 415 | + } | ||
| 416 | + if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { | ||
| 417 | + return $var; | ||
| 418 | + } | ||
| 419 | + return getenv('SystemRoot') . '\temp'; | ||
| 420 | + } | ||
| 421 | + if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { | ||
| 422 | + return $var; | ||
| 423 | + } | ||
| 424 | + return '/tmp'; | ||
| 425 | + } | ||
| 426 | + | ||
| 427 | + /** | ||
| 428 | + * The "which" command (show the full path of a command) | ||
| 429 | + * | ||
| 430 | + * @param string $program The command to search for | ||
| 431 | + * @return mixed A string with the full path or false if not found | ||
| 432 | + * @author Stig Bakken <ssb@php.net> | ||
| 433 | + */ | ||
| 434 | + function which($program, $fallback = false) | ||
| 435 | + { | ||
| 436 | + // is_executable() is not available on windows | ||
| 437 | + if (OS_WINDOWS) { | ||
| 438 | + $pear_is_executable = 'is_file'; | ||
| 439 | + } else { | ||
| 440 | + $pear_is_executable = 'is_executable'; | ||
| 441 | + } | ||
| 442 | + | ||
| 443 | + // full path given | ||
| 444 | + if (basename($program) != $program) { | ||
| 445 | + return (@$pear_is_executable($program)) ? $program : $fallback; | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + // XXX FIXME honor safe mode | ||
| 449 | + $path_delim = OS_WINDOWS ? ';' : ':'; | ||
| 450 | + $exe_suffixes = OS_WINDOWS ? array('.exe','.bat','.cmd','.com') : array(''); | ||
| 451 | + $path_elements = explode($path_delim, getenv('PATH')); | ||
| 452 | + foreach ($exe_suffixes as $suff) { | ||
| 453 | + foreach ($path_elements as $dir) { | ||
| 454 | + $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; | ||
| 455 | + if (@is_file($file) && @$pear_is_executable($file)) { | ||
| 456 | + return $file; | ||
| 457 | + } | ||
| 458 | + } | ||
| 459 | + } | ||
| 460 | + return $fallback; | ||
| 461 | + } | ||
| 462 | + | ||
| 463 | + /** | ||
| 464 | + * The "find" command | ||
| 465 | + * | ||
| 466 | + * Usage: | ||
| 467 | + * | ||
| 468 | + * System::find($dir); | ||
| 469 | + * System::find("$dir -type d"); | ||
| 470 | + * System::find("$dir -type f"); | ||
| 471 | + * System::find("$dir -name *.php"); | ||
| 472 | + * System::find("$dir -name *.php -name *.htm*"); | ||
| 473 | + * System::find("$dir -maxdepth 1"); | ||
| 474 | + * | ||
| 475 | + * Params implmented: | ||
| 476 | + * $dir -> Start the search at this directory | ||
| 477 | + * -type d -> return only directories | ||
| 478 | + * -type f -> return only files | ||
| 479 | + * -maxdepth <n> -> max depth of recursion | ||
| 480 | + * -name <pattern> -> search pattern (bash style). Multiple -name param allowed | ||
| 481 | + * | ||
| 482 | + * @param mixed Either array or string with the command line | ||
| 483 | + * @return array Array of found files | ||
| 484 | + * | ||
| 485 | + */ | ||
| 486 | + function find($args) | ||
| 487 | + { | ||
| 488 | + if (!is_array($args)) { | ||
| 489 | + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); | ||
| 490 | + } | ||
| 491 | + $dir = array_shift($args); | ||
| 492 | + $patterns = array(); | ||
| 493 | + $depth = 0; | ||
| 494 | + $do_files = $do_dirs = true; | ||
| 495 | + for ($i = 0; $i < count($args); $i++) { | ||
| 496 | + switch ($args[$i]) { | ||
| 497 | + case '-type': | ||
| 498 | + if (in_array($args[$i+1], array('d', 'f'))) { | ||
| 499 | + if ($args[$i+1] == 'd') { | ||
| 500 | + $do_files = false; | ||
| 501 | + } else { | ||
| 502 | + $do_dirs = false; | ||
| 503 | + } | ||
| 504 | + } | ||
| 505 | + $i++; | ||
| 506 | + break; | ||
| 507 | + case '-name': | ||
| 508 | + $patterns[] = "(" . preg_replace(array('/\./', '/\*/'), | ||
| 509 | + array('\.', '.*'), | ||
| 510 | + $args[$i+1]) | ||
| 511 | + . ")"; | ||
| 512 | + $i++; | ||
| 513 | + break; | ||
| 514 | + case '-maxdepth': | ||
| 515 | + $depth = $args[$i+1]; | ||
| 516 | + break; | ||
| 517 | + } | ||
| 518 | + } | ||
| 519 | + $path = System::_dirToStruct($dir, $depth); | ||
| 520 | + if ($do_files && $do_dirs) { | ||
| 521 | + $files = array_merge($path['files'], $path['dirs']); | ||
| 522 | + } elseif ($do_dirs) { | ||
| 523 | + $files = $path['dirs']; | ||
| 524 | + } else { | ||
| 525 | + $files = $path['files']; | ||
| 526 | + } | ||
| 527 | + if (count($patterns)) { | ||
| 528 | + $patterns = implode('|', $patterns); | ||
| 529 | + $ret = array(); | ||
| 530 | + for ($i = 0; $i < count($files); $i++) { | ||
| 531 | + if (preg_match("#^$patterns\$#", $files[$i])) { | ||
| 532 | + $ret[] = $files[$i]; | ||
| 533 | + } | ||
| 534 | + } | ||
| 535 | + return $ret; | ||
| 536 | + } | ||
| 537 | + return $files; | ||
| 538 | + } | ||
| 539 | +} | ||
| 540 | +?> |