r100533 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r100532‎ | r100533 | r100534 >
Date:08:54, 23 October 2011
Author:ialex
Status:ok
Tags:
Comment:
Group shell-related functions
Modified paths:
  • /trunk/phase3/includes/GlobalFunctions.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/GlobalFunctions.php
@@ -1726,217 +1726,6 @@
17271727 }
17281728
17291729 /**
1730 - * Windows-compatible version of escapeshellarg()
1731 - * Windows doesn't recognise single-quotes in the shell, but the escapeshellarg()
1732 - * function puts single quotes in regardless of OS.
1733 - *
1734 - * Also fixes the locale problems on Linux in PHP 5.2.6+ (bug backported to
1735 - * earlier distro releases of PHP)
1736 - *
1737 - * @param varargs
1738 - * @return String
1739 - */
1740 -function wfEscapeShellArg( ) {
1741 - wfInitShellLocale();
1742 -
1743 - $args = func_get_args();
1744 - $first = true;
1745 - $retVal = '';
1746 - foreach ( $args as $arg ) {
1747 - if ( !$first ) {
1748 - $retVal .= ' ';
1749 - } else {
1750 - $first = false;
1751 - }
1752 -
1753 - if ( wfIsWindows() ) {
1754 - // Escaping for an MSVC-style command line parser and CMD.EXE
1755 - // Refs:
1756 - // * http://web.archive.org/web/20020708081031/http://mailman.lyra.org/pipermail/scite-interest/2002-March/000436.html
1757 - // * http://technet.microsoft.com/en-us/library/cc723564.aspx
1758 - // * Bug #13518
1759 - // * CR r63214
1760 - // Double the backslashes before any double quotes. Escape the double quotes.
1761 - $tokens = preg_split( '/(\\\\*")/', $arg, -1, PREG_SPLIT_DELIM_CAPTURE );
1762 - $arg = '';
1763 - $iteration = 0;
1764 - foreach ( $tokens as $token ) {
1765 - if ( $iteration % 2 == 1 ) {
1766 - // Delimiter, a double quote preceded by zero or more slashes
1767 - $arg .= str_replace( '\\', '\\\\', substr( $token, 0, -1 ) ) . '\\"';
1768 - } elseif ( $iteration % 4 == 2 ) {
1769 - // ^ in $token will be outside quotes, need to be escaped
1770 - $arg .= str_replace( '^', '^^', $token );
1771 - } else { // $iteration % 4 == 0
1772 - // ^ in $token will appear inside double quotes, so leave as is
1773 - $arg .= $token;
1774 - }
1775 - $iteration++;
1776 - }
1777 - // Double the backslashes before the end of the string, because
1778 - // we will soon add a quote
1779 - $m = array();
1780 - if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) {
1781 - $arg = $m[1] . str_replace( '\\', '\\\\', $m[2] );
1782 - }
1783 -
1784 - // Add surrounding quotes
1785 - $retVal .= '"' . $arg . '"';
1786 - } else {
1787 - $retVal .= escapeshellarg( $arg );
1788 - }
1789 - }
1790 - return $retVal;
1791 -}
1792 -
1793 -/**
1794 - * wfMerge attempts to merge differences between three texts.
1795 - * Returns true for a clean merge and false for failure or a conflict.
1796 - *
1797 - * @param $old String
1798 - * @param $mine String
1799 - * @param $yours String
1800 - * @param $result String
1801 - * @return Bool
1802 - */
1803 -function wfMerge( $old, $mine, $yours, &$result ) {
1804 - global $wgDiff3;
1805 -
1806 - # This check may also protect against code injection in
1807 - # case of broken installations.
1808 - wfSuppressWarnings();
1809 - $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
1810 - wfRestoreWarnings();
1811 -
1812 - if( !$haveDiff3 ) {
1813 - wfDebug( "diff3 not found\n" );
1814 - return false;
1815 - }
1816 -
1817 - # Make temporary files
1818 - $td = wfTempDir();
1819 - $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
1820 - $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' );
1821 - $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' );
1822 -
1823 - fwrite( $oldtextFile, $old );
1824 - fclose( $oldtextFile );
1825 - fwrite( $mytextFile, $mine );
1826 - fclose( $mytextFile );
1827 - fwrite( $yourtextFile, $yours );
1828 - fclose( $yourtextFile );
1829 -
1830 - # Check for a conflict
1831 - $cmd = $wgDiff3 . ' -a --overlap-only ' .
1832 - wfEscapeShellArg( $mytextName ) . ' ' .
1833 - wfEscapeShellArg( $oldtextName ) . ' ' .
1834 - wfEscapeShellArg( $yourtextName );
1835 - $handle = popen( $cmd, 'r' );
1836 -
1837 - if( fgets( $handle, 1024 ) ) {
1838 - $conflict = true;
1839 - } else {
1840 - $conflict = false;
1841 - }
1842 - pclose( $handle );
1843 -
1844 - # Merge differences
1845 - $cmd = $wgDiff3 . ' -a -e --merge ' .
1846 - wfEscapeShellArg( $mytextName, $oldtextName, $yourtextName );
1847 - $handle = popen( $cmd, 'r' );
1848 - $result = '';
1849 - do {
1850 - $data = fread( $handle, 8192 );
1851 - if ( strlen( $data ) == 0 ) {
1852 - break;
1853 - }
1854 - $result .= $data;
1855 - } while ( true );
1856 - pclose( $handle );
1857 - unlink( $mytextName );
1858 - unlink( $oldtextName );
1859 - unlink( $yourtextName );
1860 -
1861 - if ( $result === '' && $old !== '' && !$conflict ) {
1862 - wfDebug( "Unexpected null result from diff3. Command: $cmd\n" );
1863 - $conflict = true;
1864 - }
1865 - return !$conflict;
1866 -}
1867 -
1868 -/**
1869 - * Returns unified plain-text diff of two texts.
1870 - * Useful for machine processing of diffs.
1871 - *
1872 - * @param $before String: the text before the changes.
1873 - * @param $after String: the text after the changes.
1874 - * @param $params String: command-line options for the diff command.
1875 - * @return String: unified diff of $before and $after
1876 - */
1877 -function wfDiff( $before, $after, $params = '-u' ) {
1878 - if ( $before == $after ) {
1879 - return '';
1880 - }
1881 -
1882 - global $wgDiff;
1883 - wfSuppressWarnings();
1884 - $haveDiff = $wgDiff && file_exists( $wgDiff );
1885 - wfRestoreWarnings();
1886 -
1887 - # This check may also protect against code injection in
1888 - # case of broken installations.
1889 - if( !$haveDiff ) {
1890 - wfDebug( "diff executable not found\n" );
1891 - $diffs = new Diff( explode( "\n", $before ), explode( "\n", $after ) );
1892 - $format = new UnifiedDiffFormatter();
1893 - return $format->format( $diffs );
1894 - }
1895 -
1896 - # Make temporary files
1897 - $td = wfTempDir();
1898 - $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
1899 - $newtextFile = fopen( $newtextName = tempnam( $td, 'merge-your-' ), 'w' );
1900 -
1901 - fwrite( $oldtextFile, $before );
1902 - fclose( $oldtextFile );
1903 - fwrite( $newtextFile, $after );
1904 - fclose( $newtextFile );
1905 -
1906 - // Get the diff of the two files
1907 - $cmd = "$wgDiff " . $params . ' ' . wfEscapeShellArg( $oldtextName, $newtextName );
1908 -
1909 - $h = popen( $cmd, 'r' );
1910 -
1911 - $diff = '';
1912 -
1913 - do {
1914 - $data = fread( $h, 8192 );
1915 - if ( strlen( $data ) == 0 ) {
1916 - break;
1917 - }
1918 - $diff .= $data;
1919 - } while ( true );
1920 -
1921 - // Clean up
1922 - pclose( $h );
1923 - unlink( $oldtextName );
1924 - unlink( $newtextName );
1925 -
1926 - // Kill the --- and +++ lines. They're not useful.
1927 - $diff_lines = explode( "\n", $diff );
1928 - if ( strpos( $diff_lines[0], '---' ) === 0 ) {
1929 - unset( $diff_lines[0] );
1930 - }
1931 - if ( strpos( $diff_lines[1], '+++' ) === 0 ) {
1932 - unset( $diff_lines[1] );
1933 - }
1934 -
1935 - $diff = implode( "\n", $diff_lines );
1936 -
1937 - return $diff;
1938 -}
1939 -
1940 -/**
19411730 * A wrapper around the PHP function var_export().
19421731 * Either print it or add it to the regular output ($wgOut).
19431732 *
@@ -2641,6 +2430,70 @@
26422431 }
26432432
26442433 /**
 2434+ * Windows-compatible version of escapeshellarg()
 2435+ * Windows doesn't recognise single-quotes in the shell, but the escapeshellarg()
 2436+ * function puts single quotes in regardless of OS.
 2437+ *
 2438+ * Also fixes the locale problems on Linux in PHP 5.2.6+ (bug backported to
 2439+ * earlier distro releases of PHP)
 2440+ *
 2441+ * @param varargs
 2442+ * @return String
 2443+ */
 2444+function wfEscapeShellArg( ) {
 2445+ wfInitShellLocale();
 2446+
 2447+ $args = func_get_args();
 2448+ $first = true;
 2449+ $retVal = '';
 2450+ foreach ( $args as $arg ) {
 2451+ if ( !$first ) {
 2452+ $retVal .= ' ';
 2453+ } else {
 2454+ $first = false;
 2455+ }
 2456+
 2457+ if ( wfIsWindows() ) {
 2458+ // Escaping for an MSVC-style command line parser and CMD.EXE
 2459+ // Refs:
 2460+ // * http://web.archive.org/web/20020708081031/http://mailman.lyra.org/pipermail/scite-interest/2002-March/000436.html
 2461+ // * http://technet.microsoft.com/en-us/library/cc723564.aspx
 2462+ // * Bug #13518
 2463+ // * CR r63214
 2464+ // Double the backslashes before any double quotes. Escape the double quotes.
 2465+ $tokens = preg_split( '/(\\\\*")/', $arg, -1, PREG_SPLIT_DELIM_CAPTURE );
 2466+ $arg = '';
 2467+ $iteration = 0;
 2468+ foreach ( $tokens as $token ) {
 2469+ if ( $iteration % 2 == 1 ) {
 2470+ // Delimiter, a double quote preceded by zero or more slashes
 2471+ $arg .= str_replace( '\\', '\\\\', substr( $token, 0, -1 ) ) . '\\"';
 2472+ } elseif ( $iteration % 4 == 2 ) {
 2473+ // ^ in $token will be outside quotes, need to be escaped
 2474+ $arg .= str_replace( '^', '^^', $token );
 2475+ } else { // $iteration % 4 == 0
 2476+ // ^ in $token will appear inside double quotes, so leave as is
 2477+ $arg .= $token;
 2478+ }
 2479+ $iteration++;
 2480+ }
 2481+ // Double the backslashes before the end of the string, because
 2482+ // we will soon add a quote
 2483+ $m = array();
 2484+ if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) {
 2485+ $arg = $m[1] . str_replace( '\\', '\\\\', $m[2] );
 2486+ }
 2487+
 2488+ // Add surrounding quotes
 2489+ $retVal .= '"' . $arg . '"';
 2490+ } else {
 2491+ $retVal .= escapeshellarg( $arg );
 2492+ }
 2493+ }
 2494+ return $retVal;
 2495+}
 2496+
 2497+/**
26452498 * Execute a shell command, with time and memory limits mirrored from the PHP
26462499 * configuration if supported.
26472500 * @param $cmd String Command line, properly escaped for shell.
@@ -2775,6 +2628,153 @@
27762629 }
27772630
27782631 /**
 2632+ * wfMerge attempts to merge differences between three texts.
 2633+ * Returns true for a clean merge and false for failure or a conflict.
 2634+ *
 2635+ * @param $old String
 2636+ * @param $mine String
 2637+ * @param $yours String
 2638+ * @param $result String
 2639+ * @return Bool
 2640+ */
 2641+function wfMerge( $old, $mine, $yours, &$result ) {
 2642+ global $wgDiff3;
 2643+
 2644+ # This check may also protect against code injection in
 2645+ # case of broken installations.
 2646+ wfSuppressWarnings();
 2647+ $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
 2648+ wfRestoreWarnings();
 2649+
 2650+ if( !$haveDiff3 ) {
 2651+ wfDebug( "diff3 not found\n" );
 2652+ return false;
 2653+ }
 2654+
 2655+ # Make temporary files
 2656+ $td = wfTempDir();
 2657+ $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
 2658+ $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' );
 2659+ $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' );
 2660+
 2661+ fwrite( $oldtextFile, $old );
 2662+ fclose( $oldtextFile );
 2663+ fwrite( $mytextFile, $mine );
 2664+ fclose( $mytextFile );
 2665+ fwrite( $yourtextFile, $yours );
 2666+ fclose( $yourtextFile );
 2667+
 2668+ # Check for a conflict
 2669+ $cmd = $wgDiff3 . ' -a --overlap-only ' .
 2670+ wfEscapeShellArg( $mytextName ) . ' ' .
 2671+ wfEscapeShellArg( $oldtextName ) . ' ' .
 2672+ wfEscapeShellArg( $yourtextName );
 2673+ $handle = popen( $cmd, 'r' );
 2674+
 2675+ if( fgets( $handle, 1024 ) ) {
 2676+ $conflict = true;
 2677+ } else {
 2678+ $conflict = false;
 2679+ }
 2680+ pclose( $handle );
 2681+
 2682+ # Merge differences
 2683+ $cmd = $wgDiff3 . ' -a -e --merge ' .
 2684+ wfEscapeShellArg( $mytextName, $oldtextName, $yourtextName );
 2685+ $handle = popen( $cmd, 'r' );
 2686+ $result = '';
 2687+ do {
 2688+ $data = fread( $handle, 8192 );
 2689+ if ( strlen( $data ) == 0 ) {
 2690+ break;
 2691+ }
 2692+ $result .= $data;
 2693+ } while ( true );
 2694+ pclose( $handle );
 2695+ unlink( $mytextName );
 2696+ unlink( $oldtextName );
 2697+ unlink( $yourtextName );
 2698+
 2699+ if ( $result === '' && $old !== '' && !$conflict ) {
 2700+ wfDebug( "Unexpected null result from diff3. Command: $cmd\n" );
 2701+ $conflict = true;
 2702+ }
 2703+ return !$conflict;
 2704+}
 2705+
 2706+/**
 2707+ * Returns unified plain-text diff of two texts.
 2708+ * Useful for machine processing of diffs.
 2709+ *
 2710+ * @param $before String: the text before the changes.
 2711+ * @param $after String: the text after the changes.
 2712+ * @param $params String: command-line options for the diff command.
 2713+ * @return String: unified diff of $before and $after
 2714+ */
 2715+function wfDiff( $before, $after, $params = '-u' ) {
 2716+ if ( $before == $after ) {
 2717+ return '';
 2718+ }
 2719+
 2720+ global $wgDiff;
 2721+ wfSuppressWarnings();
 2722+ $haveDiff = $wgDiff && file_exists( $wgDiff );
 2723+ wfRestoreWarnings();
 2724+
 2725+ # This check may also protect against code injection in
 2726+ # case of broken installations.
 2727+ if( !$haveDiff ) {
 2728+ wfDebug( "diff executable not found\n" );
 2729+ $diffs = new Diff( explode( "\n", $before ), explode( "\n", $after ) );
 2730+ $format = new UnifiedDiffFormatter();
 2731+ return $format->format( $diffs );
 2732+ }
 2733+
 2734+ # Make temporary files
 2735+ $td = wfTempDir();
 2736+ $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
 2737+ $newtextFile = fopen( $newtextName = tempnam( $td, 'merge-your-' ), 'w' );
 2738+
 2739+ fwrite( $oldtextFile, $before );
 2740+ fclose( $oldtextFile );
 2741+ fwrite( $newtextFile, $after );
 2742+ fclose( $newtextFile );
 2743+
 2744+ // Get the diff of the two files
 2745+ $cmd = "$wgDiff " . $params . ' ' . wfEscapeShellArg( $oldtextName, $newtextName );
 2746+
 2747+ $h = popen( $cmd, 'r' );
 2748+
 2749+ $diff = '';
 2750+
 2751+ do {
 2752+ $data = fread( $h, 8192 );
 2753+ if ( strlen( $data ) == 0 ) {
 2754+ break;
 2755+ }
 2756+ $diff .= $data;
 2757+ } while ( true );
 2758+
 2759+ // Clean up
 2760+ pclose( $h );
 2761+ unlink( $oldtextName );
 2762+ unlink( $newtextName );
 2763+
 2764+ // Kill the --- and +++ lines. They're not useful.
 2765+ $diff_lines = explode( "\n", $diff );
 2766+ if ( strpos( $diff_lines[0], '---' ) === 0 ) {
 2767+ unset( $diff_lines[0] );
 2768+ }
 2769+ if ( strpos( $diff_lines[1], '+++' ) === 0 ) {
 2770+ unset( $diff_lines[1] );
 2771+ }
 2772+
 2773+ $diff = implode( "\n", $diff_lines );
 2774+
 2775+ return $diff;
 2776+}
 2777+
 2778+/**
27792779 * This function works like "use VERSION" in Perl, the program will die with a
27802780 * backtrace if the current version of PHP is less than the version provided
27812781 *

Status & tagging log