From 77811c385ffe0514d4a245b4ae930c16566fb911 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Mon, 18 Apr 2005 14:37:43 +0000 Subject: [PATCH] Lessons learnt from installing MediaWiki with safe_mode, especially support for uploads in such an environment. --- config/index.php | 99 ++++++++++++++++++++++++++------------ includes/Image.php | 75 ++++++++++++++++++----------- includes/SpecialUpload.php | 10 +++- languages/Language.php | 1 + 4 files changed, 125 insertions(+), 60 deletions(-) diff --git a/config/index.php b/config/index.php index c3c83de10a..1c3e0017fb 100644 --- a/config/index.php +++ b/config/index.php @@ -141,11 +141,9 @@ if( file_exists( "../LocalSettings.php" ) ) { } if( file_exists( "./LocalSettings.php" ) ) { - dieout( "

You're configured!

- -

Please move LocalSettings.php to the parent directory, then - try out your wiki. - (You should remove this config directory for added security once you're done.)

" ); + writeSuccessMessage(); + + dieout( '' ); } if( !is_writable( "." ) ) { @@ -206,15 +204,6 @@ if( ini_get( "register_globals" ) ) { -
  • Warning: PHP's - safe mode is active! - You may have problems caused by this, particularly if using image uploads. -
  • -

    Cannot install wiki.

    " ); } +if( ini_get( "safe_mode" ) ) { + $conf->safeMode = true; + ?> +
  • Warning: PHP's + safe mode is active. + You may have problems caused by this, particularly if using image uploads. +
  • + safeMode = false; +} + + $sapi = php_sapi_name(); $conf->prettyURLs = true; print "
  • PHP server API is $sapi; "; @@ -446,16 +448,17 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { require_once( "maintenance/InitialiseMessages.inc" ); $wgTitle = Title::newFromText( "Installation script" ); + print "
  • Trying to connect to MySQL on $wgDBserver as root...\n"; $wgDatabase = Database::newFromParams( $wgDBserver, "root", $conf->RootPW, "", 1 ); - $wgDatabase->ignoreErrors(true); - @$myver = mysql_get_server_info( $wgDatabase->mConn ); - if( $myver ) { + if( $wgDatabase->isOpen() ) { + $myver = mysql_get_server_info( $wgDatabase->mConn ); + $wgDatabase->ignoreErrors(true); $conf->Root = true; - print "
  • Connected as root (automatic)
  • \n"; + print "\n"; } else { - print "
  • MySQL error " . ($err = mysql_errno() ) . - ": " . htmlspecialchars( mysql_error() ); + print "
  • "; $ok = false; switch( $err ) { case 1045: @@ -467,17 +470,19 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { /* Try the regular user... */ $wgDBadminuser = $wgDBuser; $wgDBadminpassword = $wgDBpassword; + /* Wait one second for connection rate limiting, present on some systems */ + sleep(1); $wgDatabase = Database::newFromParams( $wgDBserver, $wgDBuser, $wgDBpassword, "", 1 ); - $wgDatabase->isOpen(); - $wgDatabase->ignoreErrors(true); - @$myver = mysql_get_server_info( $wgDatabase->mConn ); - if( !$myver ) { + if( !$wgDatabase->isOpen() ) { + print ""; $errs["DBuser"] = "Check name/pass"; $errs["DBpassword"] = "or enter root"; $errs["DBpassword2"] = "password below"; $errs["RootPW"] = "Got root?"; - print " need password.\n"; } else { + $myver = mysql_get_server_info( $wgDatabase->mConn ); + $wgDatabase->ignoreErrors(true); $conf->Root = false; $conf->RootPW = ""; print " ok.\n"; @@ -502,7 +507,7 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { continue; } - print "
  • Connected to database... $myver"; + print "
  • Connected to $myver"; if( version_compare( $myver, "4.0.0" ) >= 0 ) { print "; enabling MySQL 4 enhancements"; $conf->DBmysql4 = true; @@ -514,6 +519,12 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { if( $sel ) { print "
  • Database " . htmlspecialchars( $wgDBname ) . " exists
  • \n"; } else { + $err = mysql_errno(); + if ( $err != 1049 ) { + print ""; + continue; + } $res = $wgDatabase->query( "CREATE DATABASE `$wgDBname`" ); if( !$res ) { print "
  • Couldn't create database " . @@ -634,9 +645,7 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { } if(fwrite( $f, $localSettings ) ) { fclose( $f ); - - print "

    Success! Move the config/LocalSettings.php file into the parent directory, then follow - this link to your wiki.

    \n"; + writeSuccessMessage(); } else { fclose( $f ); die("

    An error occured while writing the config/LocalSettings.php file. Check user rights and disk space then try again.

    \n"); @@ -937,6 +946,29 @@ if( count( $errs ) ) { } /* -------------------------------------------------------------------------------------- */ +function writeSuccessMessage() { + global $conf; + if ( ini_get( 'safe_mode' ) && !ini_get( 'open_basedir' ) ) { + echo <<Installation successful!

    +

    To complete the installation, please do the following: +

      +
    1. Download config/LocalSettings.php with your FTP client or file manager
    2. +
    3. Upload it to the parent directory
    4. +
    5. Delete config/LocalSettings.php
    6. +
    7. Start using your wiki! +
    +

    If you are in a shared hosting environment, do not just move LocalSettings.php +remotely. LocalSettings.php is currently owned by the user your webserver is running under, +which means that anyone on the same server can read your database password! Downloading +it and uploading it again will hopefully change the ownership to a user ID specific to you.

    +EOT; + } else { + echo "

    Installation successful! Move the config/LocalSettings.php file into the parent directory, then follow + this link to your wiki.

    \n"; + } +} + function escapePhpString( $string ) { return strtr( $string, @@ -960,6 +992,7 @@ function writeLocalSettings( $conf ) { $pretty = ($conf->prettyURLs ? "" : "# "); $ugly = ($conf->prettyURLs ? "# " : ""); $rights = ($conf->RightsUrl) ? "" : "# "; + $hashedUploads = $conf->safeMode ? '' : '# '; switch ( $conf->Shm ) { case 'memcached': @@ -1037,7 +1070,7 @@ if ( \$wgCommandLineMode ) { if ( isset( \$_SERVER ) && array_key_exists( 'REQUEST_METHOD', \$_SERVER ) ) { die( \"This script must be run from the command line\\n\" ); } -} elseif ( empty( \$wgConfiguring ) ) { +} elseif ( empty( \$wgNoOutputBuffer ) ) { ## Compress output if the browser supports it {$zlib}if( !ini_get( 'zlib.output_compression' ) ) @ob_start( 'ob_gzhandler' ); } @@ -1094,6 +1127,12 @@ if ( \$wgCommandLineMode ) { {$magic}\$wgUseImageMagick = true; {$magic}\$wgImageMagickConvertCommand = \"{$convert}\"; +## If you want to use image uploads under safe mode, +## create the directories images/archive, images/thumb and +## images/temp, and make them all writable. Then uncomment +## this, if it's not already uncommented: +{$hashedUploads}\$wgHashedUploadDirectory = false; + ## If you have the appropriate support software installed ## you can enable inline LaTeX equations: # \$wgUseTeX = true; diff --git a/includes/Image.php b/includes/Image.php index 57d81b815d..888c56c1c2 100644 --- a/includes/Image.php +++ b/includes/Image.php @@ -516,10 +516,14 @@ class Image $base = $wgUploadBaseUrl; $path = $wgUploadPath; } - $url = "{$base}{$path}/{$subdir}" . - wfGetHashPath($this->name, $this->fromSharedDirectory) - . $this->name.'/'.$name; - $url = wfUrlencode( $url ); + if ( Image::isHashed( $this->fromSharedDirectory ) ) { + $url = "{$base}{$path}/{$subdir}" . + wfGetHashPath($this->name, $this->fromSharedDirectory) + . $this->name.'/'.$name; + $url = wfUrlencode( $url ); + } else { + $url = "{$base}{$path}/{$subdir}/{$name}"; + } } return array( $script !== false, $url ); } @@ -796,20 +800,24 @@ class Image * Get all thumbnail names previously generated for this image */ function getThumbnails( $shared = false ) { - $this->load(); - $files = array(); - $dir = wfImageThumbDir( $this->name, $shared ); + if ( Image::isHashed( $shared ) ) { + $this->load(); + $files = array(); + $dir = wfImageThumbDir( $this->name, $shared ); - // This generates an error on failure, hence the @ - $handle = @opendir( $dir ); - - if ( $handle ) { - while ( false !== ( $file = readdir($handle) ) ) { - if ( $file{0} != '.' ) { - $files[] = $file; + // This generates an error on failure, hence the @ + $handle = @opendir( $dir ); + + if ( $handle ) { + while ( false !== ( $file = readdir($handle) ) ) { + if ( $file{0} != '.' ) { + $files[] = $file; + } } + closedir( $handle ); } - closedir( $handle ); + } else { + $files = array(); } return $files; @@ -929,6 +937,15 @@ class Image return $fullpath; } + + /** + * @return bool + * @static + */ + function isHashed( $shared ) { + global $wgHashedUploadDirectory, $wgHashedSharedUploadDirectory; + return $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory; + } /** * @return bool @@ -1134,18 +1151,22 @@ function wfImageDir( $fname ) { */ function wfImageThumbDir( $fname, $shared = false ) { $base = wfImageArchiveDir( $fname, 'thumb', $shared ); - $dir = "$base/$fname"; + if ( Image::isHashed( $shared ) ) { + $dir = "$base/$fname"; - if ( !is_dir( $base ) ) { - $oldumask = umask(0); - @mkdir( $base, 0777 ); - umask( $oldumask ); - } + if ( !is_dir( $base ) ) { + $oldumask = umask(0); + @mkdir( $base, 0777 ); + umask( $oldumask ); + } - if ( ! is_dir( $dir ) ) { - $oldumask = umask(0); - @mkdir( $dir, 0777 ); - umask( $oldumask ); + if ( ! is_dir( $dir ) ) { + $oldumask = umask(0); + @mkdir( $dir, 0777 ); + umask( $oldumask ); + } + } else { + $dir = $base; } return $dir; @@ -1208,9 +1229,7 @@ function wfGetHashPath ( $dbkey, $fromSharedDirectory = false ) { global $wgHashedSharedUploadDirectory, $wgSharedUploadDirectory; global $wgHashedUploadDirectory; - $ishashed = $fromSharedDirectory ? $wgHashedSharedUploadDirectory : - $wgHashedUploadDirectory; - if($ishashed) { + if( Image::isHashed( $fromSharedDirectory ) ) { $hash = md5($dbkey); return '/' . $hash{0} . '/' . substr( $hash, 0, 2 ) . '/'; } else { diff --git a/includes/SpecialUpload.php b/includes/SpecialUpload.php index 967576b1f0..1f16e577ee 100644 --- a/includes/SpecialUpload.php +++ b/includes/SpecialUpload.php @@ -90,14 +90,14 @@ class UploadForm { */ function execute() { global $wgUser, $wgOut; - global $wgEnableUploads; + global $wgEnableUploads, $wgUploadDirectory; /** Show an error message if file upload is disabled */ if( ! $wgEnableUploads ) { $wgOut->addWikiText( wfMsg( 'uploaddisabled' ) ); return; } - + /** Various rights checks */ if( ( $wgUser->isAnon() ) OR $wgUser->isBlocked() ) { @@ -109,6 +109,12 @@ class UploadForm { return; } + /** Check if the image directory is writeable, this is a common mistake */ + if ( !is_writeable( $wgUploadDirectory ) ) { + $wgOut->addWikiText( wfMsg( 'upload_directory_read_only', $wgUploadDirectory ) ); + return; + } + if( $this->mReUpload ) { $this->unsaveUploadedFile(); $this->mainUploadForm(); diff --git a/languages/Language.php b/languages/Language.php index dca90b4915..486249900c 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -962,6 +962,7 @@ Unselected groups will not be changed. You can deselect a group with CTRL + Left 'uploadnologin' => 'Not logged in', 'uploadnologintext' => "You must be [[Special:Userlogin|logged in]] to upload files.", +'upload_directory_read_only' => 'The upload directory ($1) is not writable by the webserver.', 'uploadfile' => 'Upload images, sounds, documents etc.', 'uploaderror' => 'Upload error', 'uploadtext' => -- 2.20.1