Make WordPress Core


Ignore:
Timestamp:
05/16/2009 02:04:36 AM (16 years ago)
Author:
ryan
Message:

Support IIS 7.0 URL Rewrite Module. Props ruslany. Hat tips to peaceablewhale, hakre, Denis-de-Bernardy, sivel. fixes #8974

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-admin/includes/misc.php

    r11170 r11350  
    137137
    138138/**
     139 * Updates the IIS web.config file with the current rules if it is writable.
     140 * If the permalinks do not require rewrite rules then the rules are deleted from the web.config file.
     141 *
     142 * @since 2.8.0
     143 *
     144 * @return bool True if web.config was updated successfully
     145 */
     146function iis7_save_url_rewrite_rules(){
     147    global $wp_rewrite;
     148   
     149    $home_path = get_home_path();
     150    $web_config_file = $home_path . 'web.config';
     151
     152    // Using win_is_writable() instead of is_writable() because of a bug in Windows PHP
     153    if ( ( ! file_exists($web_config_file) && win_is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks() ) || win_is_writable($web_config_file) ) {
     154        if ( iis7_supports_permalinks() ) {
     155            $rule = $wp_rewrite->iis7_url_rewrite_rules();
     156            if ( ! empty($rule) ) {
     157                return iis7_add_rewrite_rule($web_config_file, $rule);
     158            } else {
     159                return iis7_delete_rewrite_rule($web_config_file);
     160            }
     161        }
     162    }
     163    return false;
     164}
     165
     166/**
    139167 * {@internal Missing Short Description}}
    140168 *
     
    371399    }
    372400}
     401
     402/**
     403 * Check if IIS 7 supports pretty permalinks
     404 *
     405 * @since 2.8.0
     406 *
     407 * @return bool
     408 */
     409function iis7_supports_permalinks() {
     410    global $is_iis7;
     411
     412    $supports_permalinks = false;   
     413    if ( $is_iis7 ) {
     414        /* First we check if the DOMDocument class exists. If it does not exist,
     415         * which is the case for PHP 4.X, then we cannot easily update the xml configuration file,
     416         * hence we just bail out and tell user that pretty permalinks cannot be used.
     417         * This is not a big issue because PHP 4.X is going to be depricated and for IIS it
     418         * is recommended to use PHP 5.X NTS.
     419         * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
     420         * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
     421         * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
     422         * via ISAPI then pretty permalinks will not work.
     423         */
     424        $supports_permalinks = class_exists('DOMDocument') && isset($_SERVER['IIS_UrlRewriteModule']) && ( php_sapi_name() == 'cgi-fcgi' );
     425    }
     426       
     427    return apply_filters('iis7_supports_permalinks', $supports_permalinks);
     428}
     429
     430/**
     431 * Check if rewrite rule for WordPress already exists in the IIS 7 configuration file
     432 *
     433 * @since 2.8.0
     434 *
     435 * @return bool
     436 * @param string $filename The file path to the configuration file
     437 */
     438function iis7_rewrite_rule_exists($filename) { 
     439    if ( ! file_exists($filename) )
     440        return false;   
     441    if ( ! class_exists('DOMDocument') )
     442        return false;
     443   
     444    $doc = new DOMDocument();
     445    if ( $doc->load($filename) === false )
     446        return false;
     447    $xpath = new DOMXPath($doc);
     448    $rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[@name=\'wordpress\']');
     449    if ( $rules->length == 0 )
     450        return false;
     451    else
     452        return true;   
     453}
     454
     455/**
     456 * Delete WordPress rewrite rule from web.config file if it exists there
     457 *
     458 * @since 2.8.0
     459 *
     460 * @param string $filename Name of the configuration file
     461 * @return bool
     462 */
     463function iis7_delete_rewrite_rule($filename) { 
     464    // If configuration file does not exist then rules also do not exist so there is nothing to delete
     465    if ( ! file_exists($filename) )
     466        return true;
     467   
     468    if ( ! class_exists('DOMDocument') )
     469        return false;
     470   
     471    $doc = new DOMDocument();
     472    $doc->preserveWhiteSpace = false;
     473
     474    if ( $doc -> load($filename) === false )
     475        return false;
     476    $xpath = new DOMXPath($doc);
     477    $rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[@name=\'wordpress\']');
     478    if ( $rules->length > 0 ) {
     479        $child = $rules->item(0);
     480        $parent = $child->parentNode;
     481        $parent->removeChild($child);
     482        $doc->formatOutput = true;
     483        saveDomDocument($doc, $filename);
     484    }
     485    return true;
     486}
     487
     488/**
     489 * Add WordPress rewrite rule to the IIS 7 configuration file.
     490 *
     491 * @since 2.8.0
     492 *
     493 * @param string $filename The file path to the configuration file
     494 * @param string $rewrite_rule The XML fragment with URL Rewrite rule
     495 * @return bool
     496 */
     497function iis7_add_rewrite_rule($filename, $rewrite_rule) { 
     498    if ( ! class_exists('DOMDocument') )
     499        return false;
     500   
     501    // If configuration file does not exist then we create one.
     502    if ( ! file_exists($filename) ) {
     503        $fp = fopen( $filename, 'w');
     504        fwrite($fp, '<configuration/>');
     505        fclose($fp);
     506    }
     507   
     508    $doc = new DOMDocument();
     509    $doc->preserveWhiteSpace = false;
     510
     511    if ( $doc->load($filename) === false )
     512        return false;
     513   
     514    $xpath = new DOMXPath($doc);
     515
     516    // First check if the rule already exists as in that case there is no need to re-add it
     517    $wordpress_rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[@name=\'wordpress\']');
     518    if ( $wordpress_rules->length > 0 )
     519        return true;
     520
     521    // Check the XPath to the rewrite rule and create XML nodes if they do not exist
     522    $xmlnodes = $xpath->query('/configuration/system.webServer/rewrite/rules');
     523    if ( $xmlnodes->length > 0 ) {
     524        $rules_node = $xmlnodes->item(0);
     525    } else {
     526        $rules_node = $doc->createElement('rules');
     527       
     528        $xmlnodes = $xpath->query('/configuration/system.webServer/rewrite');
     529        if ( $xmlnodes->length > 0 ) {
     530            $rewrite_node = $xmlnodes->item(0);
     531            $rewrite_node->appendChild($rules_node);
     532        } else {
     533            $rewrite_node = $doc->createElement('rewrite');
     534            $rewrite_node->appendChild($rules_node);
     535
     536            $xmlnodes = $xpath->query('/configuration/system.webServer');
     537            if ( $xmlnodes->length > 0 ) {
     538                $system_webServer_node = $xmlnodes->item(0);
     539                $system_webServer_node->appendChild($rewrite_node);
     540            } else {
     541                $system_webServer_node = $doc->createElement('system.webServer');
     542                $system_webServer_node->appendChild($rewrite_node);
     543       
     544                $xmlnodes = $xpath->query('/configuration');
     545                if ( $xmlnodes->length > 0 ) {
     546                    $config_node = $xmlnodes->item(0);
     547                    $config_node->appendChild($system_webServer_node);
     548                } else {
     549                    $config_node = $doc->createElement('configuration');
     550                    $doc->appendChild($config_node);
     551                    $config_node->appendChild($system_webServer_node);
     552                }
     553            }
     554        }
     555    }
     556   
     557    $rule_fragment = $doc->createDocumentFragment();
     558    $rule_fragment->appendXML($rewrite_rule);
     559    $rules_node->appendChild($rule_fragment);
     560
     561    $doc->formatOutput = true; 
     562    saveDomDocument($doc, $filename);
     563
     564    return true;   
     565}
     566
     567/**
     568 * Saves the XML document into a file
     569 *
     570 * @since 2.8.0
     571 *
     572 * @param DOMDocument $doc
     573 * @param string $filename
     574 */
     575function saveDomDocument($doc, $filename) {
     576    $config = $doc->saveXML();
     577    $config = preg_replace("/([^\r])\n/", "$1\r\n", $config);
     578    $fp = fopen($filename, 'w');
     579    fwrite($fp, $config);
     580    fclose($fp);
     581}
     582
     583/**
     584 * Workaround for Windows bug in is_writable() function
     585 *
     586 * @since 2.8.0
     587 *
     588 * @param object $path
     589 * @return bool
     590 */
     591function win_is_writable($path) {
     592    /* will work in despite of Windows ACLs bug
     593     * NOTE: use a trailing slash for folders!!!
     594     * see http://bugs.php.net/bug.php?id=27609
     595     * see http://bugs.php.net/bug.php?id=30931
     596     */
     597
     598    if ( $path{strlen($path)-1} == '/' ) // recursively return a temporary file path
     599        return win_is_writable($path . uniqid(mt_rand()) . '.tmp');
     600    else if ( is_dir($path) )
     601        return win_is_writable($path . '/' . uniqid(mt_rand()) . '.tmp');
     602    // check tmp file for read/write capabilities
     603    $rm = file_exists($path);
     604    $f = @fopen($path, 'a');
     605    if ($f===false)
     606        return false;
     607    fclose($f);
     608    if ( ! $rm )
     609        unlink($path);
     610    return true;
     611}
    373612?>
Note: See TracChangeset for help on using the changeset viewer.