Rev Author Line No. Line
4988 kaklik 1 <?php
2 // WebSVN - Subversion repository viewing via the web using PHP
3 // Copyright (C) 2004-2006 Tim Armes
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 //
19 // --
20 //
21 // command.php
22 //
23 // External command handling
24  
25 function detectCharacterEncoding($str) {
26 $list = array('UTF-8', 'ISO-8859-1', 'windows-1252');
27 if (function_exists('mb_detect_encoding')) {
28 foreach ($list as $item) {
29 if (mb_check_encoding($str, $item)) return $item;
30 }
31  
32 } else if (function_exists('iconv')) {
33 foreach ($list as $item) {
34 $encstr = iconv($item, $item.'//TRANSLIT//IGNORE', $str);
35 if (md5($encstr) == md5($str)) return $item;
36 }
37 }
38  
39 return null;
40 }
41  
42 // {{{ toOutputEncoding
43  
44 function toOutputEncoding($str) {
45 $enc = detectCharacterEncoding($str);
46  
47 if ($enc !== null && function_exists('mb_convert_encoding')) {
48 $str = mb_convert_encoding($str, 'UTF-8', $enc);
49  
50 } else if ($enc !== null && function_exists('iconv')) {
51 $str = iconv($enc, 'UTF-8//TRANSLIT//IGNORE', $str);
52  
53 } else {
54 // @see http://w3.org/International/questions/qa-forms-utf-8.html
55 $isUtf8 = preg_match('%^(?:
56 [\x09\x0A\x0D\x20-\x7E] # ASCII
57 | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
58 | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
59 | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
60 | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
61 | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
62 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
63 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
64 )*$%xs', $str
65 );
66 if (!$isUtf8) $str = utf8_encode($str);
67 }
68  
69 return $str;
70 }
71  
72 // }}}
73  
74 // {{{ escape
75 //
76 // Escape a string to output
77  
78 function escape($str) {
79 $entities = array();
80 $entities['&'] = '&amp;';
81 $entities['<'] = '&lt;';
82 $entities['>'] = '&gt;';
83 $entities['"'] = '&quot;';
84 $entities['\''] = '&apos;';
85 return str_replace(array_keys($entities), array_values($entities), $str ?? '');
86 }
87  
88 // }}}
89  
90 // {{{ execCommand
91  
92 function execCommand($cmd, &$retcode) {
93 return @exec($cmd, $tmp, $retcode);
94 }
95  
96 // }}}
97  
98 // {{{ popenCommand
99  
100 function popenCommand($cmd, $mode) {
101 return popen($cmd, $mode);
102 }
103  
104 // }}}
105  
106 // {{{ passthruCommand
107  
108 function passthruCommand($cmd) {
109 return passthru($cmd);
110 }
111  
112 // }}}
113  
114 // {{{ runCommand
115  
116 function runCommand($cmd, $mayReturnNothing = false, &$errorIf = 'NOT_USED') {
117 global $config, $lang;
118  
119 $output = array();
120 $error = '';
121 $opts = null;
122  
123 // https://github.com/websvnphp/websvn/issues/75
124 // https://github.com/websvnphp/websvn/issues/78
125 if ($config->serverIsWindows) {
126 if (!strpos($cmd, '>') && !strpos($cmd, '|')) {
127 $opts = array('bypass_shell' => true);
128 } else {
129 $cmd = '"'.$cmd.'"';
130 }
131 }
132  
133 $descriptorspec = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
134 $resource = proc_open($cmd, $descriptorspec, $pipes, null, null, $opts);
135  
136 if (!is_resource($resource)) {
137 echo '<p>'.$lang['BADCMD'].': <code>'.stripCredentialsFromCommand($cmd).'</code></p>';
138 exit;
139 }
140  
141 $handle = $pipes[1];
142 $firstline = true;
143  
144 while (!feof($handle)) {
145 $line = rtrim(fgets($handle), "\n\r");
146 if ($firstline && empty($line) && !$mayReturnNothing) {
147 $error = 'No output on STDOUT.';
148 break;
149 }
150  
151 $firstline = false;
152 $output[] = toOutputEncoding($line);
153 }
154  
155 while (!feof($pipes[2])) {
156 $error .= fgets($pipes[2]);
157 }
158 $error = toOutputEncoding(trim($error));
159  
160 fclose($pipes[0]);
161 fclose($pipes[1]);
162 fclose($pipes[2]);
163  
164 proc_close($resource);
165  
166 # Some commands are expected to return no output, but warnings on STDERR.
167 if ((count($output) > 0) || $mayReturnNothing) {
168 return $output;
169 }
170  
171 if ($errorIf != 'NOT_USED') {
172 $errorIf = $error;
173 return $output;
174 }
175  
176 echo '<p>'.$lang['BADCMD'].': <code>'.stripCredentialsFromCommand($cmd).'</code></p>';
177 echo '<p>'.nl2br($error).'</p>';
178 exit;
179 }
180  
181 // }}}
182  
183 function stripCredentialsFromCommand($cmd) {
184 global $config;
185  
186 $quotingChar = ($config->serverIsWindows ? '"' : "'");
187 $quotedString = $quotingChar.'([^'.$quotingChar.'\\\\]*(\\\\.[^'.$quotingChar.'\\\\]*)*)'.$quotingChar;
188 $patterns = array('|--username '.$quotedString.' |U', '|--password '.$quotedString.' |U');
189 $replacements = array('--username '.quote('***').' ', '--password '.quote('***').' ');
190 $cmd = preg_replace($patterns, $replacements, $cmd, 1);
191  
192 return $cmd;
193 }
194  
195 // {{{ quote
196 //
197 // Quote a string to send to the command line
198  
199 function quote($str) {
200 global $config;
201  
202 if ($config->serverIsWindows) {
203 return '"'.$str.'"';
204 } else {
205 return escapeshellarg($str);
206 }
207 }
208  
209 // }}}