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 | +?> | ... | ... |