Index: trunk/phase3/includes/GlobalFunctions.php |
— | — | @@ -1726,217 +1726,6 @@ |
1727 | 1727 | } |
1728 | 1728 | |
1729 | 1729 | /** |
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 | | -/** |
1941 | 1730 | * A wrapper around the PHP function var_export(). |
1942 | 1731 | * Either print it or add it to the regular output ($wgOut). |
1943 | 1732 | * |
— | — | @@ -2641,6 +2430,70 @@ |
2642 | 2431 | } |
2643 | 2432 | |
2644 | 2433 | /** |
| 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 | +/** |
2645 | 2498 | * Execute a shell command, with time and memory limits mirrored from the PHP |
2646 | 2499 | * configuration if supported. |
2647 | 2500 | * @param $cmd String Command line, properly escaped for shell. |
— | — | @@ -2775,6 +2628,153 @@ |
2776 | 2629 | } |
2777 | 2630 | |
2778 | 2631 | /** |
| 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 | +/** |
2779 | 2779 | * This function works like "use VERSION" in Perl, the program will die with a |
2780 | 2780 | * backtrace if the current version of PHP is less than the version provided |
2781 | 2781 | * |