svn: /web/doc-editor/trunk/php/ CvsClient.php File.php PreviewFile.php RepositoryManager.php SaferExec.php SvnClient.php ToolsXmllint.php

[email protected] (Neal Poole)
Newsgroups php.doc.web
Message-ID <[email protected]>
nbpoole                                  Mon, 20 Jun 2011 21:52:18 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=312348

Log:
Replaced calls to 'exec' with calls to 'SaferExec', which provides a limited form of parameterization for arguments to system calls.

Changed paths:
    U   web/doc-editor/trunk/php/CvsClient.php
    U   web/doc-editor/trunk/php/File.php
    U   web/doc-editor/trunk/php/PreviewFile.php
    U   web/doc-editor/trunk/php/RepositoryManager.php
    A   web/doc-editor/trunk/php/SaferExec.php
    U   web/doc-editor/trunk/php/SvnClient.php
    U   web/doc-editor/trunk/php/ToolsXmllint.php
svn-diffs-312348.txt (text/x-diff, 28.3 KB)
Modified: web/doc-editor/trunk/php/CvsClient.php
===================================================================
--- web/doc-editor/trunk/php/CvsClient.php	2011-06-20 21:19:14 UTC (rev 312347)
+++ web/doc-editor/trunk/php/CvsClient.php	2011-06-20 21:52:18 UTC (rev 312348)
@@ -1,5 +1,7 @@
 <?php

+require_once dirname(__FILE__) . '/SaferExec.php';
+
 class CvsClient
 {
     private static $instance;
@@ -99,9 +101,12 @@
     {
         $appConf = AccountManager::getInstance()->appConf;

-        $cmd = 'cd '.$appConf['GLOBAL_CONFIGURATION']['data.path'].'; cvs -d :pserver:cvsread:[email protected]:/repository login;'
-              .'cvs -d :pserver:cvsread:[email protected]:/repository checkout phpdoc-all;';
-        exec($cmd);
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf['GLOBAL_CONFIGURATION']['data.path'])),
+            new ExecStatement('cvs -d :pserver:cvsread:[email protected]:/repository login'),
+            new ExecStatement('cvs -d :pserver:cvsread:[email protected]:/repository checkout phpdoc-all')
+        );
+        SaferExec::execMulti($commands);
     }

     /**
@@ -112,8 +117,11 @@
         $appConf = AccountManager::getInstance()->appConf;
         $project = AccountManager::getInstance()->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; cvs -f -q update -d -P .;';
-        exec($cmd);
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+            new ExecStatement('cvs -f -q update -d -P .')
+        );
+        SaferExec::execMulti($commands);
     }

     /**
@@ -128,10 +136,13 @@
         $appConf = AccountManager::getInstance()->appConf;
         $project = AccountManager::getInstance()->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].$path.'; cvs log '.$file;
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'] . $path)),
+            new ExecStatement('cvs log %s', array($file))
+        );

         $output = array();
-        exec($cmd, $output);
+        SaferExec::execMulti($commands, $output);

         $output = implode("\n", $output);

@@ -195,10 +206,13 @@
         $appConf = AccountManager::getInstance()->appConf;
         $project = AccountManager::getInstance()->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].$path.'; cvs diff -kk -u -r '.$rev2.' -r '.$rev1.' '.$file;
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'] . $path)),
+            new ExecStatement('cvs diff -kk -u -r %d -r %d %s', array((int)$rev2, (int)$rev1, $file))
+        );

         $output = array();
-        exec($cmd, $output);
+        SaferExec::execMulti($commands, $output);

         return $output;
     }
@@ -236,35 +250,31 @@
             $delete_stack[] = $delete[$i]->lang.'/'.$delete[$i]->path.'/'.$delete[$i]->name;
         }

-        // Linearization
-        $filesCreate = implode($create_stack, ' ');
-        $filesUpdate = implode($update_stack, ' ');
-        $filesDelete = implode($delete_stack, ' ');
-
         // Buil the command line
         $cvsLogin  = AccountManager::getInstance()->vcsLogin;
         $cvsPasswd = AccountManager::getInstance()->vcsPasswd;

-        $cmdCreate = $cmdDelete = '';
-        if (trim($filesCreate) != '') {
-            $cmdCreate = "cvs -d :pserver:$cvsLogin:[email protected]:/repository -f add $filesCreate && ";
+        $commands = array(
+            new ExecStatement('export CVS_PASSFILE=%s', array(realpath($appConf['GLOBAL_CONFIGURATION']['data.path']) . '/.cvspass')),
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+            new ExecStatement('cvs -d :pserver:' . $cvsLogin . ':' . $cvsPasswd . '@cvs.php.net:/repository login')
+        );
+
+        if (!empty($delete_stack))
+        {
+            $commands[] = new ExecStatement('cvs -d :pserver:' . $cvsLogin . ':' . $cvsPasswd . '@cvs.php.net:/repository -f remove -f' . str_repeat(' %s', count($delete_stack)), array($delete_stack));
         }
-        if (trim($filesDelete) != '') {
-            $cmdDelete = "cvs -d :pserver:$cvsLogin:[email protected]:/repository -f remove -f $filesDelete && ";
+
+        if (!empty($create_stack))
+        {
+            $commands[] = new ExecStatement('cvs -d :pserver:' . $cvsLogin . ':' . $cvsPasswd . '@cvs.php.net:/repository -f add' . str_repeat(' %s', count($create_stack)), array($create_stack));
         }

-        // Escape single quote
-        $log = str_replace("'", "\\'", $log);
-        $cmd = $cmdDelete.
-               $cmdCreate.
-               "cvs -d :pserver:$cvsLogin:[email protected]:/repository -f commit -l -m '$log' $filesUpdate $filesDelete $filesCreate";
+        $args = array_merge(array($log), $create_stack, $update_stack, $delete_stack);
+        $commands[] = new ExecStatement('cvs -d :pserver:' . $cvsLogin . ':' . $cvsPasswd . '@cvs.php.net:/repository -f commit -l -m %s' . str_repeat(' %s', count($create_stack) + count($update_stack) + count($delete_stack)), $args);

-        // First, login into Cvs
-        $fullCmd = 'export CVS_PASSFILE='.realpath($appConf['GLOBAL_CONFIGURATION']['data.path']).'/.cvspass && cd '.$appConf[$project]['vcs.path'].' && '
-                  ."cvs -d :pserver:$cvsLogin:[email protected]:/repository login && $cmd";
-
         $output  = array();
-        exec($fullCmd, $output);
+        SaferExec::execMulti($commands, $output);

         return $output;
     }

Modified: web/doc-editor/trunk/php/File.php
===================================================================
--- web/doc-editor/trunk/php/File.php	2011-06-20 21:19:14 UTC (rev 312347)
+++ web/doc-editor/trunk/php/File.php	2011-06-20 21:52:18 UTC (rev 312348)
@@ -3,6 +3,7 @@
 require_once dirname(__FILE__) . '/DBConnection.php';
 require_once dirname(__FILE__) . '/GTranslate.php';
 require_once dirname(__FILE__) . '/RepositoryManager.php';
+require_once dirname(__FILE__) . '/SaferExec.php';
 require_once dirname(__FILE__) . '/VCSFactory.php';

 class File
@@ -426,11 +427,13 @@
         $project = $am->project;

         $ext = ($isPatch) ? '.' . $uniqID . '.patch' : '.new';
-        $cmd = 'cd '.$appConf[$project]['vcs.path'].$this->lang.$this->path.'; '
-              .'diff -u '.$this->name.' '.$this->name.$ext;
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'] . $this->lang . $this->path)),
+            new ExecStatement('diff -u %s %s', array($this->name, $this->name . $ext))
+        );

         $output = array();
-        exec($cmd, $output);
+        SaferExec::execMulti($commands, $output);

         return implode("\r\n", $output);
     }
@@ -466,13 +469,15 @@
                return '<div style="size: 10px; text-align:center;margin-top:10px;">This is a new file.</div>';
             } else {

-                $cmd = 'cd '.$appConf[$project]['vcs.path'].$this->lang.$this->path.'; '
-                      .'diff -u '.$this->name.' '.$this->name.$ext;
+                $commands = array(
+                    new ExecStatement('cd %s', array($appConf[$project]['vcs.path'] . $this->lang . $this->path)),
+                    new ExecStatement('diff -u %s %s', array($this->name, $this->name . $ext))
+                );

                 $trial_threshold = 3;
                 while ($trial_threshold-- > 0) {
                     $output = array();
-                    exec($cmd, $output);
+                    SaferExec::execMulti($commands, $output);
                     if (strlen(trim(implode('', $output))) != 0) break;
                 }
             }

Modified: web/doc-editor/trunk/php/PreviewFile.php
===================================================================
--- web/doc-editor/trunk/php/PreviewFile.php	2011-06-20 21:19:14 UTC (rev 312347)
+++ web/doc-editor/trunk/php/PreviewFile.php	2011-06-20 21:52:18 UTC (rev 312348)
@@ -1,5 +1,7 @@
 <?php

+require_once dirname(__FILE__) . '/SaferExec.php';
+
 class PreviewFile
 {
     public $path;
@@ -62,9 +64,12 @@
         $this->checkDir();

         // We clean the input output directory
-        $cmd = 'rm -R '.$this->outputDir.'* ;';
-        exec("$cmd", $output);
-        $this->cleanCmd = $cmd;
+        $commands = array(
+            new ExecStatement('cd %s', array($this->outputDir)),
+            new ExecStatement('rm -R *')
+        );
+        SaferExec::execMulti($cmd, $output);
+        $this->cleanCmd = implode('; ', $commands);
         $this->cleanLog = $output;

         $rename = 0;
@@ -77,9 +82,14 @@
         }

         // We start the build for this file
-        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; '.$appConf['GLOBAL_CONFIGURATION']['php.bin'].' doc-base/configure.php --with-php=' . $appConf['GLOBAL_CONFIGURATION']['php.bin'] . ' --generate='.$this->path.' ; '.$appConf['GLOBAL_CONFIGURATION']['php.bin'].' ../phd/render.php --package PHP --format php --memoryindex -d doc-base/.manual.xml --output '.$this->outputDir;
-        exec("$cmd", $output);
-        $this->buildCmd = $cmd;
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+            new ExecStatement($appConf['GLOBAL_CONFIGURATION']['php.bin'] . ' doc-base/configure.php --with-php=%s --generate=%s', array($appConf['GLOBAL_CONFIGURATION']['php.bin'], $this->path)),
+            new ExecStatement($appConf['GLOBAL_CONFIGURATION']['php.bin'] . ' ../phd/render.php --package PHP --format php --memoryindex -d doc-base/.manual.xml --output %s', array($this->outputDir))
+        );
+
+        SaferExec::execMulti($commands, $output);
+        $this->buildCmd = implode('; ', $commands);
         $this->buildLog = $output;

         // Rename it back
@@ -92,9 +102,9 @@
         // Only move the specific file we are generating
         $xmlID = $this->getOutputId();
         $filename = 'phdoe-' . time() . '-' . $xmlID. '.php';
-        $cmd = 'mv '.$this->outputDir.'php-web/'.$xmlID.'.php '.$this->inputDir. $filename;
-        exec("$cmd", $output);
-        $this->moveCmd = $cmd;
+        $cmd = new ExecStatement('mv %s %s', array($this->outputDir . 'php-web/' . $xmlID . '.php', $this->inputDir . $filename));
+        SaferExec::exec($cmd, $output);
+        $this->moveCmd = $cmd->__toString();
         $this->moveLog = $output;



Modified: web/doc-editor/trunk/php/RepositoryManager.php
===================================================================
--- web/doc-editor/trunk/php/RepositoryManager.php	2011-06-20 21:19:14 UTC (rev 312347)
+++ web/doc-editor/trunk/php/RepositoryManager.php	2011-06-20 21:52:18 UTC (rev 312348)
@@ -4,6 +4,7 @@
 require_once dirname(__FILE__) . '/DBConnection.php';
 require_once dirname(__FILE__) . '/File.php';
 require_once dirname(__FILE__) . '/LockFile.php';
+require_once dirname(__FILE__) . '/SaferExec.php';
 require_once dirname(__FILE__) . '/ToolsCheckDoc.php';
 require_once dirname(__FILE__) . '/ToolsCheckEntities.php';
 require_once dirname(__FILE__) . '/ToolsError.php';
@@ -326,23 +327,26 @@
             "logContent" => ""
         );

-        $cmd = 'cd '.realpath($appConf[$project]['vcs.configure.script.path']).' && '
-              .$appConf['GLOBAL_CONFIGURATION']['php.bin'].' configure.php --with-php='
-              .$appConf['GLOBAL_CONFIGURATION']['php.bin'].' '
-              .$appConf[$project]['vcs.configure.script.options'];
+        $appConf[$project]['vcs.configure.script.options'] = str_replace("{LangCode}", $lang, $appConf[$project]['vcs.configure.script.options']);

-        $cmd = str_replace("{LangCode}", $lang, $cmd).'';
-
-        if ( $enable_xml_details == "true" ) {
-            $cmd = str_replace("{XmlDetails}", "--enable-xml-details", $cmd);
-        } else {
-            $cmd = str_replace("{XmlDetails}", "", $cmd);
+        if ( $enable_xml_details == "true" )
+        {
+            $appConf[$project]['vcs.configure.script.options'] = str_replace("{XmlDetails}", "--enable-xml-details", $appConf[$project]['vcs.configure.script.options']);
         }
+        else
+        {
+            $appConf[$project]['vcs.configure.script.options'] = str_replace("{XmlDetails}", "", $appConf[$project]['vcs.configure.script.options']);
+        }

+        $commands = array(
+            new ExecStatement('cd %s', array(realpath($appConf[$project]['vcs.configure.script.path']))),
+            new ExecStatement($appConf['GLOBAL_CONFIGURATION']['php.bin'] . ' configure.php --with-php=' . $appConf['GLOBAL_CONFIGURATION']['php.bin'] . ' ' . $appConf[$project]['vcs.configure.script.options'])
+        );
+
         $trial_threshold = 3;
         while ($trial_threshold-- > 0) {
             $output =array();
-            exec($cmd, $output);
+            SaferExec::exec($cmd, $output);
             if (strlen(trim(implode('', $output))) != 0) break;
         }

@@ -1984,10 +1988,11 @@
             $lang = $lang["code"];
             if( $lang == 'en' ) { continue; }

-            $cmd = 'cd '.$appConf[$project]['vcs.path'].' && '
-                  .$appConf['GLOBAL_CONFIGURATION']['php.bin'].' doc-base/scripts/revcheck.php '.$lang.' > '.$appConf['GLOBAL_CONFIGURATION']['data.path'].'revcheck/'.$lang.'.html';
-
-            exec("$cmd 2>&1");
+            $commands = array(
+                new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+                new ExecStatement($appConf['GLOBAL_CONFIGURATION']['php.bin'] . ' doc-base/scripts/revcheck.php %s > %s 2>&1', array($lang, $appConf['GLOBAL_CONFIGURATION']['data.path'].'revcheck/'.$lang.'.html'))
+            );
+            SaferExec::execMulti($commands);
         }
     }
 }

Added: web/doc-editor/trunk/php/SaferExec.php
===================================================================
--- web/doc-editor/trunk/php/SaferExec.php	                        (rev 0)
+++ web/doc-editor/trunk/php/SaferExec.php	2011-06-20 21:52:18 UTC (rev 312348)
@@ -0,0 +1,85 @@
+<?php
+/**
+ * A mildly safer substitute for PHP's exec function. It is meant to reduce the chances of arbitrary command execution
+ * via calls to the exec function.
+ */
+class SaferExec
+{
+    /**
+     * Executes a single ExecStatement
+     */
+    public static function exec(ExecStatement $command, &$output = array(), &$return_var = 0)
+    {
+        return exec($command, $output, $return_var);
+    }
+
+    /**
+     * Executes an array of ExecStatements as a single command
+     */
+    public static function execMulti(array $command_array, &$output = array(), &$return_var = 0)
+    {
+        // Verify that we're working with ExecStatements
+        foreach ($command_array as $cur_command)
+        {
+            if (!($cur_command instanceof ExecStatement))
+            {
+                trigger_error('Unexpected object encountered. Command will not execute.', E_USER_ERROR);
+                return '';
+            }
+        }
+
+        // Now that we've verified that we're looking at an array of ExecStatements, we can start working with them
+        $command = implode('; ', $command_array);
+
+        return exec($command, $output, $return_var);
+    }
+}
+
+class ExecStatement
+{
+    private $command;
+    private $args;
+
+    /**
+     * Represents a shell command to be executed.
+     *
+     * The first parameter, $command, should be a format string (eg: the kind of string you pass to printf).
+     * The directives in that string should correspond to the arguments passed as part of the second parameter, the $args array.
+     *
+     * The assumptions about security made here only holds when $command is a static string. If $command is
+     * even partly derived from user input, any assumptions made about safety and security no longer hold.
+     */
+    public function __construct($command, array $args = array())
+    {
+        $this->command = $command;
+
+        // We validate and escape certain types of input.
+        $this->args = array();
+        foreach ($args as $key => $val)
+        {
+            if (is_bool($val) || is_float($val) || is_int($val) || is_null($val))
+                $this->args[$key] = $val;
+            else if (is_string($val))
+                $this->args[$key] = escapeshellarg($val);
+            else if (is_object($val))
+                $this->args[$key] = escapeshellarg($val->__toString());
+            else
+                trigger_error('Argument with unexpected type used to construct ExecStatement. It has been omitted from the command string.', E_USER_WARNING);
+        }
+    }
+
+    public function getCommand()
+    {
+        return $this->command;
+    }
+
+    public function getArgs()
+    {
+        return $this->args;
+    }
+
+    public function __toString()
+    {
+        return vsprintf($this->getCommand(), $this->getArgs());
+    }
+}

Modified: web/doc-editor/trunk/php/SvnClient.php
===================================================================
--- web/doc-editor/trunk/php/SvnClient.php	2011-06-20 21:19:14 UTC (rev 312347)
+++ web/doc-editor/trunk/php/SvnClient.php	2011-06-20 21:52:18 UTC (rev 312348)
@@ -1,5 +1,7 @@
 <?php

+require_once dirname(__FILE__) . '/SaferExec.php';
+
 class SvnClient
 {
     private static $instance;
@@ -246,15 +248,17 @@
         $module = $appConf[$project]['vcs.module'];
         $scheme = ($port == 443 ? 'https' : 'http');

-        $cmd = 'cd '.$appConf['GLOBAL_CONFIGURATION']['data.path'].'; '
-              ."svn co $scheme://$host:$port/$uri $module";
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf['GLOBAL_CONFIGURATION']['data.path'])),
+            new ExecStatement('svn co %s %s 2>&1', array("$scheme://$host:$port/$uri", $module)),
+        );

         $err = 1;
         $trial_threshold = 3;
         $output = array();
         for ($trial = 0; $err != 0 && $trial < $trial_threshold; ++$trial) {
             array_push($output, "svn co trial #$trial\n");
-            exec("$cmd 2>&1", $output, $err); // if no err, err = 0
+            SaferExec::execMulti($commands, $output, $err); // if no err, err = 0
             if ($err == 0) array_push($output, "Success.\n");
         }

@@ -273,14 +277,17 @@
         $appConf = $am->appConf;
         $project = $am->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; svn up .'.$path;
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+            new ExecStatement('svn up %s 2>&1', array($path)),
+        );

         $err = 1;
         $trial_threshold = 3;
         $output = array();
         for ($trial = 0; $err != 0 && $trial < $trial_threshold; ++$trial) {
             array_push($output, "svn up trial #$trial\n");
-            exec("$cmd 2>&1", $output, $err); // if no err, err = 0
+            SaferExec::execMulti($commands, $output, $err); // if no err, err = 0
             if ($err == 0) array_push($output, "Success.\n");
         }

@@ -304,14 +311,17 @@
         $appConf = $am->appConf;
         $project = $am->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; svn up '.$file->full_path;
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+            new ExecStatement('svn up %s 2>&1', array($file->full_path))
+        );

         $err = 1;
         $trial_threshold = 3;
         $output = array();
         for ($trial = 0; $err != 0 && $trial < $trial_threshold; ++$trial) {
             array_push($output, "svn up trial #$trial\n");
-            exec("$cmd 2>&1", $output, $err); // if no err, err = 0
+            SaferExec::execMulti($commands, $output, $err); // if no err, err = 0
             if ($err == 0) array_push($output, "Success.\n");
         }

@@ -333,14 +343,17 @@
         $appConf = $am->appConf;
         $project = $am->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; svn up .';
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+            new ExecStatement('svn up . 2>&1')
+        );

         $err = 1;
         $trial_threshold = 3;
         $output = array();
         for ($trial = 0; $err != 0 && $trial < $trial_threshold; ++$trial) {
             array_push($output, "svn up trial #$trial\n");
-            exec("$cmd 2>&1", $output, $err); // if no err, err = 0
+            SaferExec::execMulti($commands, $output, $err); // if no err, err = 0
             if ($err == 0) array_push($output, "Success.\n");
         }

@@ -365,12 +378,15 @@
         $appConf = $am->appConf;
         $project = $am->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].$path.'; svn log '.$file;
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'].$path)),
+            new ExecStatement('svn log %s', array($file))
+        );

         $trial_threshold = 3;
         while ($trial_threshold-- > 0) {
             $output = array();
-            exec($cmd, $output);
+            SaferExec::execMulti($commands, $output);
             if (strlen(trim(implode('', $output))) != 0) break;
         }

@@ -416,12 +432,15 @@
         $appConf = $am->appConf;
         $project = $am->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].$path.'; svn diff -r '.$rev1.':'.$rev2.' '.$file;
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'].$path)),
+            new ExecStatement('svn diff -r %d:%d %s', array((int)$rev1, (int)$rev2, $file))
+        );

         $trial_threshold = 3;
         while ($trial_threshold-- > 0) {
             $output = array();
-            exec($cmd, $output);
+            SaferExec::execMulti($commands, $output);
             if (strlen(trim(implode('', $output))) != 0) break;
         }

@@ -459,14 +478,18 @@
         {
             // We add this new folder into repository

-            $cmd = 'cd '.$appConf[$project]['vcs.path'].'; svn add --non-recursive '.$path.'; svn ci --no-auth-cache --non-interactive -m "Add new folder from Php Docbook Online Editor" --username '.$vcsLogin.' --password '.$vcsPasswd.' '.$path;
+            $commands = array(
+                new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+                new ExecStatement('svn add --non-recursive %s', array($path)),
+                new ExecStatement('svn ci --no-auth-cache --non-interactive -m "Add new folder from Php Docbook Online Editor" --username %s --password %s %s 2>&1', array($vcsLogin, $vcsPasswd, $path))
+            );

             $err = 1;
             $trial_threshold = 3;
             $output = array();
             for ($trial = 0; $err != 0 && $trial < $trial_threshold; ++$trial) {
                 array_push($output, "svn ci trial #$trial\n");
-                exec("$cmd 2>&1", $output, $err); // if no err, err = 0
+                SaferExec::execMulti($commands, $output, $err); // if no err, err = 0
                 if ($err == 0) array_push($output, "Success.\n");
             }
             $commitLogMessage = array_merge($commitLogMessage, $output);
@@ -538,38 +561,41 @@
         $info['nbFilesDelete'] = count($delete_stack);
         $info['nbFilesUpdate'] = count($update_stack);

-        // Linearization
-        $filesCreate = implode($create_stack, ' ');
-        $filesUpdate = implode($update_stack, ' ');
-        $filesDelete = implode($delete_stack, ' ');
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path']))
+        );

-        // Buil the command line
-
-        $cmdCreate = $cmdDelete = $cmdUpdate = '';
-
-        if (trim($filesCreate) != '') {
-            $cmdCreate = "svn add $filesCreate ; svn propset svn:keywords \"Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL\" $filesCreate ; svn propset svn:eol-style \"native\" $filesCreate ; ";
+        if (!empty($delete_stack))
+        {
+            $commands[] = new ExecStatement('svn delete' . str_repeat(' %s', $info['nbFilesDelete']), $delete_stack);
         }
-        if (trim($filesDelete) != '') {
-            $cmdDelete = "svn delete $filesDelete ; ";
+        if (!empty($create_stack))
+        {
+            $commands[] = new ExecStatement('svn add' . str_repeat(' %s', $info['nbFilesCreate']), $create_stack);
+            $commands[] = new ExecStatement('svn propset svn:keywords "Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL"' . str_repeat(' %s', $info['nbFilesCreate']), $create_stack);
+            $commands[] = new ExecStatement('svn propset svn:eol-style "native"' . str_repeat(' %s', $info['nbFilesCreate']), $create_stack);
         }
-        if (trim($filesUpdate) != '') {
-            $cmdUpdate = "svn propset svn:keywords \"Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL\" $filesUpdate ; svn propset svn:eol-style \"native\" $filesUpdate ; ";
+        if (!empty($update_stack))
+        {
+            $commands[] = new ExecStatement('svn propset svn:keywords "Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL"' . str_repeat(' %s', $info['nbFilesUpdate']), $update_stack);
+            $commands[] = new ExecStatement('svn propset svn:eol-style "native"' . str_repeat(' %s', $info['nbFilesUpdate']), $update_stack);
         }

-        $cmd = $cmdDelete.
-               $cmdCreate.
-               $cmdUpdate.
-               "svn ci --no-auth-cache --non-interactive -F $pathLogFile --username $vcsLogin --password $vcsPasswd $filesUpdate $filesDelete $filesCreate";
+        $args = array_mege(
+            array($pathLogFile, $vcsLogin, $vcsPasswd),
+            $update_stack,
+            $delete_stack,
+            $create_stack
+        );

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; ' .$cmd;
+        $commands[] = new ExecStatement('svn ci --no-auth-cache --non-interactive -F %s --username %s --password %s' . str_repeat(' %s', $info['nbFilesCreate'] + $info['nbFilesUpdate'] + $info['nbFilesDelete']) . ' 2>&1', $args);

         $err = 1;
         $trial_threshold = 3;
         $output = array();
         for ($trial = 0; $err != 0 && $trial < $trial_threshold; ++$trial) {
             array_push($output, "svn ci trial #$trial\n");
-            exec("$cmd 2>&1", $output, $err); // if no err, err = 0
+            SaferExec::execMulti($commands, $output, $err); // if no err, err = 0
             if ($err == 0) array_push($output, "Success.\n");
         }

@@ -620,20 +646,17 @@
             $delete_stack[] = $delete[$i]->full_path;
         }

-        // Linearization
-        $filesCreate = implode($create_stack, ' ');
-        $filesUpdate = implode($update_stack, ' ');
-        $filesDelete = implode($delete_stack, ' ');
+        $commands = array(
+            new ExecStatement('cd %s', array($appConf[$project]['vcs.path'])),
+            new ExecStatement('svn revert' . str_repeat(' %s', count($create_stack) + count($update_stack) + count($delete_stack)) . ' 2>&1', array_merge($create_stack, $update_stack, $delete_stack))
+        );

-        $cmd = "svn revert $filesCreate $filesUpdate $filesDelete";
-        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; ' .$cmd;
-
         $err = 1;
         $trial_threshold = 3;
         $output = array();
         for ($trial = 0; $err != 0 && $trial < $trial_threshold; ++$trial) {
             array_push($output, "svn revert trial #$trial\n");
-            exec("$cmd 2>&1", $output, $err); // if no err, err = 0
+            SaferExec::execMulti($commands, $output, $err); // if no err, err = 0
             if ($err == 0) array_push($output, "Success.\n");
         }


Modified: web/doc-editor/trunk/php/ToolsXmllint.php
===================================================================
--- web/doc-editor/trunk/php/ToolsXmllint.php	2011-06-20 21:19:14 UTC (rev 312347)
+++ web/doc-editor/trunk/php/ToolsXmllint.php	2011-06-20 21:52:18 UTC (rev 312348)
@@ -1,5 +1,7 @@
 <?php

+require_once dirname(__FILE__) . '/SaferExec.php';
+
 class ToolsXmllint
 {
     public $xmlContent;
@@ -36,12 +38,12 @@

         $this->XmlFileResult = tempnam(sys_get_temp_dir(), 'PhDOE_'.mt_rand());

-        $cmd = $appConf['GLOBAL_CONFIGURATION']['xmllint.bin'].' --noout ' . $this->XmlFileName . ' > ' . $this->XmlFileResult . ' 2>&1';
+        $cmd = new ExecStatement($appConf['GLOBAL_CONFIGURATION']['xmllint.bin'] . ' --noout %s > %s 2>&1', array($this->XmlFileName, $this->XmlFileResult));

         $trial_threshold = 3;
         while ($trial_threshold-- > 0) {
             $output = array();
-            exec($cmd, $output);
+            SaferExec::exec($cmd, $output);
             if (strlen(trim(implode('', $output))) != 0) break;
         }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.