196
Installation guide Drupal provides an installation script that automatically populates database tables and configures the correct settings in the settings.php file. This section covers preparing for installation, running the installation script itself, and the steps that should be done after running the installation script has completed. It also explains how to do a "multi site" installation, where a number of different Drupal sites run off the same code base. Before proceeding with your first Drupal installation, you should also review the best practices section. For help with Drupal terms, see the terminology page. Other tools Some of the steps in the installation process can be performed with tools such as graphical applications for moving files and managing databases or tools that are provided by your hosting service. This documentation focuses on performing tasks at the command line. For information on using other tools, see the documentation that accompanies the application or is provided by your hosting service. Creating a test site on a local computer It is considered a good practice to do all development work on a separate test site before making changes to a production site. A test site allows you to evaluate the impact of upgrades, new modules, modifications to themes etc. without causing disruption to your live site. For information about setting up a web server on a local computer, see the Local Server Setup section of the Developing for Drupal guide. Alternative methods for installation Some web hosting companies offer "one-click" installations of Drupal, or specific Drupal support. You may be able to locate one on the Drupal hosting handbook page. There is also a handbook page listing Drupal distributions , which include installation profiles and pre-packaged distributions of Drupal and modules. These may be of help as well. See also The troubleshooting FAQ. System requirements Note: if you meet these requirements but still have problems with your site, be sure to read through the Webhosting Troubleshooting FAQ. Resources A minimum base installation requires at least 3MB of disk space but you should assume that your actual disk space will be somewhat higher. For example, if you install many contributed modules and contributed themes, the actual disk space for your installation could easily be 40 MB or more (exclusive of database content, media, backups and other files). A useful FAQ ( http://drupal.org/node/59680) explains how to use phpinfo to get the details of your system. For example, phpinfo will tell you if you have a database already installed and what version your system is running. Phpinfo will also tell you what php variables are set as well as many other helpful things. Web server Drupal has been deployed successfully on both Apache and IIS. Apache (Recommended) Drupal will work on Apache 1.3 or Apache 2.x hosted on UNIX/Linux, OS X, or Windows. The majority of Drupal development and deployment is done on Apache, so there is more community experience and testing performed on Apache than on other web servers. You can use the Apache 'mod_rewrite' extension to allow for clean URLs. Microsoft IIS Drupal core will work using IIS 5, IIS 6, or IIS 7 if PHP is configured correctly. To achieve clean URLs you may need to use a third party product. For IIS7 you can use the Microsoft URL Rewrite Module or a third party solution. When using Drupal on IIS 7 with fastcgi you must install Hotfix kb954946, or wait until the hotfix appears in a package update (recommended). KB954946 was included in Windows 2008 Server SP2 Drupal is being developed to be web server independent, but we have limited or no reports of successful use on web servers not listed here.

Drupal - Installation Guide

Embed Size (px)

DESCRIPTION

Note: if you meet these requirements but still have problems with your site, be sure to read through the Webhosting Troubleshooting FAQ. Other tools A useful FAQ (http://drupal.org/node/59680) explains how to use phpinfo to get the details of your system. For example, phpinfo will tell you if you have a database already installed and what version your system is running. Phpinfo will also tell you what php variables are set as well as many other helpful things. See also Apache (Recommended)

Citation preview

Page 1: Drupal - Installation Guide

Installation guideDrupal provides an installation script that automatically populates database tables and configuresthe correct settings in the settings.php file. This section covers preparing for installation, runningthe installation script itself, and the steps that should be done after running the installation scripthas completed. It also explains how to do a "multi site" installation, where a number of differentDrupal sites run off the same code base.

Before proceeding with your first Drupal installation, you should also review the best practicessection. For help with Drupal terms, see the terminology page.

Other tools

Some of the steps in the installation process can be performed with tools such as graphicalapplications for moving files and managing databases or tools that are provided by your hostingservice. This documentation focuses on performing tasks at the command line. For information onusing other tools, see the documentation that accompanies the application or is provided by yourhosting service.

Creating a test site on a local computer

It is considered a good practice to do all development work on a separate test site before makingchanges to a production site. A test site allows you to evaluate the impact of upgrades, newmodules, modifications to themes etc. without causing disruption to your live site. For informationabout setting up a web server on a local computer, see the Local Server Setup section of theDeveloping for Drupal guide.

Alternative methods for installation

Some web hosting companies offer "one-click" installations of Drupal, or specific Drupal support.You may be able to locate one on the Drupal hosting handbook page.

There is also a handbook page listing Drupal distributions, which include installation profiles andpre-packaged distributions of Drupal and modules. These may be of help as well.

See also

The troubleshooting FAQ.

System requirementsNote: if you meet these requirements but still have problems with your site, be sure to readthrough the Webhosting Troubleshooting FAQ.

ResourcesA minimum base installation requires at least 3MB of disk space but you should assume that youractual disk space will be somewhat higher. For example, if you install many contributed modulesand contributed themes, the actual disk space for your installation could easily be 40 MB or more(exclusive of database content, media, backups and other files).

A useful FAQ (http://drupal.org/node/59680) explains how to use phpinfo to get the details ofyour system. For example, phpinfo will tell you if you have a database already installed and whatversion your system is running. Phpinfo will also tell you what php variables are set as well asmany other helpful things.

Web serverDrupal has been deployed successfully on both Apache and IIS.

Apache (Recommended)

Drupal will work on Apache 1.3 or Apache 2.x hosted on UNIX/Linux, OS X, or Windows.The majority of Drupal development and deployment is done on Apache, so there is morecommunity experience and testing performed on Apache than on other web servers.You can use the Apache 'mod_rewrite' extension to allow for clean URLs.

Microsoft IIS

Drupal core will work using IIS 5, IIS 6, or IIS 7 if PHP is configured correctly.To achieve clean URLs you may need to use a third party product. For IIS7 you can use theMicrosoft URL Rewrite Module or a third party solution.When using Drupal on IIS 7 with fastcgi you must install Hotfix kb954946, or wait until thehotfix appears in a package update (recommended). KB954946 was included in Windows2008 Server SP2

Drupal is being developed to be web server independent, but we have limited or no reports ofsuccessful use on web servers not listed here.

Page 2: Drupal - Installation Guide

The total file size of your Drupal installation will depend on what you add to your site, but Drupalcore files alone will take up approximately 2 to 3 MB uncompressed. The exact size depends onthe version of Drupal you have installed.

Database serverRecommended: MySQL 4.1 or MySQL 5.0

Drupal 5.x and earlier supports MySQL 3.23.17 or higher. MySQL 4.1 or higher is stronglyrecommended.Drupal 6 supports MySQL 4.1 or higher.Drupal 7 will only support MySQL 5.0.15 or higher, and requires the PDO databaseextension for PHP (see PHP section below).

NOTE: Drupal makes use of some features not available on some inexpensive hosting plansso please check that your host allows database accounts with the following rights:SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER.These rights are sufficient to run Drupal core 6.x.

Some contributed modules, and also Drupal core 5.x (but not Drupal core 6.x), additionallyrequire the following rights:CREATE TEMPORARY TABLES, LOCK TABLES.

Note: If your system/host is running MySQL 4.1 or newer and you receive the error "Clientdoes not support authentication protocol requested by server", address the problem byfollowing the instructions provided by MySQL AB. There is a minor OS issue with someMySQL 5+ installations primarily on Windows but affecting some versions of Unix/Linuxas well.Note: When using Drupal 5.x or later, particularly with contributed modules, it may benecessary to set the system variable max_allowed_packet to at least 16M. Some inexpensivehosting plans set this value too low (the MySQL default is only 1M). In that case, you mayneed to choose a better hosting plan. A value of 1M may be sufficient for 5.x.Note: Drupal supports MyISAM and InnoDB table types. NDB tables (MySQL Cluster) arenot supported.

Note that if your web hosting account is set up with a graphic control panel such as Plesk orCPanel, it is very likely that you do not need to worry about installing a driver for MySQL -- it isprobably already installed on your server. You might wish to simply create your database andproceed with installing Drupal, and then refer back to Drupal documentation for specifictroubleshooting help if you run into problems.

PostgreSQL 7.4 or higher

Note: Some contributed modules are not as abstracted from MySQL-specific code aseveryone would like. If you are familiar with PostgreSQL please file issues with thosecontributed modules as you find them.Drupal 7 will only support PostgreSQL 8.3 or higherPHP 5.2.6 for Windows has a bug in its pgsql extension. You will need to replace it with thephp_pgsql.dll from version 5.2.5.

Currently Microsoft SQL Server and Oracle are not supported, but various efforts are underway tosupply schema. Please see discussions in the Enterprise Group if you are interested in working onthis.

PHPRecommended: PHP 5.2.xRequired: PHP version 4.4.0 or higher (Contributed modules may not support this version of PHP)

PHP 5.3 is not yet supported by Drupal 5.x, but is supported by Drupal 6.14 core and higher(see the release notes for 6.14) and also by Drupal 7.x. Note that some contributed modulesmay not be compatible with PHP 5.3, and that some PHP 5.3 configurations still showwarnings with Drupal 6.14; work is ongoing to resolve the latter in #360605: PHP 5.3Compatibility.PHP 5.2 or higher will be a requirement for Drupal 7.PHP memory requirements can vary significantly depending on your use of modules. While16 MB may be sufficient for a default Drupal 6 installation and 30 MB may be sufficient fora default Drupal 7 installation, a production site with a number of commonly used modulesenabled (CCK, Views etc.) could require 64 MB or more. Some installations may requiremuch more, especially with media-rich implementations. If you are using a hosting service itis important to verify that your host can provide sufficient memory for the set of modulesyou are deploying or may deploy in the future. (See the Increase PHP memory limit page inthe Troubleshooting FAQ for additional information on modifying the PHP memory limit.)The PHP extension for connecting to your chosen database must be installed and enabled.Drupal's currently supported database connectors are: mysql (the original MySQLextension), mysqli (an improved connector for newer MySQL installations), and pgsql (forPostgreSQL). Note: PHP 5.x no longer enables the mysql extension by default. Please readthe links above for installing and enabling your chosen connector. Additionally, Drupal 6.xdoes not provide the option to select the mysql connector if mysqli is enabled in your PHPconfiguration.PHP XML extension (for Blog API, Drupal, and Ping modules). This extension is enabledby default in a standard PHP installation; the Windows version of PHP has built-in support

Page 3: Drupal - Installation Guide

for this extension.An image library for PHP such as the GD library is needed for image manipulation (resizinguser pictures, image and imagecache modules). GD is included with PHP 4.3 and higher andenabled by default. ImageMagick is also supported for basic image manipulations in Drupalcore but there is much less support from contributed modules.PHP needs the following configuration directives for Drupal to work (only directives thatdiffer from the default php.ini-dist / php.ini-recommended):

register_globals: off; this is the default value, but some hosts have it enablederror_reporting set to E_ALL & ~E_NOTICE. Work is ongoing to change this toE_ALL for Drupal 6 and Drupal 7.safe_mode: off. Safe mode may interfere with file and image uploads.Php Data Objects (PDO) must be activated for Drupal 7 to install and run correctly.Look in your php.ini. Uncomment (remove the leading semicolin) at lineextension=php_pdo.dll, extension=php_pdo_mysql.dll. If these lines are not there, youwill need to add them. You can also use pecl install pdo to install pdo, and thenpecl install pdo_mysql (for instance), to install the PDO database driver. Moreinformation can be found on the What is PDO page.In addition, we recommend the following setting: session.cache_limiter: nocache

Some of these settings are contained in the default .htaccess file that ships with Drupal, soyou shouldn't need to set them explicitly. Note, however, that setting PHP configurationoptions from .htaccess only works under the following conditions:

With Apache (or a compatible web server)If the .htaccess file is actually read, i.e. AllowOverride is not NoneIf PHP is installed as an Apache module

See the PHP manual for how to change configuration settings for other interfaces to PHP.Drupal 7 may require the time parameter to be at least 30 seconds.In some shared hosting environments, access to these settings is restricted. If you cannotmake these changes yourself, please ask your hosting provider to adjust them for you.

Browser requirementsWebsites built using just Drupal core (i.e. with no additional, contributed modules) are compatiblewith, and fully functional, in all modern browsers that support CSS and JavaScript. However,browsers have varying levels of compliance with Internet standards such as CSS 2, so there maybe minor variations in appearance.

Here is an incomplete list of browsers that are known to work well with Drupal core and supportall of its features:

Internet Explorer 6.x and laterFirefox 2.x and laterOpera 7 and laterSafari 1.x and laterCamino 1.x and laterGoogle Chrome

It is also possible to use a browser that does not support JavaScript with Drupal, although thefunctionality will of course be slightly different. For instance, in Drupal 6 running in a browserwith JavaScript enabled, you can use a drag-and-drop interface to position blocks on the Blocksadministration page (admin >> site building >> blocks). If you don't have JavaScript, you will stillbe able to position blocks, but you will use an interface more like Drupal 5, where you will assignnumerical weights to the blocks.

It is also possible to use a browser that does not support CSS with Drupal, but of course the sitewill not look very similar to how it looks in a browser that does support CSS.

Some contributed modules and themes may not be compatible with all browsers. If you find aproblem with browser compatibility in a contributed module or theme, or some functionality in acontributed module that does not work at all without JavaScript enabled, please submit an issue toreport it to the module or theme maintainer.

Known IssuesIt's worth mentioning here that IE6 has an problem with loading more than 30 stylesheets, and it'sfairly easy to run into this problem once you start adding contrib modules.

Capacity PlanningThere are no definite figures available for Drupal's resource requirements. They will varydepending on what modules you have installed, how many users you have, and what proportionlog in rather than browse anonymously.

In the absence of definite information, here are some relevant discussions:

Need suggested baselines for Server Resource Requirements

It would help to know baseline requirements for Drupal and just the Core Modules:

- Simultaneous MySQL Connections- Simultaneous PHP Connections- CPU Thresholds

Page 4: Drupal - Installation Guide

- CPU Thresholds

The following discussions state:

"Drupal regularly makes more than 100 queries per page load"(Does 1 query = 1 connection?)

http://drupal.org/node/190070

Some combinations of modules and options have a big impact and would be worth measuring inD7. Menu entries expanded for drop down menus + path aliases + logged in users in D6:http://drupal.org/node/625898 "Executed 595 queries in 207 milliseconds."

"Is it reasonable to expect 100s of simultaneous connections"

http://drupal.org/node/312868

Measuring stuffThe Devel module, http://drupal.org/project/devel, counts database calls and execution times.

Firefox Firebug measures and displays the download times within the browser. See the overheadof adding Google analytics to a page. (for many sites, it is the slowest download.) See theoverhead of splitting a CSS file into two files for easier maintenance. See the time saved byDrupal CSS and Javascript merging.

Measure your Drupal 6 configuration and modules to see what has the greatest impact onperformance then look in the issues to see if there are major changes for the D7 versions.

Measure for both anonymous users and logged in users. A feature might add hundreds orthousands of database calls. That extra overhead might occur once every 5 minutes for anonymoususers and once every page for logged in users.

Remeasure after adding a module. When you add a cloud display module, you might add a read ofevery node for every display. You might find an alternative module that performs the reads lessfrequently and caches the result.

Remeasure after changing a setting. An example: Adding path aliases in Drupal 6 had the sideeffect of adding a database call for every entry in the menu, a significant difference for logged inusers. Combine that with hidden entries behind drop down menus and you could have a bigoverhead. Now do something as simple as listing your main menu and select Expanded for itemswith a lot of children. You could be adding hundreds of menu entries to an otherwise small smallmenu. A logged in user will get a fresh menu on every page view.

Remeasure after changing themes. Some themes add their own file and database accesses. RunFirebug to compare the CSS and Javascript file downloads, especially if the theme createsproblems with CSS or Javascript merging.

Check known Drupal 6 performance problems in D7. Some parts of D7 are different and someparts hardly changed. If you know of something that had a big impact in D6 then check it in D7.Where the impact is similar, either document the problem or open an issue for possibleimprovement.

Check the impact of Fields in your favourite add on modules. An add on module in D6 might adda special table with one row per node. In D7 the same module might add a field to the existingnode fields. The change from separate tables to a single table might make things faster byreducing accesses. The change might also slow things down because the separate table uses anindex for a lookup while the merged table uses a standard row by row search. It is worth reportingthe results, both positive and negative, to the module developers.

What is PDO?PDO is an acronym for PHP Data Objects. PDO is a lean, consistent way to access databases. Thismeans developers can write portable code much easier. PDO is not an abstraction layer likePearDB. PDO is a more like a data access layer which uses a unified API (ApplicationProgramming Interface).

How to enable PDOTo enable PDO configure --enable-pdo and --with-pdo_sqlite --with_pdo_mysql or whateverdatabase needs supporting by PDO.

Windows users

For Apache, you will need to make sure php_pdo.dll and php_pdo_mysql.dll exist in thephp/ext directory, un-comment or add the appropriate lines in php.ini, and restart the webserver.For IIS, PDO DLLs are not enabled by default. The preferred method for enabling them isto go to the Control Panel | Add/Remove Programs, highlight your PHP installation andclick "Change" (Change/Remove - XP). Specify "FastCGI", then modify the installedextensions to include these two, then restart your server.

Page 5: Drupal - Installation Guide

Macintosh users

Method 1

OS X 10.5: Detailed, step-by-step instructions are available here:

Getting PHP + GD + pdo_mysql working on OSX 10.5 (aka recompiling everything)Getting PHP + GD + PostgreSQL working on OSX 10.5 (aka recompiling everything)

OS X 10.6: OS 10.6 comes with the PDO extension enabled by default. (For instructions onconfiguring your development environment, see: Drupal 6 on OS X 10.6

Method 2

MAMP comes pre-configured with the PDO extension. For more information, see: HowTo: Createa local environment using MAMP.

Linux users

PDO is enabled by default as of php 5.1.0 on most linux systems. There is documentation toenable PDO for a mysql specific-driver.

Ubuntu

As with most Linux systems, PDO support is present in PHP5 in all recent Ubuntu distributions,and certainly in PHP 5.2 which is required for Drupal 7. If you find that PDO support is notenabled, install the following packages and restart the server.

sudo apt-get install php5-common php5-mysqlsudo /etc/init.d/apache2 reload

Before restarting the server, make sure that extension=pdo.so and extension=pdo_mysql.soare being loaded, either in the php.ini file or in their own .ini files inside /etc/php5/conf.d.

Ubuntu PDO Troubleshooting

Do not use the PECL PDO installer. The project is horribly outdated and abandoned. (Seehttp://pecl.php.net/package/PDO.) Cases have been reported where PECL PDO support seemsenabled but it doesn't work correctly. One symptom was the inability to install Drupal 7 alpha4 ornewer.

If you have already installed PECL PDO, you will need to remove it and then reinstall thefollowing PHP packages, because PHP's PDO drivers have probably been overwritten.

sudo pecl uninstall pdo_mysqlsudo pecl uninstall pdosudo apt-get install --reinstall php5-common php5-mysqlsudo /etc/init.d/apache2 reload

Again. before restarting the server, make sure that extension=pdo.so andextension=pdo_mysql.so are being loaded, either in the php.ini file or in their own .ini filesinside /etc/php5/conf.d

Basic installation

Quick install for expertsThis page provides a summary of the command line instructions for installing Drupal on a typicalUNIX/Linux web server. Every step contains a link to more detailed installation instructions whereyou also can find information about installing Drupal on other systems.

If you have problems, read Troubleshooting common problems.

Read more about system requirements (among which detailed PHP-settings and browserrequirements).

1. Download and extract files

Download Drupal from http://drupal.org/project/drupal and extract the files with a compressiontool (such as tar or 7-zip).

wget http://drupal.org/files/projects/drupal-x.x.tar.gztar -zxvf drupal-x.x.tar.gz

Move the files to a directory within your web server's document root or your public HTMLdirectory using the following command, substituting drupal-x.x with the actual version number.(On many *nix computers the path from the server's root will be /var/www/.)

mv drupal-x.x /var/www/

Page 6: Drupal - Installation Guide

You can install and use Drupal in other languages by downloading translations fromhttp://drupal.org/project/translation. Extract the files into the Drupal directory (e.g./var/www/drupal-x.x)

Read more about downloading and extracting Drupal (includes instructions for FTP, Windows andMac OS).

2. Create the configuration file and grant permissions

In the sites/default directory, copy the default.settings.php file and name the copied file assettings.php.

cp sites/default/default.settings.php sites/default/settings.php

Give the web server write privileges (666 or u=rw,g=rw,o=rw) to the configuration file.

chmod a+w sites/default/settings.php

Give the web server write privileges to the sites/default directory.

chmod a+w sites/default

Read more about preparing the configuration file.

3. Create the Drupal database

To complete the installation, you must create a database for Drupal to use. You can do this bycommand line or through phpMyAdmin (or another web interface).

mysqladmin -u username -p create databasename

Where 'username' is a MySQL user which has the CREATE and GRANT privileges. MySQL willprompt for the 'username' database password. Next you must set the access database rights. Log into MySQL:

mysql -u username -p

At the MySQL prompt, enter:

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATETEMPORARY TABLES, LOCK TABLES ON databasename.* TO 'username'@'localhost' IDENTIFIED BY 'password';

Where:

'databasename' is the name of your database'username' is the username of your MySQL account'localhost' is the server name used to access MySQL'password' is the password required for that username

If successful, MySQL will reply with:

Query OK, 0 rows affected

Read more about creating the database (among which instructions on using phpMyAdmin, andPostgreSQL and SQLite as database).

4. Run the installation script

To run the installation script, point your browser to the base URL of your website (e.g.http://www.example.com, http://www.example.com/drupal or http://localhost/drupal).

The installation wizard will guide you through several screens to set up the database, add the firstuser account, and provide basic web site settings. Follow the wizard to finalize the installation andstart working with your Drupal website.

Read more about the installation script (along with a detailed description of all the availableoptions).

Before you beginDrupal provides an installation script that automatically populates database tables and configuresthe correct settings in the settings.php file. This Installation Guide covers:

Preparing to installDownloading softwareModifying file permissionsRunning the installation scriptTroubleshooting problemsOptional: Multi-site installation(where a number of different Drupal sites run off the same code base)

About this guide

Page 7: Drupal - Installation Guide

This guide focuses on installing Drupal on a remote server running *nix (Linux, Unix, or similar)and performing tasks at the command line. You should have a terminal program and becomfortable using a text-based interface.

If you do not have "shell access" (the ability to connect to the remote computer using thecommand line) to the remote server and/or if you would prefer to use an ftp client instead ofcommand-line commands: See "Alternative tools" below.If you are installing Drupal on a Windows Server, see the "For Windows Users" notes ineach section.For IIS installations, this guide assumes you have created a web site using the IIS Manager.

Helpful InfoBefore proceeding with your first Drupal installation, you should also review:

Drupal requirementsWeb Hosting IssuesDrupal best practices sectionDrupal terminology

Alternative tools

Some of the steps in the installation process can be performed with tools such as graphicalapplications for moving files (File Transfer Protocol-FTP applications) or managing databases.This documentation focuses on performing tasks at the command line. For information on usingother tools, see the documentation that accompanies the application or is provided by your hostingservice.

Some FTP information you might find helpful:How to install drupal for newbies using windows, FTP and phpMyAdminVideocast of Drupal 6 installationModifying Linux, Unix, and Mac file permissions

Creating a test site

It is considered a good practice to do all development work on a separate test site before makingchanges to a production site. A test site allows you to evaluate the impact of upgrades, newmodules, modifications to themes etc. without causing disruption to your live site. For informationabout setting up a web server on a local computer, see the Local Server Setup section of theDeveloping for Drupal guide. A test site can also be set up on your web server using a separatedomain or subdomain.

For help setting up a test site running on the same codebase, see the [D6 Advanced and multisiteinstallation guide].

You should also review Copying a live site via command line

Alternative methods for installation

Some web hosting companies offer "one-click" installations of Drupal, or specific Drupal support.You may be able to locate one on the Drupal hosting handbook page.

There is a handbook page listing Drupal distributions, which include installation profiles and pre-packaged distributions of Drupal and modules. These may be of help as well.

Step 1: Download and uncompress DrupalDrupal is available in several versions. The "recommended release" is the latest stable release.

To learn more about versions, see the Drupal version information page.

Information about Drupal translations is available at http://drupal.org/project/translations.

Downloading DrupalBefore you begin, log in to your server and navigate to the directory from which you will beserving your Drupal site. On many *nix computers the path from the server's root will be/var/www/html, so cd /var/www/html. On a shared server, or a server that hosts multipledomains, the path will be different -- perhaps the command cd ~/www or cd ~/public_html willwork. If you are unsure of the directory, ask your hosting provider for assistance.

Download Drupal using any download utility, the two most popular of which are wget and curl.Not every computer has both. The commands are:

wget http://ftp.drupal.org/files/projects/drupal-x.x.tar.gzorcurl -O http://drupal.org/files/projects/drupal-x.x.tar.gz

(Note that the option for the curl command is the upper case letter "O" and not the numeral thatstands for zero.)

Page 8: Drupal - Installation Guide

(Replace the "http://drupal.org/files/projects/drupal-x.x.tar.gz" string with the link for the versionyou will be installing.)

Uncompressing DrupalType the following command (replacing "x.x" with your downloaded version):

tar -xzvf drupal-x.x.tar.gz

Remove the compressed file by typing rm drupal-x.x.tar.gz.

Moving Drupal to its intended locationNow you need to move the contents of the drupal-x.x directory one level "up" into the webserver's document root or your public HTML directory:

mv drupal-x.x/* drupal-x.x/.htaccess ./

The files from the directory you downloaded and decompressed have now been moved up a levelinto your web directory, and you can delete the drupal-x.x directory (which is now empty):

rmdir drupal-x.x

Before continuing to the next page ...The base URL for your Drupal installation will be set in your Web server's configuration file. Youwill need to know this URL before proceeding to the next steps of the installation. If you areinstalling Drupal on your local machine the base URL may be: http://localhost. If you are installingDrupal to a Web server your base URL may be a specific domain name (such ashttp://example.com).

OS-Specific InstructionsFor other operating systems besides *nix, refer to your site's operating system's page forinstructions and notes.

Macintosh Download NotesIf you are installing on a Mac server, or are creating a test site on your Mac, you may also wantreview these handbook pages during installation:

1. http://drupal.org/node/3691072. http://drupal.org/node/22676 -- especially if you are unsure of the "web server's document

root or the location of your public HTML directory

SELinux Download NotesNote for SELinux users

Users of Fedora or other distributions with SELinux (Security Enhanced Linux) should not movefiles unpacked into their home directory into the Web directory /var/www/html.+++++WHY NOTJUST HAVE THEM DL TO THE WEB DIRECTORY & UNPACK THERE TO BEGIN WITH?(as per the DL instructions I just modified) I do not know anything about SELinux (unless myCentOS server *is* SELinux ... which statement reveals my utter ignorance) so could someoneelse please check this Note for SELinux users section? ty --kazar 2009-08-18+++++

As posted at http://drupal.org/node/50280 moving a file preserves the context with the directory inwhich it was created. In this case the files are incorrectly associated with the home directory(user_home_t) instead of the web directory (httpd_sys_content_t).

Instead, copying the files to the directory /var/www/html will cause them to inherit the context ofthe correct directory:

cp -R drupal-x.x/* drupal-x.x/.htaccess /var/www/html

If you have already moved the files you may re-associate the files using the command chcon tochange the security context for the files:

chcon -R -t httpd_sys_content_t /var/www/html

See: SELinux may cause mysterious permission problems

Windows Download InstructionsPrerequisites

Unzip program for processing .tar.gz files. .tar.gz is a format Windows doesn't understand

Page 9: Drupal - Installation Guide

by default. This tutorial assumes you've downloaded and installed the freely available utility7-Zip to allow you to extract .tar.gz files. A number of other file compression utilities arealso available.

Download Drupal1. At the project download page., find the version you want to download. In this case, select

the first Drupal 7 version under the section 'Official Releases'. Click on 'Download'. Save thefile (don't open it with another program.)

2. Uncompress the file. Right-click on the .tar.gz file and select Open With...|7-Zip. The finalDrupal folder will appear. Hilight it, click Extract, and specify the folder into which youwould like to extract it.

Note: If you extract the files into a folder other than your web site's folder, copy thecontents of the Drupal folder into the appropriate web folder, rather than cutting/pastingthem. (This will ensure the files will inherit the appropriate permissions for the web server.)

3. Create the files folder. In the sites/default folder, create a folder called files and grantmodify permissions for it to IIS_WPG (IIS6) or IIS_IUSRS (IIS7).

4. IIS7: Create/modify web.config file. Drupal distributions come with .htaccess files for *nixuse; IIS7 users should convert this file to a web.config file for their site. If you have usedthe IIS Manager to create a new site, a basic web.config file will exist in your site's rootdirectory. Edit the file to look like this example:<?xml version="1.0" encoding="UTF-8"?><configuration> <system.webServer> <!-- Don't show directory listings for URLs which map to a directory. --> <directoryBrowse enabled="false" />

<!-- Caching configuration was not delegated by default. Some hosters maynot delegate the caching configuration to site owners by default and that may cause errorswhen users install. Uncomment this if you want to and are allowed to enable caching --> <!-- <caching> <profiles> <add extension=".php" policy="DisableCache"kernelCachePolicy="DisableCache" /> <add extension=".html" policy="CacheForTimePeriod"kernelCachePolicy="CacheForTimePeriod" duration="14:00:00" /> </profiles> </caching> -->

<rewrite> <rules> <!-- rule name="postinst-redirect" stopProcessing="true"> <match url=".*" /> <action type="Rewrite" url="postinst.php"/> </rule -->

<rule name="Protect files and directories from prying eyes"stopProcessing="true"> <matchurl="\.(engine|inc|info|install|module|profile|test|po|sh|.*sql|postinst.1|theme|tpl(\.php)?|xtmpl|svn-base)$|^(code-style\.pl|Entries.*|Repository|Root|Tag|Template|all-wcprops|entries|format)$" /> <action type="CustomResponse" statusCode="403" subStatusCode="0"statusReason="Forbidden" statusDescription="Access is forbidden." /> </rule> <rule name="Force simple error message for requests for non-existent favicon.ico" stopProcessing="true"> <match url="favicon\.ico" /> <action type="CustomResponse" statusCode="404" subStatusCode="1"statusReason="File Not Found" statusDescription="The requested filefavicon.ico was not found" /> </rule> <!-- To redirect all users to access the site WITH the'www.' prefix, http://example.com/... will be redirected tohttp://www.example.com/...) adapt and uncomment the following: --> <!-- <rule name="Redirect to add www" stopProcessing="true"> <match url="^(.*)$" ignoreCase="false" /> <conditions> <add input="{HTTP_HOST}" pattern="^example\.com$" /> </conditions> <action type="Redirect" redirectType="Permanent"url="http://www.example.com/{R:1}" /> </rule> --> <!-- To redirect all users to access the site WITHOUT the'www.' prefix, http://www.example.com/... will be redirected tohttp://example.com/...) adapt and uncomment the following: --> <!-- <rule name="Redirect to remove www" stopProcessing="true">

Page 10: Drupal - Installation Guide

<match url="^(.*)$" ignoreCase="false" /> <conditions> <add input="{HTTP_HOST}" pattern="^www\.example\.com$" /> </conditions> <action type="Redirect" redirectType="Permanent"url="http://example.com/{R:1}" /> </rule> --> <!-- Rewrite URLs of the form 'x' to the form 'index.php?q=x'. --> <rule name="Short URLS" stopProcessing="true"> <match url="^(.*)$" ignoreCase="false" /> <conditions> <add input="{REQUEST_FILENAME}" matchType="IsFile"ignoreCase="false" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory"ignoreCase="false" negate="true" /> <add input="{URL}" pattern="^/favicon.ico$" ignoreCase="false"negate="true" /> </conditions> <action type="Rewrite" url="index.php?q={R:1}"appendQueryString="true" /> </rule> </rules> </rewrite>

<!-- httpErrors> <remove statusCode="404" subStatusCode="-1" /> <error statusCode="404" prefixLanguageFilePath="" path="/index.php"responseMode="ExecuteURL" /> </httpErrors -->

<defaultDocument> <!-- Set the default document --> <files> <remove value="index.php" /> <add value="index.php" /> </files> </defaultDocument> </system.webServer></configuration>

Step 2: Create the databaseBefore running the installation script, you must create an empty database and database user (a username assigned the rights to use the Drupal database).

This page offers guidance for creating your Drupal database using a Web browser-based controlpanel (such as "CPanel" or "Plesk"), or by using phpMyAdmin (another browser-based databaseutility), or by creating the database directly from the MySQL or PostgreSQL command prompt(for more advanced users).

Create a database using a browser-based control panelMost web hosting accounts provide a Web-based control panel to help you administer your site.These tools include easy-to-use features for creating a new database, and for creating a "user"with rights to the database. To create a database using a browser-based control panel consult thedocumentation or ask your web host service provider.

When you create the user for your database, you may see a page where you can specify theprivileges that user will have for various operations on the database. In most Web control panels'"database wizard", if you simply check "All" privileges for the user you create (and then uncheck"Grant" if it is listed as a privilege) your user will be set up correctly.

Take note of the username, password, database name and hostname (e.g., are you installing inwww.example.com, or in drupal.example.com, www.example.com/blog etc.) as you create thedatabase. You will enter these items into fields in your browser when running the install script (seenext page).

Note that in many cases when creating databases and users via a Web-based graphic interface, theuser name you use to log into your control panel is added as a prefix to the database name andpossibly to the database user name as well. For example, if you log into your Web site controlpanel as "webadmin" and create a database named "drupal7db" and a user for that database named"d7user", when running the Install script (see next page) the database and user may need to betyped in as "webadmin_drupal7db" and "webadmin_d7user". (This is because many hostingaccounts are on shared servers, and on one server each database and user name must be uniqueacross all accounts on the server.)

If you have created your database and user via a Web-based interface, you can skip the remainderof this page and continue with the install instructions on the next page.

Create database and user using PHPMyAdminThis presumes you have root access to PHPMyAdmin

1. Log in to PHPMyAdmin as the root user2. Click Privileges & Add a new User3. In the User name field, enter the username you wish to use4. In the Host field, select Local which is more secure, unless you will be accessing the

Page 11: Drupal - Installation Guide

database with this user from another server5. Enter or generate a password for the user.6. In the Database for User list, select Create database with same name and grant all privileges

and click Go

You have now created a user that has all privileges only on the database with the same name. Thisis more secure than using a general username & password for all your sites on the same server, asit limits access to your databases if someone gets hold of your database logins.If you want to have a different name for database and user, just select the created database, thenoperations tab. You will find an option Rename database to. If you need more details about usingPHPMyAdmin, check out the official wiki.

Take note of the username, password, database name and hostname (e.g., are you installing inwww.example.com, or in drupal.example.com, www.example.com/blog etc.) as you create thedatabase. You will enter these items into fields in your browser when running the install script (seenext page).

Note that in many cases when creating databases and users using a web interface, the user nameyou use to log in to your control panel is added as a prefix to the database name and possibly tothe database user name as well. For example, if you log into your Web site control panel as"webadmin" and create a database named "drupal7db" and a user for that database named"d7user", when running the Install script (see next page) the database and user may need to betyped in as "webadmin_drupal7db" and "webadmin_d7user". (This is because many hostingaccounts are on shared servers, and on one server each database and user name must be uniqueacross all accounts on the server.)

If you have created your database and user via phpMyAdmin, you can skip the remainder of thispage and continue with the install instructions on the next page.

Create a database from the command lineIf you do not use a Web control panel or are experienced with and prefer to use MySQL orPostgreSQL commands, you can follow the information below.

Additional information about privileges, and instructions to create a database using the commandline are available in INSTALL.mysql.txt (for MySQL) or INSTALL.pgsql.txt (for PostgreSQL).

Create a database using MySQL commands

For information on installing and configuring MySQL see http://dev.mysql.com/tech-resources/articles/mysql_intro.html

In the following examples, 'username' is an example MySQL user who will have the CREATEand GRANT privileges and 'databasename' is the name of the new database Use the appropriatenames for your system.

1. Create a new database for your site.

mysqladmin -u username -p create databasename

MySQL prompts for the 'username' database password, and creates the initial database files.

2. Log in and set the access database rights:

mysql -u username -p

MySQL prompts for the 'username' database password.

3. At the MySQL prompt, set the permissions using the following command:

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCKTABLES, CREATE TEMPORARY TABLES ON `databasename`.* TO'username'@'localhost' IDENTIFIED BY 'password';

In this case:

'databasename' is the name of your database'username@localhost' is the username of your MySQL account'password' is the password required for that username

You will need the ` around the database name if you have used a MySQL escape characterin your schema name.

Eg: drupal_test_account.* should be drupal\_test\_account.* for security (underscore is awildcard). This requires the ` wrapper. `drupal\_test\_account`.*

Note: unless your database user has all of the privileges listed above, you will not beable to run Drupal.

4. If successful, MySQL will reply with:

Query OK, 0 rows affected

5. To activate the new permissions, enter the following command:

FLUSH PRIVILEGES;

Page 12: Drupal - Installation Guide

The database should be created with UTF-8 (Unicode) encoding.

Create a database using PostgreSQL

The database must be created with UTF-8 (Unicode) encoding.

1. Create a database userThis step is only necessary if you don't already have a user setup (e.g. by your host) or youwant to create new user for use with Drupal only. The following command creates a newuser named 'username' (you should substitute this with the desired username), and promptsfor a password for that user:

createuser --pwprompt --encrypted --no-adduser--no-createdb username

If everything works correctly, you'll see a CREATE USER notice.

2. Create the databaseThis step is only necessary if you don't already have a database setup (e.g. by your host) oryou want to create new database for use with Drupal only. The following command createsa new database named "databasename" (you should substitute this with the desired databasename), which is owned by previously created "username":

createdb --encoding=UNICODE --owner=username databasename

If everything works correctly, you'll see a CREATE DATABASE notice.

Step 3: settings.phpYou must create a settings.php file and set some permissions.

Settings.phpYour Drupal download comes with a sample configuration file at sites/default/default.settings.php. The default file is not used by the installer. It must be copied and thenew file must be given the correct name.

1. Copy the default.settings.php to settings.php.You can do this from the command line (working from the root of the directory containingyour Drupal installation) using cp sites/default/default.settings.phpsites/default/settings.php.NOTE: Do not simply rename the file. The Drupal installer will need both files.

2. You should now have both a default.settings.php and settings.php file in yoursites/default directory.

3. Make the settings file writeable, so that the installer can edit it, usingchmod a+w sites/default/settings.phporchmod 666 sites/default/settings.phpBoth commands have the same effect.Several FTP tools like Filezilla, Transmit, and Fetch allow you to change file permissions,using a 'file attribute' or 'get info' command. In this case the octal or numeric value filepermission should be set to 666. If your ftp client has checkboxes for setting permissions,check both the Read and Write boxes for "Owner", "Group", and "Others" (leaving theExecute boxes unchecked).

4. To let the files directory be created automatically, give the web server write privileges to thesites/default directory.chmod a+w sites/default

OS-Specific InstructionsFor other operating systems besides *nix, refer to your site's operating system's page forinstructions and notes.

Fedora LinuxYou will need to put selinux in permissive mode to have the permissions modified by the installscript. Even if you have the permissions set correctly for settings.php the install script will thinkyou don't if selinux is active.

You may need to turn off selinux during your Drupal install and turn it on after the install iscomplete.

Remember that permissions must also be set to allow writing to the default folder so that thestartup script can create the files folder inside it.

IIS (Windows)

Page 13: Drupal - Installation Guide

On a Windows system using IIS, right-click on sites/default/settings.php and grant Modifypermissions to IIS_WPG (IIS6) or IIS_IUSRS (IIS7).

IIS7: You can also do this from the command line from within your \Drupal directory:

C:\inetpub\wwwroot\Drupal&gt;icacls sites\default\settings.php /grantBUILTIN\IIS_IUSRS:(M)

The installer will change the file back to Read Only after installation, but you should verify thisafter installation. For more information about modifying Windows file permissions, see theTroubleshooting FAQ.

Mac OS XOptional instructions on setting up a local MAMP (Mac Apache MySQL PHP) server.

For an external server, follow these steps:

1. Install Drupal 7.0 as /Users/xxx/Sites/drupal, user xxx is in the "_www" group and make theentire installation is group writable. Create a soft link from

/Library/WebServer/Documents/xxx to /Users/xxx/Sites.2. Re-writing seems to be enabled by default in Apache2 on Leopard. Enable PHP5 and virtual

hosts in Apache2, i.e. by uncommenting these lines in /etc/apache2/httpd.conf:

#<br /># Dynamic Shared Object (DSO) Support<br />#<br />...<br /><br/>LoadModule libexec/apache2/libphp5.so<br /><br />...<br /><br /># Virtualhosts<br />Include /private/etc/apache2/extra/httpd-vhosts.conf

3. Add a virtual host stanza to the /private/etc/apache2/extra/httpd-vhosts.conf filethat has at least this in it:

&lt;VirtualHost *:80&gt;<br />&nbsp;&nbsp;&nbsp; DocumentRoot/Library/WebServer/Documents<br />&nbsp;&nbsp;&nbsp; ServerNamelocalhost<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; &lt;Directory&quot;/Library/WebServer/Documents&quot;&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Options FollowSymLinks IndexesMultiViews<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AllowOverrideAll<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Order allow,deny<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Allow from all<br/>&nbsp;&nbsp;&nbsp; &lt;/Directory&gt;<br />&lt;/VirtualHost&gt;

4. Add a variant of the RewriteBase /drupal line in the stock/Users/xxx/Sites/drupal/.htaccess file:

&lt;IfModule mod_rewrite.c&gt;<br /> RewriteEngine on<br /><br /> ...<br/><br /> # Modify the RewriteBase if you are using Drupal in a subdirectoryor in a<br /> # VirtualDocumentRoot and the rewrite rules are not workingproperly.<br /> # For example if your site is at <ahref="http://example.com/drupal" title="http://example.com/drupal"rel="nofollow">http://example.com/drupal</a> uncomment and<br /> # modifythe following line:<br /> # RewriteBase /drupal<br /> RewriteBase/xxx/drupal<br /><br /> ...<br /><br /> # Rewrite URLs of the form&#039;x&#039; to the form &#039;index.php?q=x&#039;.<br /> RewriteCond%{REQUEST_FILENAME} !-f<br /> RewriteCond %{REQUEST_FILENAME} !-d<br />RewriteCond %{REQUEST_URI} !=/favicon.ico<br /> RewriteRule ^(.*)$index.php?q=$1 [L,QSA]<br />&lt;/IfModule&gt;

5. Make a copy of the /Users/xxx/Sites/drupal/sites/default directory tree as/Users/xxx/Sites/drupal/sites/localhost. Make sure this directory is writable by the _wwwgroup.

6. Manually create the database in MySQL. Make a copy of

/Users/xxx/Sites/drupal/sites/localhost/default.settings.php file as

/Users/xxx/Sites/drupal/sites/settings.php and make this file writable by the _www group.Configure the database in /Users/xxx/Sites/drupal/sites/settings.php

/**<br /> * Database settings:<br /> *<br />...<br /><br /> */<br/>#$db_url = &#039;mysql://username:password@localhost/databasename&#039;;

7. Rebuild PHP5 to include the GD tools according to the instructions

here.8. After modifying the file permissions in the next step, go to

http://localhost/xxx/drupal/install.php. The pages came up as shown on the Run the installscript.

Step 4: Run the installation scriptFor Drupal 6

To run the install script point your browser to the base URL of your website.

The base URL is defined in your Web server configuration file and is specific to the document

Page 14: Drupal - Installation Guide

root where you placed your Drupal files. If you have installed Drupal on a Web server this willlikely be a domain name such as http://example.com. If you have installed Drupal on your desktopmachine this URL might be http://localhost.

You will be guided through several screens to set up the database, create tables,

add the first user account and provide basic web site settings.

Page 15: Drupal - Installation Guide

If you get any errors regarding the files directory and its permissions, see [#394704].

For Drupal 7

To run the Drupal install script, point your browser to the base URL of your web site.The "base URL" means the document root (directory) where you placed your Drupal files (and isdefined in your web server configuration file). If you have installed Drupal on a web host this willlikely be a domain name such as http://www.example.com. If you installed Drupal in asubfolder, then you should point your browser to the subfolder (e.g.http://example.com/subfolder). If you have installed Drupal on your desktop machine thisURL might be http://localhost/drupal.

If the installation process does not simply appear by entering the base URL of your site, add thefile name "install.php" (for example http://www.example.com/install.php).

You will be guided through several screens:

1. Choose which profile to use for the installation (standard or minimal).Most people should select the "standard" option. The standard option comes with defaultcontent types already enabled, such as Article and Page, and with appropriate publishingoptions already set. (Of course you can later edit these default content types and theirsettings, or add additional ones.) The standard profile also has a useful collection of modulespre-enabled for you.

The "minimal" option is targeted toward more experienced Drupal site creators who wish toset up their own content types with associated publishing options. The minimal profile hasonly three modules enabled: Block, Database logging, and Update status.

2. Select a languageIf you want to install using a language other than the default English, click the Learn how toinstall Drupal in other languages link.

3. Verify requirementsIf your installation directory is not yet configured properly, you will be informed at this step.You can correct the settings individually and either refresh the browser screen or click 'Tryagain' to see whether there are any errors left.

Possible errors include:

Missing directories and/or incorrect permissionsThe installer will attempt to automatically set up a number of directories, but this mayfail due to permission settings. In this case you will find the missing directories listed.

Page 16: Drupal - Installation Guide

sites/default/files

sites/default/private

sites/default/private/files

These directories should be set to the following permissions chmod o+wsites/default/files OR chmod 777 sites/default/files

Missing settings.php or incorrect permissionsIf settings.php is missing or not accessible, follow the instructions in Step 2:Modify file permission. Note that you will need both the default.settings.php andsettings.php files.

4. Set up databaseEnter the database name as well as the username and password for the database that youcreated in Step 3: Create Drupal's database. This username and password information allowsDrupal to access your database, so the install script can create tables. Note that this is notthe username and password for administering Drupal; these will be created in the next step.

The Advanced options will allow you to change the database host ('localhost' is usually usedin this entry: wamp/bin/apache/Apache2.2.11/bin/php.ini as an example of the locationon a Windows box running WAMP). You can also change the port and the table prefix. Youonly need to change the port if you are using a non-standard port number. The table prefix isuseful if you are installing multiple instances of Drupal tables that share the same database.

Click Save and continue at the bottom of the page.

5. Install profileA progress bar will appear and display notes from the installer regarding the progress of theinstallation. If no errors are encountered, the next page will automatically load in yourbrowser.

6. Configure siteInput the information for the first user account (which will be automatically assigned fulladministration permissions) and provide basic web site settings.

In the Site name field enter the name you wish to use for the site. You can also edit itlater through the administration interface.In the Site e-mail address field, enter the e-mail address that will be used by Drupalwhen it sends out notifications such as registration information.In the Site maintenance account field, enter the Username, E-mail address, andpassword for the main administration account.

Note that there is a distinction, as of Drupal 7, between the main administrationaccount that you set up on this page, and the "Administrator" site administrator userrole that you will see when you visit the "Roles" and "Permissions" pages in theadministration interface. The account you set up in the Site maintenance accountsection during installation is a super-user who has overall control over every aspect ofthe management and configuration of the site. (This will bewww.example.com/user/1, for those of you familiar with that account from earlierversions of Drupal.)

In the Server settings field, select your Default country and Default time zone.In the Update notifications field leave both boxes checked if you want your Drupalserver to alert you when updates are required. Often updates relate to security issuesand are important to perform. However, if you have restricted Internet connectivity(for example if you are behind a corporate firewall) you may want to leave thesesettings unchecked and test them later.

Click "Save and continue". On success you will see the Drupal installation complete screen.If there are any error messages, review and correct them now.

Secure your site

After the installation is complete, remove write permissions for the settings.php file.

chmod u=rw,o=r,a=r sites/default/settings.php OR chmod 644sites/default/settings.php

If you make manual changes to the settings.php file later, be sure to protect it again after makingyour modifications.

Failure to remove write permissions to that file is a security risk. (Although the default location forthe settings.php file is at sites/default/settings.php, it may be in another location if you use themulti-site setup.)

Installing an installation profileWhat is an installation profile?

From Installation profiles:

Installation profiles are a feature in Drupal core that was added in the 5.x series. TheDrupal installer allows you to specify an installation profile which defines whichmodules should be enabled, and can customize the new installation after they havebeen installed. This will allow customized "distributions" that enable and configure a

Page 17: Drupal - Installation Guide

set of modules that work together for a specific kind of site (Drupal for bloggers,Drupal for musicians, Drupal for developers, and so on).

Please note that an installation profile can only be used when you're installing a new Drupalinstance. This means that you can not run an installation profile on an existing Drupal to add extrafunctionality. You can also only select one installation profile, it is not possible to install a wikiinstallation profile along with a French language profile for instance.

The installation of an installation profile is not required, but optional.

Installing the profile

1. Start by downloading the installation profile and unpacking it.2. Copy the entire directory that you just unpacked into the profiles directory of your core

installation. For example, if you have core installed at /home/www/htdocs and youdownloaded and unpacked an installation profile called "fooprofile", you would want tocopy the entire "fooprofile" directory into /home/www/htdocs/profiles/fooprofile.

3. Read the documentation on the installation pack you downloaded. This can either be foundon the profile's project page (example: Innovation News Installation Profile) or in theREADME.TXT that came with the download (example: Drupal Hebrew Installation Profile).It should contain installation instructions such as listing the required extra modules and/orthemes that you will have to download.

4. Download these modules and themes and put them in the right directory. This is usuallysites/all/modules and sites/all/themes.

5. Go to your site's install.php and select which installation profile to install.

Enjoy your fresh pre-configured Drupal installation!

After InstallationNow that you've installed Drupal, there are a few tasks you need to do:

Set up cronConfiguring cron is an extremely important task in your Drupal website setup. Search module'sindexing of your website's content, aggregator module's retrieval of feeds, ping module'snotification of other sites of updates, and system module's routine maintenance tasks, such aspruning of logs, all depend a properly configured cron job.

What is a cron job?

Many Drupal modules have tasks that have to take place from time to time. Think of cron as thetolling of a bell, letting Drupal know that it should perform the appropriate tasks.

The actual "cron job" is a time-triggered action that is usually (and most efficiently) performed byyour website's hosting server, but can also be configured by a remote service or even from yourown desktop.

For your Drupal site, what actually happens is that the cron job triggers an invisible visit to thesite's cron.php file (http://www.example.com/cron.php) which, in turn, executes tasks on behalf ofinstalled modules.

Configuring cron jobsCron is a daemon that executes commands at specified intervals. These commands are called "cronjobs." Cron is available on Unix, Linux and Mac servers. Windows servers use a Scheduled Taskto execute commands.

There is a video, How To: Setting up Drupal's Cron that talks about cron and shows various waysof configuring it.

The cron command

In the following example, the crontab command shown below will activate the cron tasksautomatically on the hour:

0 * * * * wget -O - -q -t 1 http://www.example.com/cron.php

In the above sample, the 0 * * * * represents when the task should happen. The first figurerepresents minutes – in this case, on the "zero" minute, or top of the hour. (If the number were,say, 10, then the action would take place at 10 minutes past the hour.) The other figures represent,respectively, hour, day, month and day of the week. A * is a wildcard, meaning "every time."

The rest of the line basically tells the server to "ping" the url http://www.example.com/cron.php.

Here is a diagram of the general crontab syntax, for illustration:

# +---------------- minute (0 - 59)# | +------------- hour (0 - 23)# | | +---------- day of month (1 - 31)

Page 18: Drupal - Installation Guide

# | | +---------- day of month (1 - 31)# | | | +------- month (1 - 12)# | | | | +---- day of week (0 - 7) (Sunday=0 or 7)# | | | | |* * * * * command to be executed

Thus, the cron command example above means "ping http://www.example.com/cron.php at thezero minute on every hour of every day of every month of every day of the week."

How Drupal uses cron

Every Drupal install requires regular actions to handle maintenance tasks such as cleaning up logfiles and checking for updates. Cron.php is the file that Drupal uses to run the maintenanceprocess.

For instance, if your site were www.example.com, loading the URLhttp://www.example.com/cron.php in your browser would run the maintenance.

This page is automatically set up when you install Drupal. Simply loading the URL will run themaintenance. Nothing more is required.

For a modest personal site, you might set up this cron job to run once a day. For a more active siteyou might want to run that job more often—perhaps every few hours or every hour. This regularvisit will tell Drupal to perform its periodic tasks, and this will help keep your system runningsmoothly.

How to set up a cron job

Cron jobs are scheduled by setting up a "crontab." A crontab is a text file that contains thecommands to be run. This file can be created and edited either through the command lineinterface, or, if you manage your website through a web-based control panel such as cpanel orPlesk, you will use the web interface. Check with your hosting company for detailed instructions ifyou are using a web-based control panel.

To edit a crontab through the command line, type:

crontab -e

If this fails, see the Troubleshooting Cron section below.

Add ONE of the following lines:

45 * * * * /usr/bin/lynx -source http://example.com/cron.php

45 * * * * /usr/bin/wget -O - -q -t 1 http://www.example.com/cron.php

45 * * * * curl --silent --compressed http://example.com/cron.php

This would have a lynx, wget, or curl visit your cron page 45 minutes after every hour.

Three options are provided in case either wget, lynx or curl are not installed on the server. Anywill do the job well.

Learn more about the crontab file syntax here to set up the cron job to run more or less often.

There are many ways to configure a cron job. If you have full access to crontab features, youshould be able to simply paste in one of the above example commands – be sure to replace"example.com" with your own web domain or docroot.

If you're on shared hosting, you should be able to find cron job configuration somewhere in yourhosting control panel. Some hosts even have cron "wizards" that walk you through the cronconfiguration, making it much easier if cron is new to you. On a Windows system you canaccomplish the same thing with scheduled tasks to launch Internet Explorer pointed to the URL.

Some hosting companies do not permit local loopback, so using wget, curl or lynx will not work.If this is the case, and they run PHP as a CGI (check with your hosting company to see if this isthe case), the following will run the cron locally:-

/usr/bin/php /home/sites/example.com/public_html/cron.php

Some hosting companies don’t allow access to cron

If your hosting company restricts access to cron you have many options.

Ask the company to give you access, or to set up a cron job for youAsk someone else with access to a server to set up a cron job for you. Any Unix, Linux, orMac server with access to the internet can have a cron job to regularly visit your site. Thereare also some companies that offer cron services.Use the Poor Man's Cron module.Find an online cron service. Many are free but with restrictions.

Cron doesn't guarantee your commands will run at the specified interval. But Drupal will try itsbest to come as close as possible. The more you visit cron.php, the more accurate cron will be.

Troubleshooting cron jobs

Page 19: Drupal - Installation Guide

If you receive a permission denied error after starting crontab -e, you may need to use sudo:

sudo crontab -e

You may need to adjust the path to wget, lynx or curl in your crontab. For example, the cronexample listed above contains the line:

45 * * * * /usr/bin/lynx -source http://example.com/cron.php

However, Lynx may be in a different location on your server, or not installed at all. To find outwhere Lynx is installed, enter:

whereis lynx

or

which lynx

If it is not located at /usr/bin/lynx adjust the path as needed. The same applies for wget and curl. Ifnone are installed ask a server administrator for help.

It may be necessary to change http://example.com/cron.php to the location of your Drupalinstallation. For example, if you have Drupal installed in a subdirectory, it might behttp://www.example.com/drupal/cron.php).

Example scripts

Drupal ships with two example scripts in the scripts directory, cron-curl.sh and cron-lynx.sh. Youcan call these scripts from cron as well:

45 * * * * /home/www/drupal/scripts/cron-lynx.sh

Note that the scripts will need to be updated with the path to your directory and URL.

Running cron as an authenticated user

#!/bin/sh# Reference http://drupal.org/node/479948#comment-1673488 by pearlbear

SITE=https://dev.example.com/USERNAME=user.namePASS=ChangeMe!!12

COOKIES=/tmp/cron-cookies.txtWGETPARAMS="--quiet -O /dev/null --no-check-certificate --save-cookies $COOKIES--keep-session-cookies --load-cookies $COOKIES"# if you run drupal in a default language different than English you need tomodify thisLOGIN="Log%20in"

wget $WGETPARAMS "${SITE}user"wget $WGETPARAMS --post-data="name=$USERNAME&pass=$PASS&op=$LOGIN&form_id=user_login" "${SITE}user"wget $WGETPARAMS " ${SITE}cron.php"

Security notes

It is possible to run cron.php directly via scripts/drupal.sh with Drupal 6. Drupal.sh allows aDrupal page to be executed from a shell script. To do so, add the following cron job to run as theApache user.

/full/path/to/drupal.sh --root /full/path/to/site/root/ http://default/cron.php

Note that http://default/cron.php is NOT shown as an example, it should be used as is, withoutchanges.

Taking this approach allows cron.php to be blocked to prevent remote access.

To block remote access to cron.php, in the server, .htaccess or vhost configuration file add thissection:

<Files "cron.php"> Order Deny,Allow Deny from all Allow from localhost Allow from 127.0.0.1 Allow from xx.xx.xx.xx <-- your IP address </Files>

If you take this approach and use drupal.sh to call cron.php, it is probably best not to use the rootuser to run the cron job. A non-privileged user account, or the Apache account user, for examplehttp-service or www-data, is a better choice. To do so, call crontab -e when logged in as a non-privileged user, or for the Apache account on a Debian server, for example, you can add a userparameter:

sudo crontab -e -u www-data

The downside to this method is that any URLs generated by cron jobs using this method will notbe properly formed, starting with "http://default/".

Page 20: Drupal - Installation Guide

Tips and tricks

Cron Sandbox is a useful site for testing cron entries.

Multiple sites

If you run many sites, you can use this tip to make managing your cron jobs easier. To minimizethe clutter, create a /etc/cron.5min directory and have crontab read this directory every fiveminutes.

*/5 * * * * root run-parts /etc/cron.5min

Then place multiple individual files into the /etc/cron.5min directory, one for each site. The filescan be named "site1", "site2", etc. -- note that run-parts may fail to detect files which contain adot (.) in their name. To make sure that all of your files are visible to cron, type this at a shellprompt:

$ sudo run-parts --test /etc/cron.5minand make sure that all of your files are listed.

Each of the files in /etc/cron.5min should contain one line:

/usr/bin/lynx -source http://(full site URL)/cron.php > /dev/null 2>&1or, alternatively, one of the curl or wget commands specified above.

If this doesn't work, try putting another line at the start of each file:

#!/bin/shand make sure that the files are executable by doing

$ sudo chmod u+x /etc/cron.5min/*

For more information about using cron in a multisite configuration, see the Multisite Cron sectionof this guide.

SSL

When using SSL, add one additional argument when calling wget: --no-check-certificate. Do notput “--no-check-certificate” between the -0 and the -.

45 * * * * /usr/bin/wget --no-check-certificate --quiet -O -https://example.com/cron.php

Configuring an editor for cron

You can specify which text editor (emacs, vi, nano, etc.) you want to use to edit the crontab. Totell the system which editor you want to use, type:

export EDITOR=nano

Configuring cron jobs in CpanelCpanel controls domains. WHM, Web Host Manager, is the Cpanel product for controllingdomains in a Virtual Private Server. If there is no cron option in your Cpanel, you may have toadd cron in WHM. Cron may be in different places in the various Cpanel themes. In the Crimsonsmoke theme, you select Advanced then Cron jobs.

You are offered the option of standard or an "advanced" Unix style user interface. You may see anerror message similar to the following./usr/bin/crontab permissions are wrong. Please set to 4755

The Unix style interface dumps you in a page where you can enter a command the same asdescribed on the main Configuring cron jobs page.

The standard page lets you select the number of minutes, hours, days, or months from selectionlists.

Configuring cron jobs on MAMP localhostThese are instructions for setting up a cron job on your localhost using MAMP on a Mac.

1. In Terminal type crontab -e. This allows you to add a cron job, using the vim editor.2. Press i on your keyboard to go into vim's insert mode.3. Type in you cron command. For example, to run at minute 5 of every hour using curl, use:

5 * * * * /usr/bin/curl --silent --compressedhttp://localhost:8888/cron.phpBut to run every 5 minutes, use:*/5 * * * * /usr/bin/curl --silent --compressedhttp://localhost:8888/cron.phpNote that if you are not using MAMP's default 8888 port, you should leave that off.

4. While in insert mode you can use the arrows and delete keys as you would normally.5. Press escape key to exit vim's insert mode.

Page 21: Drupal - Installation Guide

6. Type ZZ (Must be capital letters -- saves the file and exits crontab).7. Verify the cron job details by typing crontab -l (that's a lower case L) at the terminal

prompt.

I recommend that you first try setting the job to run every 2 minutes (with */2), so that you cancheck, reasonably quickly, that it is running. Then edit crontab again and change the curl commandto your preferred time.

Non-Vim althernative

For those with a reservation against Vim (or any other command-line editor), you can do it likethis:- Create a document with your editor of choice.- Add the cronjobs you want to add, like described above.- Save the file as "mycron.txt" on your desktop (or any other place you like).- Open up a Terminal window, and go to the desktop ( cd ~/Desktop ).- Type in crontab mycron.txt- Type in crontab -l to verify that your commands were added to cron.Note: This method will overwrite the entire crontab, so keep the mycron.txt file available. Whenyou need to add or change cronjobs, just edit that file and repeat the crontab mycron.txtcommand to update your cronjobs.

Configuring cron jobs on DreamHostOn DreamHost you can configure cron jobs using either the web panel or the shell.

Setting up cron jobs using the web panelVisit https://panel.dreamhost.com/index.cgi?tree=goodies.cron&

Click 'Add a New Cron Job' and enter the following command:curl --silent --compressed http://example.com/cron.php

Note: The above code is dependent on http being accessible. If you want to run a cron job ona password protect domain, use the include the following with the absolute path for yourdomain to cron.php instead of the example:/dh/cgi-system/php5.cgi /home/username/example.com/drupal/cron.php

In the same interface, you should specify a title (such as 'Drupal Cron'), e-mail address for results(not recommended), and a run interval. If you have more than one Drupal site, you can add morethan one command per cron job (one per line).

Setting up cron jobs using the shellThis information comes from the Dreamhost knowledge base.

Via the "crontab" command from the shell.

crontab -l will show you your currently set up cron jobs on the server.crontab -r will delete your current cron jobs.crontab -e will allow you to add or edit your current cron jobs by using your default text editor toedit your "crontab file".

Your crontab includes all the cron jobs you'd like, with one cron entry per line. A cron entry lookslike this:

45 2 * * * curl --silent --compressed http://example.com/cron.php

The first number is the minute of the hour for the command to run on.The second number is the hour of the day for the command to run on.The third number is the day of the month for the command to run on.The fourth number is the month of the year for the command to run on.The fifth number is the day of the week for the command to run on.

Here are some examples to help you learn the syntax for the numbers:

32 * * * * : will be run every hour on the 32nd minute.12,42 * * * * : will be run twice an hour on the 12th and 42nd minutes.*/15 */2 * * *: will be run at 0:00, 0:15, 0:30, 0:45, 2:00, 2:15, 2:30, ...43 18 * * 7: will be run at 6:43pm every Sunday.

You can also edit crontab on a local file. Upload it to a directory and run:

crontab YourFileName

It'll replace your crontab with what's on the text file, without having to edit it online. This is usefulif you're using a telnet client which doesn't support ANSI control codes (such as the Windows'one) and can't understand what the heck is going on on the editors.

In my own experience, I found that only by entering one cron command per line worked (one lineeach for :10, :20, :30, etc.). I could not get crontab to take the "*/15" argument, so I workedaround it. Also, if you have ANY character after the last command (space, CR, whatever) the file

Page 22: Drupal - Installation Guide

will not take.

I like this file-load approach because I have a basic command file to edit or call up again ifneeded. Afterwards, running crontab -l will confirm that the job did take.

Configuring cron jobs on Media Temple GridServers (gs)Through my experience and to my knowledge, cron jobs on Media Temple's Grid Servers must berun via an .sh file in the "/scripts" directory of your Drupal installation. This was confusing to meas I've always setup cron jobs in cPanel. Media Temple does not use cPanel. Following the steps tosetup a cron job like 45 * * * * /usr/bin/wget -O - -qhttp://www.example.com/cron.php through a typical cPanel interface will not work in MediaTemple's cron job creation tool.

Use the following steps to get cron jobs working on a Media Temple Grid Server:

1. Log into your (mt) AccountCenter and go to your WebControl panel.2. Click on the "Cron Jobs" icon to enter the cron configuration page.3. Select the "Add a new cron job" button.4. Enter an email address for the "Output email". Note:Leave this blank if you don't want

constant emails.5. Enter the following in the "command to run" text box:

curl http://www.example.com/cron.phpwhere "example.com" is your domain name.

6. Under "Scheduling Settings" select how often you want your cron job to run.7. Note the Media Temple will not allow a cron job to run more often than "every 5 minutes".

To setup a cron job to run once an hour:Under the "minutes" entry, specify the minute value on which the cron job willstart each hour.Then select the following radio boxes: hour, day, month, day of the week.

Configuring cron jobs on WindowsTo setup a Windows machine to run cron.php at a specific time follow the specific instructionsbelow. This can be useful if you are not familiar with Linux/Unix, or if your web host does notoffer the ability to run cron jobs; you can run them remotely from your own computer.

Note: These instructions were written for Windows XP but should be similar in other versions ofWindows.

Creating a Scheduled Task

1. Open Scheduler2. Go to Start > Programs > Accessories > System Tools > Scheduled Tasks3. Double-click Add Scheduled Task4. The Scheduled Task Wizard will appear. Click Next.5. Select the program to run. Choose your browser from the list (for example, Internet Explorer

or Mozilla Firefox). Click Next.6. Give the task a Name, such as Drupal Cron Job, and choose the Frequency with which to

perform the task (for example, Daily)). Click Next.7. Choose specific date and time options (this step will vary, depending on the option selected

in the previous step). When finished, click Next.8. Enter your password if prompted. Change the username if required (for example, you'd like

the task to run under a user with fewer privileges security reasons). Click Next.9. On the final page, select the checkbox Open advanced properties for this task when I

click Finish and click Finish.

Configuring the task

1. Go to the task's setting page either by checking the checkbox at the end of the last step, orby double-clicking on the task.

2. In the Run box, after the text that is there now (for example,C:\PROGRA~1\MOZILL~1\firefox.exe), enter a space and then type the address to yourwebsite's cron.php page in double quotations (for example,C:\PROGRA~1\MOZILL~1\firefox.exe http://www.example.com/cron.php

3. To set a frequency more often than Daily (for example, hourly), click the Schedule tab, thenclick Advanced. Here you can set options such as Repeat task, every 1 hour for 23 hours.Click Ok when finished.

4. Change the start time on the task to one minute from the current time. This will allowyou to test the task and make sure that it is working.

5. When all settings have been configured to your liking, click Apply and OK (note: you maybe prompted for your password)

Command-line version

Another way to perform the above commands is by using the schtasks (or at in Windows 2000)command from the command line. To duplicate the example above, which runs Firefox hourly toexecute http://www.example.com/cron.php, open a command prompt (Start > Programs >Accessories > Command Prompt) and enter:

Page 23: Drupal - Installation Guide

schtasks /create /tn "Drupal Cron Job" /tr "C:\PROGRA~1\MOZILL~1\firefox.exehttp://www.example.com/cron.php" /sc hourly

Enter your password if prompted.

Using wget for Windows to run cron

If for whatever reason you'd rather not deal with a browser window popping up on the machine,you can use wget, the Windows port of which works more or less the same as it does in UNIX.curl and lynx also have windows ports but wget is probably the easiest to set up and use.

Grab a copy of wget from your choice of either the author's site or from SourceForge. Install it tothe location of your choice.

Follow the steps for Creating A Scheduled Task above, except select wget.exe as the program torun (you may need to click the Browse button to locate it if you installed from a .zip file, forexample). When you get to the Advanced Properties dialog, paste in the following after theprogram path:

-O - -q -t 1 http://www.example.com/cron.php

Adjust the rest of the options as described above and test it.

Configuring cron jobs on ixWebHostingLogin to the control panel at https://manage.ixwebhosting.com/index.php

Click on "Manage" following this path: My Products >> Hosting Products >> Manage

This will take you to H-Sphere page. Click on "FTP Manager" under FTP.

You'll see one of the parameters as Crontab. The Value will be set to Off by default. Click on theOff button.(Note: If it's been set to On, click on Edit button)

This will take you to list of cron jobs(should be empty at first).Fill in the Mail-To field with an email address where you want cron run success/failure messagessent.The other fields are:TT- Opens up a help popup.Minute - Set to "0" to run at every time the clock strikes 0th minute.Hour - Set to "*" to run every hour or say for example "8" to run at 8am in the morning.Day of month - Set to "*" to run every day in the month.Month - Set to "*" to run every month.Day of week - Set to "*" to run every day of week.Command - This is the only tricky part. Copy paste command below replacing "example.com"with the actual site name.

/usr/bin/curl -o /dev/null http://example.com/cron.php

Delete - Can be checked to delete previously stored cron jobs.(will otherwise state "New")

That should be it. Click on "Submit Query" to save cron job. You can add multiple ones by fillingin the last row which is always empty and cannot be deleted.

Hope this helps. If pictures help, I'll re-edit this post with some.

Configuring cron on Mac OS X Server 10.5.xand laterDrupal documentation refers to running cron jobs periodically. But OS X Server (at least LeopardServer) has a kernel bug that results in a log message from cron jobs to the effect “Could notsetup Mach task special port 9: (os/kern) no access”. Not a joyful message to come across, thoughit appears to be harmless.

In addition, OS X doesn’t come with wget, so the suggested cron call in the Drupal docs doesn’twork anyhow.

To avoid both of these problems, put a call to curl in a launchd daemon .plist file (e.g./Library/LaunchDaemons/drupal-cron-call.plist), thusly:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>Label</key> <string>com.{domain-name}.drupal-cron</string> <key>UserName</key> <string>nobody</string> <key>GroupName</key> <string>_www</string> <key>ProgramArguments</key> <array> <string>/usr/bin/curl</string>

Page 24: Drupal - Installation Guide

<string>-s</string> <string>http://localhost/{drupal-subdirectory/}cron.php</string> </array> <key>RunAtLoad</key> <true/> <key>StartCalendarInterval</key> <dict> <key>Minute</key> <integer>09</integer> </dict> </dict></plist>

Then launchctl load /Library/LaunchDaemons/drupal-cron-call.plist and enjoy.

Notes:

“http://localhost/{drupal-subdirectory/}cron.php” might be replaced with “http://{domain-name}/cron.php” for a production server.Be sure to replace {domain-name} and/or {drupal-subdirectory/} placeholders (in sample.plist file above) with appropriate values.For non-production environments, StartCalendarInterval, which always runs at nineminutes past the hour in this example, should perhaps be replaced with StartInterval, whichalways runs after a specified number of seconds have elapsed (since the last run). Forproduction environments, it’s nice to run cron by the clock, but development computersmay be asleep during arbitrary times and thus benefit from the elapsed-time approach. Tochange this, replace: <key>StartCalendarInterval</key> <dict> <key>Minute</key> <integer>09</integer> </dict>

with: <key>StartInterval</key> <integer>3600</integer>(This example runs every hour.)

Configuring cron on Rackspace Cloud SitesIn the Features tab of your domain, go to "Scheduled Tasks (Cron Jobs)". Then:

1. Click on "add new task"2. Enter a task name (such as "Drupal Cron")3. Enter an email address for output (results of each cron run will be emailed to this address)4. For Command Language, select "HTTP"5. For Command to Run, enter the url of the cron.php file (for example,http://www.example.com/cron.php)6. Select the interval to run the cron task (no more frequently than once every 5 minutes)7. Click on "Save Task"

That should do it.

Cronjobs without wget/lynx or curlSome of you might have trouble getting lynx or wget to work. This may be the case if "localhost"is not permitted.Then wget, lynx or curl won't work on the local machine. If you are not willing to depend onothers to perform cronjobs and you dislike poormans cron, try this script.touch ~/scripts/cron-php.shchmod 700 ~/scripts/cron-php.shvi ~/scripts/cron-php.sh

#!/bin/bash## Simple cron script for those who cannot# use wget, lynx or curl because the host# closed the localhost loop.## Usage:# - put this file in the ~/scripts dir# - add a cronjob pointing to this script## Copyright OCS - 2006# Copyright [email protected] - 2008# This script is provided under the GPL.## v 0.1 original release# V 0.2 added PHP parser options and verbosity# setting to keep it quiet so real errors can# be reported by cron.

############################## CONFIGURATION OPTIONS#############################

# Complete local path#

Page 25: Drupal - Installation Guide

# Set the complete local path# to where the cron.php file# is (ie the root path)# Default is /var/www/html/root_path=/var/www/html/

# Complete php path## Set the complete path# to the php parser if# different from standardparse=/usr/bin/php

# PHP parser options## Defaulting to not report notices.parse_options="-d error_reporting=2037"

# Verbosity## Default to only report errors.verbose=false

############################### END OF CONFIGURATION OPTIONS##############################

cd $root_path

if [ -e "cron.php" ]then $parse $parse_options cron.php if [ "$?" -ne "0" ] then echo "cron.php not parsed." else if $verbose then echo "cron.php has succesfully been parsed." fi fielse echo "cron.php not found." exitfi

exit

and then the crontab itself:crontab -e* * * * * ~/scripts/cron-php.sh

where ~ is the directory where your drupal install is (the script defaults to /var/www/html/ butyour professional hosting company will probably use /home/your.domain.tld/www

Another multi site cron without lynx/wget orcurlTry A multi-site cron script without lynx/wget/curl

Multisite cron without wget/lynx or curlI recently moved my sites to a new host, and they don't allow me to use either wget or curl fromcron. Since I'm running multiple sites, I also can't just run cron.php directly. However, I can usethe 'exec()' PHP call, so I came up with these two scripts:

runcron.php:#!/usr/local/bin/php

<?php$SITES = array( 'www.mainsite.com', 'www.subsite1.com', 'www.subsite2.com', ...);

$_SERVER['SCRIPT_NAME'] = '/cron.php';$_SERVER['SCRIPT_FILENAME'] = '/cron.php';foreach( $SITES as $site ) { exec( "./runsitecron.php ".$site );}?>

runsitecron.php:#!/usr/local/bin/php

<?php$_SERVER['SCRIPT_NAME'] = '/cron.php';$_SERVER['SCRIPT_FILENAME'] = '/cron.php';$_SERVER['HTTP_HOST'] = $_SERVER["argv"][1];include "cron.php";?>

Page 26: Drupal - Installation Guide

Then I just call 'runcron.php' from my crontab and it runs Drupal's 'cron.php' for each of my sites.

Using Perl to run cronIf you're having problems with cron using curl and wget is not allowed on your server try out thecurl call from the shell on another box - you may find you get HTML delivered saying "page notfound."

If this is the case you can also use Perl to perform the call to the cron script.

You need command line access to Perl and the LWP::Simple module installed. Your crontab entrythen becomes:

45 * * * * perl -MLWP::Simple -e "getprint 'http://yourdomainhere/cron.php'"

Multisite cronSites that make use of Drupal's multisite feature need to take extra steps to ensure that each sitegets it cron run, rather than just the default site. The following pages have ways that people haveaddressed this issue. Feel free to add your own solution as a child page.

Automatic multisite cron using php5Create a new file preferably in the same directory as your drupal dir. Name it 'cronall.php' orsomething. Copy the following script into it. Then adjust the settings in the file, and visit the scriptwith your webbrowser, to see if it is setup correctly.Then create a cronjob for the cronall.php script, and you're done.

<?php/*** This script scans the sites directory, and uses a regular expression toextract the sitenames.* It then uses this sitename to execute the cronjob for these sites.* You then only have to create a cronjob for this script.* In this way, you can create and delete sites on the fly, but all theircronjobs will be executed.*/

/************ SETTINGS**********///the location of the 'sites' directory relative to this script.$sitesDir = '../drupal/sites';/*** A regular expression that matches the name of the directories in* the 'sites' dir that you want to execute cronjobs for, with a * backreference around the actual site name. (so we can exclude the* domain part)* * If you don't know regular expressions you might want to brush up* on them: <a href="http://www.regular-expressions.info/tutorial.html" title="http://www.regular-expressions.info/tutorial.html" rel="nofollow">http://www.regular-expressions.info/tutorial.html</a> * * Alternatively, you can just copy the name of one of the directories* in the site dir, put a backslash \ in front of all dots . and replace* the actual name of the site with ([a-zA-Z0-9_-])*/$siteNameRegExp = 'www\.example\.com\.([a-zA-Z0-9_-])';//the url of the cron script, you should insert %s where the sitename should beinserted later.$cronUrl = 'http://www.example.com/%s/cron.php';//any other sites that you want to execute cronjobs for. Just comment this ifyou haven't got any.$addedSites = array('drupal');/************ END SETTINGS**********/

error_reporting(E_ALL);$sites = array();

$handle = opendir($sitesDir);while ($file = readdir($handle)) { if(ereg($siteNameRegExp, $file)){ $sites[] = ereg_replace($siteNameRegExp, '\\1', $file); }}//default siteif(isset($addedSites) && is_array($addedSites)){ $sites = array_merge($sites, $addedSites);}foreach($sites as $site){ $cmd = 'wget --spider '.sprintf($cronUrl, $site); echo 'Executing command: '.$cmd.'<br>'; exec($cmd);}

?>

Page 27: Drupal - Installation Guide

Cron script for multi source, multi site setupI've just hacked up this little script as I have multiple installations of drupal each with multiplesites that get more each day. This should figure out which sites cron should run for.

#!/bin/bash

SITESROOT=/var/www/sitesMYIPRANGE=41.204.221

# get the base installscd $SITESROOTfor drupaldir in $(find . -maxdepth 2 -name INSTALL.mysql.txt | awk -F/ '{print$2}')do cd $SITESROOT/$drupaldir/sites for site in $(find -L . -maxdepth 1 -type d -iregex "./[a-z].*\.[a-z].*" |awk -F/ '{print $2}') do IP=$(dig $site | sed '/AUTHORITY SECTION/,$d' | grep -v "^;" | grep "IN[[:space:]]*A" | sed 's/.*A\W*//' ) if echo $IP | grep -q $MYIPRANGE then #echo "Doing cron for $site" wget -O - -q http://$site/cron.php else a=1 #echo "Skipping cron for $site" fi donedone

Multi-site Cron Bash ScriptA quick bash script to run cron for multiple sites:

#!/bin/bash

## Define your websites in an arraysites=(example.com example2.com example3.com)

len=${#sites[*]}for((i=0; i<$len; i++)); do wget -q http://${sites[${i}]}/cron.php # You may remove (or comment) the following line if you # wish to retain the downloaded file. rm cron.phpdone

Multisite cron without wget/curl#!/usr/bin/php5<?php/*** This script scans the sites directory, and uses a regular expression toextract the sitenames.* It then uses this sitename to execute the cronjob for these sites.* You then only have to create one cronjob for this script.* In this way, you can create and delete sites on the fly, but all theircronjobs will be executed.*//** Carl van Denzen, june 2009:* Options for this script:* -h <hostname> (p.e. arjan.vandenzen.nl)* -r <regexp> (p.e. .+\.vandenzen\.nl) This will be used in most cases.* -a** When this script is invoked with parameter -r, then it will call* itself for every host in the sites directory that matches the -r regexp.* These calls will be with the -h <hostname> argument set to the site name.** When invoked with -h option (only ONE is allowed), it will run cron* for the named hostname site.** When this script is invoked without parameters, it will die. This is to avoid* runaway scripts.** Purpose of this behaviour:** You can add this script to your crontab with parameter -a: it will run* for every site found in the drupal sites directory. This is the regular* drupal/cron.php behaviour.* In a one-site set-up it will only run for the default directory.* In a multi-site set-up it will run for all sites (beware of the defaultdirectory?)** You can add this script to your crontab with the -r parameter and it will onlyrun cron* for the sites that match the <regexp>. This is primarily meant for a multi-site set-up* when the sites directory contains sites that you want to exclude from running

Page 28: Drupal - Installation Guide

cron* (p.e. the "default" site).** You can add this script to your crontab with the -h option to run cron* for only the specified site (only one allowed).** Without parameters it will do nothing.* I have seen some problems with argument parsing that made me* afraid of doing things like calling the same script. I would have preferred* that this script would cron all sites if it was invoked without parameters.** This script calls itself for every site (in a new command shell).* It is impossible to do this in a* php function (i.e. without invoking a new process) because the drupal* bootstrap coding cannot (easily) be called multiple times.** Disadvantages of this script:* pearl5 is needed for Console/Getopt.php* It is not efficient because for every host a new php process is* created.** Advantage:* For me it works.* It is only one script (I saw other solutions that used two scripts* to accomplish this task).* It doesn't use wget or similar programs that try to start cron* by making a connection to the cron.php file. This strategy didn't* work for me, because my website hoster doesn't allow outgoing* connections.*/

/************ SETTINGS**********///the location of the 'sites' directory relative to this script.$sitesDir = 'sites';/*** A regular expression that matches the name of the directories in* the 'sites' dir that you want to execute cronjobs for, with a* backreference around the actual site name. (so we can exclude the* domain part)**/$siteNameRegExp = '(.*\.example\.com)';$debug=0;/************ END SETTINGS**********/

/** Do default action like old cron.php (i.e. before* the year 2008) script in Drupal 6.x*/function do_old_cron() { drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); drupal_cron_run(); }/** some sanity checks*/if (!isset($_SERVER['argv'])) { // print('server argv not set<br/>'); do_old_cron();}

error_reporting(E_ALL);

include ("Console/Getopt.php");

// initialize object$cg = new Console_Getopt();

/* define list of allowed options - p = a:all sites, h:one site, r:sites thatmatch regular expression */$allowedShortOptions = "ah:r:";

// read the command line$args = $cg->readPHPArgv();

// get the options$ret = $cg->getopt($args, $allowedShortOptions);

// check for errors and die with an error message if there was a problemif (PEAR::isError($ret)) { die ("Error in command line: " . $ret->getMessage() . "\n");}

ini_set('include_path',ini_get('include_path'). PATH_SEPARATOR . './scripts');

/* This doesn't work in every case: getopt function is not always available$options = getopt("h:r:");var_dump($options);*/

include_once './includes/bootstrap.inc';

function cron_one_site($sitename) { $_SERVER['SCRIPT_NAME'] = '/cron.php'; $_SERVER['SCRIPT_FILENAME'] = '/cron.php';

Page 29: Drupal - Installation Guide

$_SERVER['HTTP_HOST'] = $sitename; $_SERVER['REMOTE_ADDR'] = 'localhost'; $_SERVER['REQUEST_METHOD'] = 'GET';

drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); echo "Hostname is: $hostname<br/>\n"; print 'conf_path is '.conf_path() . '<br/>'; drupal_cron_run();}/** Call this script for every site in regexp (call* it with -h option for every site).*/function cron_regexp($siteNameRegExp) { global $sitesDir; global $debug; $sites = array(); // Get the name of this script, so we can call it recursively // doesn't work: argv is not defined: $thisScript=$argv[0]; $argv=$_SERVER["argv"]; $thisScript=$argv[0];

$handle = opendir($sitesDir); while ($file = readdir($handle)) { if ($debug>0) { if (file_exists("$sitesDir/$file/settings.php")) { print('Yes: '); } else { print("No: "); } print("exists $sitesDir/$file/settings.php<br/>"); } if (($file!='all') && (file_exists("$sitesDir/$file/settings.php"))) { // preg expects the pattern to be enclosed in a (freely chosen) // delimiter. I have chosen ^ because I think that will never // be used in a host name if(preg_match('^'.$siteNameRegExp.'^', $file)){ if ($debug>0) { print '$file is '.$file.', $siteNameRegExp is'.$siteNameRegExp.'<br/>\n'; } $sites[] = $file; } } } foreach($sites as $site){

if ($debug>0) { print 'Doing site '.$site.'<br/>\n'; } $commandline='/usr/bin/php5 '.$thisScript.' -h '.$site; exec($commandline,$out1,$out2); if ($debug>0) { print 'Commandline is '.$commandline.'<br/>\n'; print 'out1 is '.implode('\n',$out1).'<br/>\n'; print 'out2 is '.implode('\n',$out2).'<br/>\n'; } }}// display the options//print_r($ret);if ($debug>0) { print_r($_SERVER);}// parse the options array$opts = $ret[0];if (sizeof($opts) > 0) { // if at least one option is present foreach ($opts as $opt) { switch ($opt[0]) { // handle the all sites option case 'a': $re='.*'; cron_regexp($re); break; // handle the hostname case 'h': $hostname = $opt[1]; cron_one_site($hostname); break; /* handle the regexp option. */ case 'r': $re = $opt[1]; // regular expression cron_regexp($re); break; default: print 'Usage: <br/>\n'; print '- h hostname<br/>\n'; print '- r regexp<br/>\n'; print '- a (do all sites)<br/>\n'; break;

} }}

/** Some experienced I had with this script at your-webhost.nl in june 2009* // $_SERVER["PHP_SELF"] is not set*/

Page 30: Drupal - Installation Guide

?>

Multisite with cron-curl.shI have domain1.com hosted as the primary domain with domain2.com "parked" at domain1.com.My public_html/sites folder looks like this:

sites/allsites/defaultsites/domain2

My webhost (an Apache server running Cpanel 11) blocks user access to lynx or wget, so thenormal recommendations for setting up a crontab were not working for me. However, I discovereda suggestion in http://drupal.org/cron to try the cron-curl.sh script that ships with Drupal in the"scripts" folder. I edited cron-curl.sh so that it includes the following line:

curl --silent --compressed http://domain1.com/cron.php

And then I set up a crontab that looks like this:

*/2 * * * * /home/webhostaccountname/public_html/scripts/cron-curl.sh

After remembering to set the file permissions on cron-curl.sh so that it could be executed, the cronjob worked perfectly. The "*/2" executes the crontab every other minute for testing purposes only.

So, then I went back into cron-curl.sh and added the following line:

curl --silent --compressed http://domain2.com/cron.php

Again, success! I'm watching the logs for both domain1.com and domain2.com. Cron jobs arebeing executed every 2 minutes for both domains.

Run cron.php with python.I was unable to run cron.php from the cpanel cron on a multisite because I had no access to curl,lynx and wget. I knew I had python installed in the shared server so what I did was to create apython script in my home folder called wget.py

import sys, urllibdef reporthook(*a): print afor url in sys.argv[1:]: i = url.rfind('/') file = url[i+1:] print url, "->", file urllib.urlopen(url)

Then, in the cron configuration, just add the command:

/path/to/python /path/to/wget.py url1/cron.php url2/cron.php url3/cron.php

Attachment Size

wget.py_.txt 218 bytes

Simple wget multisite cron, lazy methodI just wrote this script for running the crons on all my drupal sites before I discovered this sectionin the documentation. This works well for me because I'm lazy and I don't have to maintain a listof my drupal sites somewhere for it to run all my crons. The script simply reads the domains frommy sites folder. It works well for me, but I think it might not work for every situation, ymmv.

Create an executable called drupalcron:

#!/bin/bash

#change the following line to match your sites foldercd /var/www/drupal/htdocs/sites

#the next line gets only directories, not symlinks (and not the 'all' nor'default' directories)for f in `ls -Fd *.*|grep '/$'`#remove the 'echo' from the following line after making sure it looks rightdo echo wget -O - -q -t 1 http://${f}cron.phpdone

Please note, the script will only echo the command and not actually do anything. This is so thatyou can check to see if it looks right first. Please read the comments in the script. If the output iswhat you expect, then delete the word echo from the do line and then it will execute the wgetcommands next time.

Then simply add that to your crontab however you wish:

10 * * * * /path/to/drupalcron > /dev/null 2>&1

Page 31: Drupal - Installation Guide

Running cron manuallyTo run a cron job manually, simply visit your own site's url at http://example.com/cron.php withyour web browser, and cron will run and complete in the background. You'll be left with a blankwhite page, which is normal. Use the browser's back button to return to the previous page andcontinue where you left off. It doesn't matter how long you wait while you're seeing the blankwhite page, and returning to the previous page at any time won't stop the cron process fromrunning.

Core provides a convenience link for running cron manually too. Look at the Status page's link:/admin/logs/status/run-cron?destination=admin%2Flogs%2Fstatus. You can paste that into yourown site's address bar any time you want to run a cron.

In addition, if you have the update_status.module installed, and you should since it's simplyglorious, you'll be presented with a custom link on your admin/logs/updates page.

For Drupal 6.x, see in your site: Administer > Reports > Status report > Cron maintenance tasks> Run cron manually.

Setting up cron on Hostmonster through thecPanel interface

1. Logging into the cPanel interface for your hostmonster account, scroll to the bottom andlook in the "Advanced" section

2. Select "Cron Jobs." It is represented with a calendar icon3. Select "Standard"

Do not use an email address or you will be hit with a notification every time the cronjob runs

4. Enter the following command: php /home/+++Your hostmonster loginusername+++/public_html/cron.php

This is only for your main domain, subdomains are in different folders5. Select the number of times that you would like the cron job to run6. See if it works -you can check whether or not a Cron Job has been run in the Logs menu in

Drupal

Solving cron problemsVarious things can keep cron from doing its job on your Drupal site. If your Status report(admin/reports/status) indicates that cron hasn't run recently, try the following to diagnose andfix the problem:

Make sure cron.php is being called at allIf your Status report indicates that cron has never run, you may simply need to configure configurea cron job. If you can successfully run cron manually from your Status report screen, Adminmenu, or Drush, this is almost certainly the case. If manually running cron fails, you have a deeperproblem...

Check for problems with cron itselfIf cron hangs, redirects, returns a 404 error, or just plain fails when run manually, you have aproblem with cron itself.

Cron may be cached badly. Clear your site caches from admin/settings/performance,Admin menu, or Drush, or truncate (empty) all database tables with names beginning withcache_. You could also search for cached instances of cron.Cron may have been interrupted during execution, such as by a server restart. This can resultin watchdog (error) messages like "Attempting to re-run cron while it is already running"and "Cron has been running for more than an hour and is most likely stuck". Try resettingthe semaphore and deleting the "last run" timestamp from the database. (Note: deleting the"last run" timestamp will cause your Status report to indicate that cron has never run.) Youcan do so with this SQL...

USE Name_Of_Your_Drupal_Database;DELETE FROM variable WHERE name="cron_semaphore";DELETE FROM variable WHERE name="cron_last";

...or with this PHP in a custom module or script:

<?phpvariable_del('cron_semaphore');variable_del('cron_last');?>

Cron may be taking too long to complete, resulting in WSOD or in watchdog (error)messages like "Cron run exceeded the time limit and was aborted". This is especiallycommon on sites that have been online for some time where database tables cron isattempting to clean up have become unmanageably large. Check the size of the watchdog,sessions, and accesslog tables and truncate (empty) them if necessary.

Page 32: Drupal - Installation Guide

, and tables and truncate (empty) them if necessary.A cron process with too much to do may also easily run out of memory, resulting in PHPerror messages like "PHP Fatal error: Allowed memory size of X bytes exhausted (tried toallocate Y bytes) in file on line x". Try increasing PHP's memory limit.

Check for problems with modules

Certain modules may cause cron to abort, redirect, or return a 404 error. To find an offendingmodule, first find out which ones implement hook_cron. Print a list using this code:

<?phpecho theme('item_list', module_implements('cron'));?>

Disable the modules, one by one, running cron after each one. (At least) the last module youdisabled before it starts working again was causing a problem.

Core search module is frequently the source of problems because of errors in nodes it's trying toindex. Cron may choke on following things in your content:

Invalid PHP codeNon-ASCII charactersdrupal_goto (See #102138: cron breaks on drupal_goto.)

If you know cron is failing during search indexing and you suspect bad content to be to blame, youcan use the following SQL to see which nodes haven't been indexed yet—chances are it's chokingon one of them.

SELECT *FROM node nLEFT JOIN search_dataset d ON d.type = 'node' AND d.sid = n.nidWHERE n.status = 1 AND n.type IN ('blog', 'page') AND (d.sid IS NULL OR d.reindex > 0)

The files directoryIn most cases, Drupal would create the files directory for you. If Drupal can't create thedirectory, follow the instructions below.

After installing Drupal, it is helpful to have a writable directory so that you can upload your owncontent files. If you skip this step, you may get an error message stating that "sites/default/filesdoes not exist ..."

Here’s how:

1. Make a directory called 'files' in the sites/default folder.2. Assign write permissions to it with the following command (from the installation directory):

chmod -R a+wrx sites/default/files

or

chmod -R 777 sites/default/files

Also, most FTP programs allow you to create the files directory and set its permissions. Be sure togive read, write, and execute permissions to everyone (777). FYI: chmod a+rwx is equivalent tochmod 777

Troubleshoot installation problemsLinks to some of the more common installation issues are listed below. More troubleshootinginformation is available at the Troubleshooting FAQ.

Fatal error: Allowed memory size of n bytes exhausted

The error "Allowed memory size exhausted" indicates that Drupal needs more memory than hasbeen allocated under current settings. This error can be resolved by adding an extra line toDrupal's configuration files.

Failed to connect to your MySQL database server

The installation script cannot connect to the database. Check if the username, password andhostname that you provided are correct.

Cannot create directories 'files' or 'private'

The installation script needs permissions to create these directories inside the sites/default folder.

Cannot write to configuration files settings.php

Page 33: Drupal - Installation Guide

The installation script needs permissions to write to the configuration files settings.php.

Blank page (White Screen of Death)

Occasionally the page is completely blank (No content. No errors.) This is what is sometimesreferred to as the "White Screen of Death". There are several reasons why this might occur

"Your PHP configuration only supports the SQLite database type" on thedatabase configuration page during install

Drupal 7 now requires PHP to have the PDO (Php Data Object) extension enabled or compiled in.Older or home-brewed versions of PHP may not have this enabled by default. Check your phpinfofor the "pdo_mysql" extension, or see the instructions for enabling it. Discussion

Other errorsHost-specific error messagesRegister globals should be disabledWhat permissions does Drupal need?Why is this uploading stuff so difficultAll my pages are blankWhite screen of death fixing step by stepClient does not support authentication protocol500 internal server errorGot a packet bigger than 'max-allowed-packet'Lock tables sequences write errorError on installation step 3Database setup fails to proceedTranslation issuesClean URLs how-to

Advanced and multisite installationThe following pages cover some special installation cases, such as running several Drupal sitesfrom a single code base (also known as multi-site installations) and specifying a database tableprefix.

Modify the file system pathThe files directory created in the initial install is the default file system path used to store alluploaded files, as well as some temporary files created by Drupal. After installation, the settingsfor the file system path may be modified to store uploaded files in a different location.

It is not necessary to modify this path, but you may wish to change it if:

your site runs multiple Drupal installations from a single codebase (modify the file systempath of each installation to a different directory so that uploads do not overlap betweeninstallations); or,your site runs a number of web server front-ends behind a load balancer or reverse proxy(modify the file system path on each server to point to a shared file repository).

To modify the file system path:

1. Ensure that the new location for the path exists or create it if necessary. To create a newdirectory named uploads, for example, use the following command from a shell or systemprompt (while in the installation directory):mkdir uploads

2. Ensure that the new location for the path is writable by the web server process. To grantwrite permissions for a directory named uploads, you may need to use the followingcommand from a shell or system prompt (while in the installation directory):chmod o+w uploads

3. Access the file system path settings in Drupal by selecting these menu items from theNavigation menu:Administer > Site configuration > File system

4. Enter the path to the new location (e.g.: uploads) at the File System Path prompt.

NoteChanging the file system path after files have been uploaded may cause unexpected problems onan existing site. If you modify the file system path on an existing site, remember to copy all filesfrom the original location to the new location.

Some administrators suggest making the documentation files, especially CHANGELOG.txt, non-readable so that the exact version of Drupal you are running is slightly more difficult to determine.If you wish to implement this optional security measure, use the following command from a shellor system prompt (while in the installation directory):chmod a-r CHANGELOG.txt

Note that the example only affects CHANGELOG.txt. To completely hide all documentation filesfrom public view, repeat this command for each of the Drupal documentation files in theinstallation directory, substituting the name of each file for CHANGELOG.txt in the example.

Page 34: Drupal - Installation Guide

Run multiple sites from the same code base(multi-site)If you are running more than one Drupal site, you can simplify management and upgrading of yoursites by using the multi-site feature. Multi-site allows you to share a single Drupal installation(including core code, contributed modules, and themes) among several sites.

This is particularly useful for managing the code since each upgrade only needs to be done once.Each site will have its own database and its own configuration settings, so each site will have itsown content, settings, enabled modules, and enabled theme. However, the sites are sharing a codebase and web document root, so there may be security concerns (see section below for moreinformation).

Overview of the ProcessTo create a new site using a shared Drupal code base you must complete the following steps:

1. Create a new database for the site.2. Create a new subdirectory of the 'sites' directory with the name of your new site (see below

for information on how to name the subdirectory).3. Copy the file sites/default/default.settings.php into the subdirectory you created in

the previous step. Rename the new file to settings.php.4. Adjust the permissions of the new site directory, and grant write permissions on the

configuration file5. Make symbolic links if you are using a subdirectory such as example.com/subdir and not a

subdomain such as subd.example.com (see the subdirectory multi-site section below fordetails).

6. In a Web browser, navigate to the URL of the new site and continue with the standardDrupal installation procedure.

It may also be necessary to modify your Web server's configuration file (often named httpd.conffor Apache) to allow Drupal to override Apache's settings. This is true for all installations ofDrupal and is not specific to the multi-site install. Additional information is available in the BestPractices: Configuring Apache and PHP for Drupal in a Shared Environment section of the InstallGuide.

Details of the Process

Domains, URLs, and sites subdirectory name

The new subdirectory of the sites directory has a name that is constructed from the site's URL. Forexample, the configuration for www.example.com would be insites/example.com/settings.php. You do not need to include 'www' as part of the directoryname.

Drupal will use the same sites/example.com directory for any subdomain of example.com,including www, unless there is an alternative, matching subdomain sites subdirectory. Forinstance, URL http://sub.example.com would be served from sites/sub.example.com, if itexists.

For a subdirectory URL, such as http://example.com/subdir, name the sites subdirectory asfollows: sites/example.com.subdir -- and read the section below on getting subdirectory multi-site working.

If you are installing on a non-standard port, the port number is treated as the first part of thesubdomain. For example, http://www.example.com:8080 could be loaded fromsites/8080.example.com. If that directory doesn't exist, Drupal would then look forsites/example.com, just like a real subdomain.

Site-specific modules and themes

Each site configuration can have its own site-specific modules and themes in addition to thoseinstalled in the standard 'modules' and 'themes' directories. To use site-specific modules or themes,simply create a 'modules' or 'themes' directory within the site configuration directory. For example,if sub.example.com has a custom theme and a custom module that should not be accessible toother sites, the setup would look like this:

sites/sub.example.com/settings.php sites/sub.example.com/themes/custom_theme sites/sub.example.com/modules/custom_module

Document root

One area of frequent confusion is that in a Drupal multisite installation the webserver documentroot is the same for all sites. For example with the following three sites: example.com,sub.example.com and example.com/site3 there will be a single Drupal directory and all sites willbe calling the same index.php file.

Some webhosts automatically create a new directory (i.e. example.com) when creating a newdomain or subdomain. In this case it is necessary to make it into a symbolic link to the main

Page 35: Drupal - Installation Guide

Drupal directory, or better yet when creating the domain or subdomain, set it to use the samedocument root as the site where you have Drupal installed.

Subdirectory multi-site

If you are attempting to get Drupal multi-site working using subdirectory URLs rather thansubdomain or different domain URLs, you may encounter problems. You'll start out by making adirectory such as sites/example.com.subdir, and putting a settings.php file there. If this worksfor you, great! But it probably will not, until you make a symbolic link that tells your web serverthat the document root for http://example.com/subdir is the same as the document root forhttp://example.com. To do this, go to the example.com document root and type:

ln -s . subdir

(substituting the actual name of the subdirectory you want to make work).

If your codebase itself is in a subdirectory, then link your new site to the directory:

ls -s drupaldir subdir

This symbolic link is enough to resolve issues with subdirectory multi-site installations on at leastsome web hosts. But if you still encounter problems, such as issues getting clean URLs to work(especially if you had to edit the .htaccess file to get clean URLs working on the mainexample.com domain site), you may find this forum suggestion useful:http://drupal.org/node/239583#comment-786932

Note that these problems do not usually occur for multi-site installations using a subdomain, soyou might want to try that if you cannot get subdirectory multi-site to work. (However,subdomains are not good for search engine rankings!)

Localhost alias for local workstation

On many systems it is possible to create entries in a "hosts" file to create aliases for the localhostname for a local workstation. By creating aliases for localhost it is possible to create names suchas localdev1.example.com and localdev2.example.com, both for the local computer.

If on the other hand you use subdirectories in your local web root, create a symbolic link like this:

ls -s drupaldir subdir

and name your site folder localhost.subdir.

Domain name changes

Once a site is in production in a particular subdirectory under the sites directory, the subdirectoryshould not be renamed, even if the Web site URL changes. This is because several database tables(for example: system and files) include references to "sites/www.mydomain.com." Instead ofrenaming the sites directory, you can create a symlink to the new URL from the old one. Navigateto the sites directory and then use the following command:$ ln -s /path/to/drupal/sites/old.domainname.com new.domainname.com

Security ConcernsYou might want to reconsider using Drupal's multi-site configuration, in situations where theadministrators for all of the sites being run from the same code base are not either the same personor a small group with a high level of mutual trust. The reason is that anyone with fulladministrative privileges on a Drupal site can execute arbitrary PHP code on that site throughvarious means (even without FTP access to the site), and that arbitrary PHP code could be usedfrom one site to affect another site, if the two sites are in the same HTTP document root andsharing the same Drupal code.

So, unless you completely trust all of the administrators of the sites you are considering runningfrom the same Drupal code base to be knowledgeable, careful, and not malicious, you might wantto consider installing their Drupal sites in completely separate areas of the web server that are notable to affect each other via PHP scripting.

Comprehensive Multi-site VideoRunning a successful multi-site install requires knowledge of how Drupal handles multiple sitesand how various features of Apache can be leveraged to make the multi-site much easier tomanage.

The video at this link provides a great deal of detail and comprehensive conf files for an Apachemulti-site install of Drupal

Video about Multisites vs. Multiple Sites at GotDrupal.com

Domain AccessThe Domain Access project is a group of lightweight modules that provide tools for running agroup of affiliated sites from one Drupal installation and a single shared database. The module

Page 36: Drupal - Installation Guide

allows you to share users, content, and configurations across a group of sites such as:

- example.com- one.example.com- two.example.com- my.example.com- thisexample.com <-- can use any domain string- example.com:3000 <-- treats non-standard ports as unique

By default, these sites share all tables in your Drupal installation. The Domain Prefix moduleallows for selective, dynamic table prefixing for advanced users.

The module uses Drupal's Node Access system to determine what content is available on each sitein the network. Unlike other multi-domain modules for Drupal, the Domain Access moduledetermines user access based on the active domain that the user is viewing, rather than whichgroup or site the user belongs to.

Installation and configurationMake sure to install and configure your Drupal site before installing Domain Access. You onlyneed one settings.php file.For detailed instructions, see INSTALL.txt in the module directory.

To install the module, simply untar the download and put it in your site's modules directory andenable the module normally.When you enable the module, it will create a {domain} table in your Drupal database. All existingnodes on your site will be assigned to the default domain for your web site and to all affiliates. Asof 6.x.2.0, the primary domain is created for you in domain table on installation, previous versionsstore the primary domain in variables table.

How to add a patch that will synchronize filepaths between dev and prod/live sitesIf you have built your Drupal site on a development machine using multi-site configuration,you've discovered that there's a headache that will occur once you've ported your site to its livebox. If you are about to do this, then you'll soon see the problem.

The problem lays within the site/files directory. Once you've uploaded your development site to itslive server, you'll discover that you have to go into your tables and change the paths for imagesand other files. On your development box, you named, just for the sake of example, your site:drupal/sites/mygreatwebsite.com And in both of these directories, you've added a files directory.

To the world, that site will be: thegreatestwebsite.com and its file structure isdrupal/sites/thegreatestwebsite.com Once you went live, you'll see that the paths to your images,pdf and other files looks something like this:http://thegreatestwebsite.com/sites/thegreatestwebsite.com/files/myimage...

On one hand, you gulp at the length of that url. Next, you sigh because you realize that you have tochange the path -- in the database.

Drupal 7 has a fix for this -- not the length (that's another story) but for the path problem.

And, while it won't be committed to Drupal 6, there is a patch that you can add to Drupal 6 -- ifyou don't mind doing that no-no: patching core.

You'll find the patch here: http://drupal.org/user/216078 It's called: multisite-d6-2.patch

Here are the steps I used to install this on a WinXP machine. To do patching, I use cygwin patchutility. Please change words that are italicized to domains/paths applicable to your site.

1. Place patch in apache2/triad/htdocsfolder2. In command screen go to apache2triad/htdocs/drupal folder3. Run the patch: patch -p0 < ../thepatch.patch 4. Make sure there is a files directory located as follows:apache2triad/htdocs/drupal/sites/water/files5. Production and development sites should BOTH contain: sites/water/files 6. Files system path on both local development box and production site ---- sites/water/files7. Create a file named "sites.php" and put it into: drupal/sites/ Content of file:

<?php $sites = array( 'water.uida.local' => 'water', 'water.uida.edu' => 'water', ); ?>

Note that this file can also be created by copying the default.sites.php file created when the patchwas installed. Copy it and rename it to sites.php Open the file and remove the hash marks (#) thatare located in front of the array at the bottom of the file. Replace the variables in the array withyour configuration.8. Clear caches. Run update.php if you are updating an already created site.

Page 37: Drupal - Installation Guide

9. Add a "hacks.txt" file to your site, perhaps, to make sure others know about this core changeand how it affects updates.

If you are doing this on an established site, you'll need to modify the path for your images/files asthey'll be pointing to the old directory under sites.

Multi-site on LinuxSoftware installed:

Drupal 6Apache 1.3Red Hat 6.1 (Although other distributions will work)PHP5PostgreSQL 7.4

The process:

1. Install the Drupal core download from Drupal.org.2. Install default Drupal site. I created mine with a "dummyUSER" user and "dummyDB"

database with Drupal code in apache/htdocs/drupal3. Once you have this working then create a new dir "example1.com" directly under "sites" dir.

mkdir sites/example1.com

cp -R sites/default/* sites/example1.com/

4. Create a new database "example1DB" and new user "example1USER" in database.5. Edit the sites/example1.com/settings.php and change the following:

$db_url = 'pgsql://dummyUSER:dummyPSSWDl@localhost/dummyDB';

to $db_url ='pgsql://example1USER:example1PSSWDl@localhost/example1DB';

(this step is optional, normally Drupal will recognise the base url automatically):# $base_url = 'http://www.example.com';

to $base_url = 'http://www.example1.com'; (Remove the '#' [comment])6. cp apache/htdocs/drupal/install.php to

apache/htdocs/drupal/sites/example1.com/

7. Point your browser to www.example1.com. Drupal will show you lot of errors.8. Once it shows you errors you are all good. Just point your browser to

www.example1.com/install.php and it will present you the installation screen. Install fromthere on.

9. Repeat the above process for www.example2.com

NoteIf it says the site is offline then your database information in settings.php is not correct. If it sayssite not found then your base url in settings.php is not correct.

Multi-site on MacTo get multi-sites working on apache on a Mac, see "HowTo: Configure your local workstation toserve multiple sites using Drupal's multisite configurations and Apache's VirtualHost".

Multi-site on WindowsSoftware

This guide assumes you have installed WAMPServer, which you can download below:

WampServer - includes Apache, PHP, and MySQL.

Alternatively, you can install another WAMP package, but you will need to adjust the paths as necessary.

Process

1. Set up Drupal as usual1. Install WampServer (or another 'WAMP' package) and make sure that Apache and

MySQL services are running.2. open phpMyAdmin in your browser localhost/phpmyadmin (or it can be launched via

the WampServer icon in your system tray.)3. Create a new database -- we'll call it drupal6 because this will be our base installation

which we will leave untouched. While you're here create a second and third database,which we'll call site1 and site2. You can also change the database privileges if youwant, but to keep things simple here, we'll stick with the default user root and nopassword.

4. Download Drupal 6 into WampServer's wamp/www folder (or the htdocs folder inXampp and some other packages). (You'll need a tool like 7-zip to unpack the Drupaltar.gz file).

5. Do your first Drupal installation by pointing your browser to your Drupal folder,which should be something like http://localhost/drupal-6.x. Enter the drupal6 databaseand user settings (root and no password in this example). Complete the installation,but then leave it alone.

2. Prepare the files for your new multi-sites

Page 38: Drupal - Installation Guide

2. Prepare the files for your new multi-sites1. Find Drupal's sites folder, make a copy of the default folder and rename it to the URL

you want for your first test site. To keep it simple, we'll make it the same as the firsttest site database: site1. While you're here, create files, tmp and themes sub-folderswithin this new folder. The themes sub-folder will be used for any custom theme youcreate specifically for this site. Similarly, you can create a modules sub-folder for anymodule you use only with this site. However, generally, I find it easier to keep allcontributed modules together in the sites/all/modules folder so I can use them with allmy test sites.

2. Use a text editor to open the settings.php file in your new site1 folder and change$db_url line to reflect your first test site database, and the database user name andpassword, eg:mysql://username:password@localhost/site1Also, change the $base_url to the above site URL, eg:$base_url = 'http://site1'; // NO trailing slash!

3. Repeat the above 2 steps for the other test site (site2)3. Adjust windows so it can find the new site at a new made-up name

Find the Windows hosts file, which should be in Windows' System32/drivers/etc folder,make a backup of that file and then open the hosts file in a text editor. Here, add new linesmapping your localhost IP address to match the URLs of your test sites and your originalDrupal site. In our example, it would look like this:

127.0.0.1 localhost127.0.0.1 site1127.0.0.1 site2127.0.0.1 drupal6

This is telling Windows Networking that http://site1/ is a name for this machine.4. Adjust Apache so it responds to requests for the new names

1. Find the Apache httpd.conf file which, in WampServer, should be in thewamp/bin/ApacheX.X/conf folder (where X.X is the Apache version number). Sorry, Ican't remember where Xampp installs this, but it will be in the Apache folder.Anyway, all you need to do with this file is make sure the "Virtual hosts" line is activeby removing the # before Include conf/extra/httpd-vhosts.conf.

2. Make a backup of that httpd-vhosts.conf file (which is in Apache's conf/extra folder),then open httpd-vhosts.conf with a text editor and add these lines:<VirtualHost *:80>DocumentRoot C:/wamp/www/drupal-6.xServerName site1</VirtualHost>

where C:/wamp/www/drupal-6.x is the path to the Drupal installation folder and site1is the URL for your first test site. Add another entry for your other test site, anotherentry for your original Drupal installation and another entry for WampServer'slocalhost URL (if you want to keep this active), eg:<VirtualHost *:80>DocumentRoot C:/wamp/www/drupal-6.xServerName site2</VirtualHost>

<VirtualHost *:80>DocumentRoot C:/wamp/www/drupal-6.xServerName drupal6</VirtualHost>

<VirtualHost *:80>DocumentRoot C:/wamp/wwwServerName localhost</VirtualHost>

3. Restart Apache for the changes to take effect. With WampServer, this is done byselecting the WampServer icon in the system tray and then "Restart all services".

5. Now you're ready to install each Drupal test site using your browser, eg:http://site1/install.phphttp://site2/install.php

And that's it. You can access your two test sites anytime WampServer is running by using thehttp://site1 and http://site1 URLs.

As I said, it's not exactly simple, but it is well worth the effort. Now you can do whatever you likewith your test sites. If you mess up with, say, site1, just delete the site1 folder, the site1 databasein phpMyAdmin and the site1 entries in the Windows hosts and Apache httpd-vhosts.conf files andstart again. Alternatively, if a site works out and you want to go live with it, the multi-siteapproach makes this easier (in my opinion).One final caveat: I'm no expert. This technique works for me (apart from one corporateenvironment with a particularly annoying proxy server), but I'd welcome any feedback, especiallyif there are any accuracies.

Multi-site with single codebase, differentcontent databases, shared user database,shared sign-onSECURITY ALERT - The Shared Sign-On module this tutorial formerly relied on has beenwithdrawn because of security risks. It is no longer available at all. There is a replacement module

Page 39: Drupal - Installation Guide

called Single Sign On. It should replace the Shared Sign-On module, but currently reportsproblems with user registration and recommends registration happens through the master site. Ifyour solution requires branded registration pages, you could create a suite of registration pages onthe master site and use the Theme Key module to apply the correct theme to each one, for aseamless user experience (except for the URL, obviously).

WARNING - Following this approach will make updates potentially trickier. It's not a majorissue, but you must be mindful that you are sharing some tables amongst several Drupal instances,so you will need to be aware of install and update hooks which want to make changes to anyshared tables. For example, it is possible for the update or install scripts of a module unique to oneinstance to break other instances if it makes changes to shared tables. There are other multi-sitesolutions, so plan carefully before selecting which one is right for you.

This tutorial makes two assumptions:

1. You are _not_ a total newbie2. You have downloaded MySQL GUI Tools (to make life easier) - clearly this is not a pre-requisite - if you know and prefer command line MySQL then you can replicate the steps I provideeasily enough:http://dev.mysql.com/downloads/gui-tools/5.0.html

Make a copy of /sites/default to /sites/site1 and another to /sites/site2. You may add modules andthemes directories in these new directories in the usual way for site-specific configurations. A filesdirectory should be there already but create it if not. Rename /sites/site1/default.settings.php tosettings.php and /sites/site2/default.settings.php to settings.php (and, for Linux, make sure bothnew files directories are writeable by the web user).

Add these lines to your hosts files:

127.0.0.1 site1127.0.0.1 site2

Create three empty MySQL databases:

drupal_site1drupal_site2drupal_shared_tables

Go to http://site1 and run through the install process in the normal way, using the database name'drupal_site1'.

In MySQL Administrator create a new back-up project of the 'drupal_site1' database containing_only_ the tables you want to share, save it and run it. The result should be a .sql file somewhereon your computer. For reference, the Drupal 6.x tables for sharing users are as follows:

authmapprofile_fieldsprofile_valuesrolesessionsusers

The absolute basic essential tables (if you don't want to share any data except for the users andsessions, no profile data, roles, etc.) are:

sessionsusers

IMPORTANT: if you have Open ID authentication enabled you will also need to share theopenid_associations table.

(This is not a definitive list. Nothing stops you from sharing taxonomy, etc. For example, with thisconfiguration permissions are _not_ shared - each site has its own permissions matrix - but youmight want to share one across all sites. Ditto with enabled modules.)

Edit the .sql script you created and update the database name within to 'drupal_shared_tables'.Using the Restore interface, run the .sql script. You should now have a database called'drupal_shared_tables' containing only the list of tables above.

Go to http://site2 and run through the install process in the normal way, using the database name'drupal_site2'.

Go back to your original 'drupal_site1' database and drop the same list of tables from the schema.Ditto for the 'drupal_site2' database.

Now our databases are ready.

Browse to your Drupal application and edit /sites/site1/settings.php. Change these lines (usuallystarting at line 93 in Drupal 6.3):

<?php$db_url = 'mysqli://user:password@localhost/drupal_site1';$db_prefix = '';?>

To:

<?php$db_url = 'mysqli://user:password@localhost/drupal_site1';

Page 40: Drupal - Installation Guide

$db_prefix = array( 'default' => '', 'authmap' => 'drupal_shared_tables.', 'profile_fields' => 'drupal_shared_tables.', 'profile_values' => 'drupal_shared_tables.', 'role' => 'drupal_shared_tables.', 'sessions' => 'drupal_shared_tables.', 'users' => 'drupal_shared_tables.',);?>

Note the all important trailing dot on the end of drupal_shared_tables - this is vital! You're pre-pending table name info to Drupal's default table name, so you need the dot or Drupal will try toselect:

drupal_site_1.drupal_shared_tablesauthmap

Instead of the desired:

drupal_shared_tables.authmap

Do the same for /sites/site2/settings.php, but with $db_url set to drupal_site2.

You should now be able to login as the super user on both sites separately (http://site1/user orhttp://site2/user), using the credentials you entered when you installed site1, give them bothdifferent settings, modules, permissions and content but use the same user credentials. Moreover,if you create a user on site1, you will see them in users in site2, but with an entirely independentset of permissions you can decide on a site level.

Now for the shared logins. Download and unzip the Single Sign On module in to/sites/all/modules.

Enable the Single Sign On Controller module on the site you want to use as the master for logins(the controller) - in our case, site1. Enable the Single Sign On Client module on all other sites, forthis example just site2.

Then IMMEDIATELY add the following line to settings.php for both sites (see the Single Sign-On README) or you will get PHP errors:

<?php# Single Sign On settings:$conf['session_inc'] = 'sites/all/modules/sso/session.singlesignon.inc';?>

Copy and paste the Controller information on site1 (found at admin/settings/singlesignon-controller) over to the Client settings on site2 (go to admin/settings/singlesignon-client). Savesettings on site2 and logout of both sites. Clear your cookies to avoid any hang-overs from pre-single-sign-on days.

Go to http://site1/user and login. Now go to http://site2. You should stay logged in. Logout againand see you are logged out in both locations. Reverse it so you login on site2 and visit site1. Neat,huh? =)

Need a new site? Take a copy of /sites/default to /sites/new-site, make the necessary vhosts(optional, see below) and DNS/hosts changes, create a blank database, run the Drupal installer,drop the tables you don't want from your new database (the shared ones), edit settings.php addingthe $db_prefix array as above, configure Single Sign-On and you're done!

Optional Apache settings

If you would like to set different Apache settings for your various sites (e.g. different access anderror logs for each) add a vhost entry to Apache looking something like this:

<VirtualHost *:80> DocumentRoot "c:/path/to/drupal" ServerName site1 ServerAlias site2 <IfModule log_config_module> CustomLog logs/d6_access_log.log common </IfModule> ErrorLog logs/d6_error_log.log <Directory "c:/path/to/drupal"> Options +Indexes AllowOverride All Allow from all </Directory> </VirtualHost>

This is not usually necessary.

IMPORTANT - if any of your client sites have any URLs that need to be accessed without anauthentication check, the site concerned _must_ have a line in the 'Request paths' box of SingleSign On Client settings to exclude that URL from being redirected to the controller site forauthentication. These settings can be found under 'Bot recognition' settings(admin/settings/singlesignon-client). For example, if one of your clients uses the Services moduleto expose Drupal-based web services you would add a line like this to that box, in order to excludeall your endpoints from the authentication check:

services/*

Page 41: Drupal - Installation Guide

Remember, this only applies to client sites, not the controller, and must be done on all sites.

Multisite Manager moduleThe Multisite Manager contributed module allows creation of new Drupal sites from a centralDrupal site without the creator having access to database info. The new site is installed either inthe same database with a different prefix or if the drupal db_user has access to create a databaseand grant privileges, then possibly there.

Get started by reading the INSTALL.txt documentation.

More help on some gotchas exists below.

File namesIn a situation where you have an existing file for a site http://www.mysite.com and youwant to multisite http://www.myothersite.com into it you need to make a new directory tothe /sites directory you will find within the mysite file system.This directory should be called /sites/myothersite.com.When you set up a new Drupal site you are asked for the database name, username,password and the prefix of files relevant to the site. This information has to be entered intoDatabase Manager in http://www.mysite.com/admin/settings/multisite_manager and willgenerate a scriptThis script - which currently does not include the database password and omits the initial<?php - should be copied into a file called settings.php and pasted into the directory you setup above.

What Happens NextLog into http://www.myothersite.com normally and the normal Drupal set up screens willappear.Complete this and then create the new site as if it were free standing.

Notes on Multi-sites with Separate Code basesA simple Multi-Site install uses different databases for each site that the installation is hosting. Ina nutshell, a simple Multi-Site extends a "Singular-Site" installation by the web developer (that'syou) adding folders for each site that is served by the installation, in the "sites" directory.

The "default" FolderWhen you install a fresh copy of Drupal, a "default" folder is created inside"theRootOfYourInstallation/sites". Inside this folder resides a file called "settings.php" whichcontains this line of code:$db_url = 'mysql://username:password@pathTodataBase'; tosecurely access your database.

During the initial database installation wizard, Drupal populates that particular line of code withvalues you entered into the fields.

The reason this is called "default" is because, well, this is the default folder that Drupal looks intoto find (in the "settings.php" file) they keys to access the databases. The "default" folder can alsocontain other items, such as a folder called "files" that contains the files for the default installation.

The Key to Understanding Multi-SitesFor continuity, I will use "example.com" as the domain name for the "default"installation / folder and "doesthiswork.com" as the domain name for the site we areadding to this installation.

Now that you know about the "default" folder, you can begin to understand how to add multiplesites to one installation: to add another site to this installation,

1. Create a sibling of the "default" folder with the domain name of "doesthiswork.com" . It isway important to use the extenstion (the .com or .edu, or .org).

2. Inside this folder, you will include a fresh version of "settings.php" (renamed from a"default.settings.php" taken from the zipped files of fresh Drupal core files)

3. Make sure that you have a fresh database created with no tables in it. Write down the path tothe database, the username and password

4. Now you are ready to point your site to the root of the installation. The tricky part of this"simple" instruction is find where your DNS provider lets you point to another site. Anexample of a solution to this step is this: Say my "default" domain name (that goes to thedefault folder) is http://www.example.com and a domain /site that I want to add to thisinstallation is http://www.doesthiswork.com. In the DNS panel forhttp://www.doesthiswork.com, I would point the CNAME to http://www.example.com.When Drupal gets a request for "doesthiswork.com", it will find the doesthiswork.com folderin sites.

5. The first time you go to "doesthiswork.com", you will be greeted with the welcoming DrupalInstallation Wizard". Once you finish the installation wizard, the keys to your databasekingdom will be saved an you will be free to enter your new Drupal site.

So, what's the key to understanding how this works? It is: for every site that you add on thisinstallation, you will need to create a separate domain name folder in sites with (at least) a"settings.php" file. Each folder/settings.php file points to a different database installation.

Page 42: Drupal - Installation Guide

Drupal uses the files stored on the multisite server, in addition to the data in each database to serveup the site.

For each new site that you add, you will have to run through the installation wizard, setting up thesite and adding content. (See installation profiles to make your life easier!) To reiterate: when youupdate a module, you will have to run "http://www.example.com/update.php" and"http://www.doesthiswork.com/update.php" (and other update.php's for each site on your multi-siteinstall) to update EACH database. You might think that this is still alot of work... but it really is atime saver.

Remember to:

put your sites in maintainence mode (admin/settings/site-maintenance)beforerun cron manually (admin/reports/status/run-cron)and clear the cache (admin/settings/performance)

after you run update.php !

Additional Files to place inside your "default" siblingYou can also have

FilesThemeModules

as folders in the "doesthiswork.com" folders. Those items will only be seen by the"doesthiswork.com" installation. As you might have guessed, items in the"theRootOfYourInstallation/sites/all" folder will be avaliable to ALL the site in your Multi-siteinstall.

If you place all your modules in the "theRootOfYourInstallation/sites/all" folder, when youupgrade to an newer version, you only have to replace the module there. However, you need to"update.php" on all sites in your multi-site... including your default site.

One of the things that can trip you up is forgetting to create a "files" folder in your"doesthiswork.com" folder. Make sure you have done that to keep separate files from "different"sites.

Multi-site how-tosInstructions on multi-site configuration (also known as "multisite" and "single code base"installations) can be found within the installation instructions.

Here are some useful links:

Search results4.6 Multi-Site from single code baseMulti-Site .htaccess configurationmulti-site, single installation, shared db, single sign on. is this possible?Automatic Multi-site registrationUsing Multi-Site (4.x)Multihosting Off Single Codebase (4.x)Multisite and symlinks doesn't workSharing tables between installations (4.x)

10 Minute Multisite Install & ConfigurationMultisite 10 minute Install:

Server: LAMPSSH (telnet) Client: ssh (PuTTY if you are using Windows to access your LAMP host)Must have root access to your server.

If website in question is an addon domain, i.e., addon.example.com, then substitute "addon" for"www" in steps below.

For list of Linux commands visit: http://www.oreillynet.com/linux/cmd/ orhttp://www.ss64.com/bash/

Here we go:

[login via ssh / PuTTY]

Debian (Ubuntu)Debian and offshoot distributions (e.g. Ubuntu) make installation and configuration very easy.This was done on a Debian distribution, Ubuntu should work identically.

Installation

Page 43: Drupal - Installation Guide

Assumption: apache2 and mysql are already installed. If not, use apt-get install to install andconfigure them.

# apt-get install drupal6

Answer the questions. This will install everything necessary to run drupal and do the basicconfiguration, including creating an empty database for drupal.

Configure database for drupal6 with dbconfig-common? [YES]Database type to be used by drupal6: [mysql]Password of your database's administrative user: [enter mysql root password]MySQL application password for drupal6: [create a password for your drupal6 db](enter the password again for verification)

You now have a basic unconfigured Drupal6 installation using the database drupal6 andaccessible at http://www.example.com/drupal6. Do not use it. This is the "prototype"installation that we will use to create the sites we really want to use.

Create Site Databases

The easiest way to create databases for your sites is to use dpkg-reconfigure and answer thequestions.

# dpkg-reconfigure drupal6

Re-install database for drupal6? [YES]Database type to be used by drupal6: [mysql]Connection method for MySQL database of drupal6: [unix socket]Name of your database's administrative user: [root]Password of your database's administrative user: [enter mysql root password]username for drupal6: [ENTER YOUR DB SITE *USERNAME* HERE (e.g. mysite)]database name for drupal6: [ENTER YOUR DB *SITE* NAME HERE (e.g. mysite)]

Notes:

1. Repeat the above for each site you want to support.2. I used the same name for the database and the site. KISS.3. Don't use periods (e.g. mysite.com is a bad choice). If you want to spell out the whole

name, use underscores instead of periods (e.g. mysite_com).4. The above method ends up using the same site database password for all the sites you create.

Advice: use mysql-admin (or mysql) to use different passwords for each site.

Configure Apache2 for Sites

Apache2 needs to be configured to support vhost access to your new sites.

Create vhost site configuration files in /etc/apache2/sites-available/

## Virtual hosting configuration for Drupal#

<VirtualHost *:80>ServerAdmin [your email address]

DocumentRoot /usr/share/drupal6/ServerName [your vhost#1 name]ServerAlias [if you want to support www.example.com and example.com]RewriteEngine OnRewriteOptions inherit</VirtualHost>

<VirtualHost *:80>ServerAdmin [your email address]

DocumentRoot /usr/share/drupal6/ServerName [your vhost#2 name]ServerAlias [if you want to support www.example1.com and example1.com]RewriteEngine OnRewriteOptions inherit</VirtualHost>

[...repeat for all your vhosts]

Notes:

Modify the above items that are in [square brackets].You likely will want to support port 443 (https) as well. See Apache documentation fordetailed instructions.I've chosen to put all the vhosts in one file named drupal. You may want to use one file pervhost.

Sym-link the drupal file in the sites-enabled directory to enable it in your site:

# cd /etc/apache2/sites-enabled# ln -s ../sites-available/drupal .

...and reload Apache2 to pick up your configuration changes...# /etc/init.d/apache2 reload

Page 44: Drupal - Installation Guide

Create Drupal Site Configurations

We need to create Drupal configurations for each site by copying the default configuration to theDrupal site subdirectory.

# cd /etc/drupal/6/sites/# cp -a default [site1.com]# cp -a default [site2.com]::

...and edit the configurations to use the right database, MySQL user name, and password...# vi site1.com/dbconfig.php # vi site2.com/dbconfig.php ::

Notes:

Modify the above items that are in [square brackets].

Run Drupal and Configure Your Sites

Browse to your sites, running install.php (e.g. http://www.example.com/install.php) toconfigure them.

ManualGet to location where Drupal core will be located:

[/]# cd /var/www

Upload Drupal core:

"x.x" should be replaced with the version of Drupal you're installing, e.g. "5.2"

[/var/www]# wget http://ftp.osuosl.org/pub/drupal/files/projects/drupal-x.x.tar.gz

Unpack Drupal core:

[/var/www]# tar -zxvf drupal-5.2.tar.gz

Move contents of Drupal core (including .htaccess) to html:

[/var/www]# mv drupal-x.x/* drupal-x.x/.htaccess /var/www/html

Clean-up:

[/var/www]# rm drupal-x.x.tar.gz

[/var/www]# rm drupal-5.2

Create the files directory per Drupal instructions and change permissions (will change permissionagain after install):

[/var/www]# cd html

[/var/www/html]# mkdir files

[/var/www/html]# chmod 777 files

Make directories that will hold custom and contributes modules and themes:

[/var/www/html]# cd sites/all

[/var/www/html/sites/all]# mkdir modules

[/var/www/html/sites/all]# mkdir themes

[/var/www/html/sites/all]# cd modules

[/var/www/html/sites/all/modules]# mkdir custom

[/var/www/html/sites/all/modules]# mkdir contrib

[/var/www/html/sites/all/modules]# cd ../

[/var/www/html/sites/all]# cd themes

[/var/www/html/sites/all/themes]# mkdir custom

[/var/www/html/sites/all/themes]# mkdir contrib

Create directory "www.example.com.tld":

[/var/www/html/sites/all/themes]# cd ../

[/var/www/html/sites/all]# cd ../

[/var/www/html/sites]# mkdir www.example.com

Page 45: Drupal - Installation Guide

Change permission of "settings.php" per Drupal instructions and copy "settings.php" in default towww.example.com:

[/var/www/html/sites]# cd default

[/var/www/html/sites/default]# chmod 777 settings.php

[/var/www/html/sites/default]# cd ../

[/var/www/html/sites]# cp -a default www.example.com

Create database and user with permissions:

[/var/www/html/sites]# mysql

mysql> CREATE DATABASE wwwexamplecom_drupal;

mysql> GRANT ALL PRIVILEGES ON wwwwexamplecom_drupal_drupal.* TO'wwwexamplecom_drupal_myusername'@'localhost' IDENTIFIED BY 'mypassword';

mysql> \q

Go back to PuTTY to chmod on settings.php in www.example.com:

[/var/www/html/sites]# cd www.example.com

[/var/www/html/sites/www.example.com]# chmod 755 settings.php

[/var/www/html/sites/www.example.com]# logout

What next?:

Make changes to "settings.php" in www.example.com? I've read that it's not necessary tomake changes to setting.php.Make changes to "httpd.conf" in /usr/local/apache/conf?

I've been using WHM to create accounts, putting Drupal in public_html and having no problems.But when it comes to parting from the WHM abstraction and getting multisite set-up correctly thisis the end of the proverbial road for me.

Could use help...:

1. Help making improvements to steps articulated above2. Help with next steps so that I/we can get on to grander things, like creating modules, custom

themes, profiles, (and maybe - just maybe - spend some time working on business strategy :-)

Setting up multi-site Drupal on Windows orLinux - consolidated instructionsIf you are new to Drupal and Apache, these instructions will walk you through most of the thingsyou need to do, to get Drupal up and running on Linux or Windows. I haven't covered the detailsof setting up a database in MySQL with phpMyAdmin, but I do show you how to configureApache so that this works. For the Linux instructions the file paths are typical for SuSE Linux10.1 - for most other Linuxes the htdocs path is likely to start at a different place, but theprinciples are the same.

We will assume you want to make a local installation on a Windows PC and an installationreachable via the Internet on a Linux server.

Hosts file

You will find the hosts file at the following locations:

- on Windows: c:\windows\system32\drivers\etc\hosts- on Linux: /etc/hosts

In these instructions, we will assume you want to install a number of sites at:

On Windows (local): strawberry.loc and blueberry.siteOn Linux (Internet): yourdomain.com and blueberry.com

The hosts file will look as follows for the Windows example:127.0.0.1 localhost127.0.0.1 strawberry.loc 127.0.0.1 blueberry.site blueberry

For a Linux internet server the hosts file should look as follows:

ipaddress yourhostname.yourdomain.com yourhostname127.0.0.1 localhost

Please note that for the Linux server on the Internet you only need to have the Fully QualifiedDomainname (FQD) in the form of yourhostname.yourdomain.com in the hosts file. On a Linuxsystem working with DNS, you DO NOT need to make any entries other than the primary FQD inthe hosts file. If you want to have a local site at blueberry.site on Linux, you should add the

Page 46: Drupal - Installation Guide

following line to the Linux hosts file:127.0.0.1 blueberry.site blueberry

Of course blueberry.site would not be reachable through the Internet, because the Internet DNSsystem would know nothing about it, whereas it would work for a local user on that computerbecause the local system would know how to deal with it by looking up the information in thecomputer's hosts file.

DNS

Set up the DNS entries for every domainname your server is hosting. Each one of these domainsneeds to be resolved to your server's ip address. You will normally be able to configure this withyour domain registrar or hosting provider.

For a local Windows or Linux installation, e.g. for development, no DNS configuration isnecessary - the entries in the hosts file on your computer are sufficient. Please note that the defaultlocalhosts entry in the hosts file is not sufficient to get multi sites working on a Drupal installation.

Apache

Configure Apache for all the different domain names that your web server will be serving.

For Linux (our examples use paths for SuSE Linux > 10.0) the best place to do this is in thevhosts.conf file in the /etc/apache2/vhosts.d directory (you can call this file{anything}.conf). Actually every filename ending in .conf in the vhosts.d directory will be pickedup, so beware of multiple overlapping entries - they will confuse the web server.

The entries can also be placed in the /etc/apache2/httpd.conf file initially to keep thingssimple. Later it is better to do it in the vhosts.conf file - this way, in case of an update of theApache software, if the httpd.conf file is overwritten, your configuration will survive.

For Windows, you can get Apache, MySQL and PHP from:http://www.apachefriends.org/en/xampp-windows.html If you installed XAMPP in the default directory on Windows, the vhosts file will be at:c:\program files\xampp\apache\conf\extra\httpd-vhosts.confThe entries can also be placed in thec:\program files\xampp\apache\conf\httpd.conf file initially to keep things simple.

On Linux (the paths in the example are for SuSE Linux), your vhosts.conf file (or entries at theend of the httpd.conf file) should look as follows:

## First entry of this file should be the NameVirtualHost entry, unless it isalready there# If you want your web server to respond on a different port from the default# replace 80 with that port number # Available alternative port numbers are 8080 and 2222#NameVirtualHost *:80

# For each domain you want to serve up with Drupal, # you need an entry that will match the incoming domain# You do not need a separate entry for each subdomain - Drupal takes care ofthat# The following entry takes care of :# yourdomain.com# www.yourdomain.com# bla.yourdomain.com# gaga.yourdomain.com# etc.## In the following we assume that the Apache htdocs directory is at/srv/www/htdocs# and that Drupal has been installed in /srv/www/htdocs/drupal#

<VirtualHost *:80> DocumentRoot /srv/www/htdocs/drupal ServerName yourdomain.com ServerAlias *.yourdomain.com <Directory /srv/www/htdocs/drupal> Allow from all Options +Includes +Indexes +FollowSymLinks AllowOverride all </Directory></VirtualHost>

## The following entry takes care of :# blueberry.com# www.blueberry.com# bla.blueberry.com# gaga.blueberry.com# etc.## In the following we assume that the Apache htdocs directory is at/srv/www/htdocs# and that Drupal has been installed in /srv/www/htdocs/drupal#

<VirtualHost *:80> DocumentRoot /srv/www/htdocs/drupal

Page 47: Drupal - Installation Guide

ServerName blueberry.com ServerAlias *.blueberry.com <Directory /srv/www/htdocs/drupal> Allow from all Options +Includes +Indexes +FollowSymLinks AllowOverride all </Directory></VirtualHost>

## On Linux, you will also need an entry to ensure that your phpMyAdmin works# - you will need phpMyAdmin to set up and manage your MySQL databases# I assume here that you have unpacked and copied the phpMyAdmin files to # /srv/www/htdocs/phpMyAdmin# Please note that in the following, the DocumentRoot and Directory command# both need to use phpMyAdmin# using phpmyadmin doesn't work even though phpmyadmin# is a symbolic link to phpMyAdmin#<VirtualHost *:80> ServerName phpmyadmin.yourdomain.com DocumentRoot /srv/www/htdocs/phpMyAdmin <Directory /srv/www/htdocs/phpMyAdmin> allow from all Options +Indexes +Includes +FollowSymLinks AllowOverride FileInfo Options </Directory></VirtualHost>

For the local Windows example, your httpd-vhosts.conf file (or entries at the end of thehttpd.conf file) should look as follows:

## First entry of this file should be the NameVirtualHost entry, unless it isalready there# If you want your web server to respond on a different port from the default# replace 80 with that port number # Available alternative port numbers are 8080 and 2222#NameVirtualHost *:80

# For each domain you want to serve up with Drupal, # you need an entry that will match the incoming domain# You do not need a separate entry for each subdomain - Drupal takes care ofthat## The following entry takes care of e.g:# strawberry.loc# www.strawberry.loc# bla.strawberry.loc# gaga.strawberry.loc# etc.## In the following we assume that the Apache htdocs directory is at# c:/program files/xampp/htdocs# and that Drupal has been installed in c:/program files/xampp/htdocs/drupal#

<VirtualHost *:80> DocumentRoot "c:/program files/xampp/htdocs/drupal" ServerName strawberry.loc ServerAlias *.yourdomain.com <Directory "c:/program files/xampp/htdocs/drupal"> Allow from all Options +Includes +Indexes +FollowSymLinks AllowOverride all </Directory></VirtualHost>

# The following entry takes care of e.g:# blueberry.site# www.blueberry.site# bla.blueberry.site# gaga.blueberry.site# etc.## In the following we assume that the Apache htdocs directory is at# c:/program files/xampp/htdocs# and that Drupal has been installed in c:/program files/xampp/htdocs/drupal#

<VirtualHost *:80> DocumentRoot "c:/program files/xampp/htdocs/drupal" ServerName blueberry.site ServerAlias *.blueberry.site <Directory "c:/program files/xampp/htdocs/drupal"> Allow from all Options +Includes +Indexes +FollowSymLinks AllowOverride all </Directory></VirtualHost>

It seems that the first entry in vhosts.conf becomes the default Apache server, whereas thelast entry in httpd.conf becomes the default.

On Windows, you get to phpMyAdmin by pointing your browser to http://localhost/phpmyadmin,if it is installed in the default location under the xampp directory.

Page 48: Drupal - Installation Guide

Drupal

Make sure that the settings.php file in

/srv/www/htdocs/drupal/sites/default on Linux or c:\program files\xampp\htdocs\drupal\sites\default on Windows

is the default file that came with the Drupal distribution. Now point your browser tohttp://yourdomain.com and you will see the Drupal install screen which will walk you through theinstallation for the site http://yourdomain.com.

It will ask you for- the name of the MySQL database- the database user and password, and- ask you to set up the first user who will become the administrator of the site.

It is IMPORTANT that the you use this original settings.php file, OR ELSE the Drupal installprocedure DOES NOT WORK when you go to http://yourdomain.com. The reason for this is thatif you use an existing installations settings.php file, Drupal thinks the site is already configuredand DOES NOT start the one time start up installation.

Do the same for any other domains you intend to use and have configured in Apache.

Independent Site at a subdomain

To have http://bla.yourdomain.com (Linux example) or http://bla.strawberry.loc (Windows local)be a different Drupal site, create a directory called:

/srv/www/htdocs/drupal/sites/bla.yourdomain.com on Linux or c:\program files\xampp\htdocs\drupal\sites\bla.stawberry.loc on Windows

and copy the default settings.php file that came with the Drupal distribution into the abovedirectory.

It is IMPORTANT that the you use this original settings.php file, OR ELSE the easy Drupal installprocedure DOES NOT WORK. Make sure you have created a separate database for this site inMySQL before starting the install. Just point the browser to:

http://bla.yourdomain.com on Linux hosting server or http://bla.strawberry.loc on your Windows server

to start the installation. Again, It will ask you:- for the name of the MySQL database- for the database user and password, and- to set up the first user who will become the administrator of the site.

Repeat the above for any other sub-domains you want to configure such ashttp://hello.blueberry.site on Windows.

Independent site at a sub URL

To set up a separate Drupal site at http://www.yourdomain.com/gugu create a directory called

/srv/www/htdocs/drupal/sites/www.yourdomain.com.gugu c:\program files\xampp\htdocs\drupal\sites\www.stawberry.loc.gugu onWindows

and copy the default settings.php file that came with the Drupal distribution into the abovedirectory.

It is IMPORTANT that the you use this original settings.php file, OR ELSE the Drupal installprocedure DOES NOT WORK. Make sure you have created a separate database for this site inMySQL before starting the install. Just point the browser to:

http://www.yourdomain.com/gugu on Linux or http://www.strawberry.com/gugu on Windows

to start the installation. You will be asked:- for the name of the MySQL database- for the database user and password, and- to set up the first user who will become the administrator of the site.

Mechanism for setting up sub-domain and sub-directory/sub-URL sites

For details on how Drupal uses the sites directory structure, read the INSTALL.txt file in the toplevel drupal directory. Here is the relevant excerpt:

MULTISITE CONFIGURATION

A single Drupal installation can host several Drupal-powered sites, each withits own individual configuration.

Additional site configurations are created in subdirectories within the 'sites'directory. Each subdirectory must have a 'settings.php' file which specifies theconfiguration settings. The easiest way to create additional sites is to copythe 'default' directory and modify the 'settings.php' file as appropriate. The

Page 49: Drupal - Installation Guide

new directory name is constructed from the site's URL. The configuration forwww.example.com could be in 'sites/example.com/settings.php' (note that 'www.'should be omitted if users can access your site at http://example.com/).

Sites do not have to have a different domain. You can also use subdomains andsubdirectories for Drupal sites. For example, example.com, sub.example.com,and sub.example.com/site3 can all be defined as independent Drupal sites. Thesetup for a configuration such as this would look like the following:

sites/default/settings.phpsites/example.com/settings.phpsites/sub.example.com/settings.phpsites/sub.example.com.site3/settings.php

When searching for a site configuration (for example www.sub.example.com/site3),Drupal will search for configuration files in the following order, using thefirst configuration it finds:

sites/www.sub.example.com.site3/settings.phpsites/sub.example.com.site3/settings.phpsites/example.com.site3/settings.phpsites/www.sub.example.com/settings.phpsites/sub.example.com/settings.phpsites/example.com/settings.phpsites/default/settings.php

If you are installing on a non-standard port, the port number is treated as thedeepest subdomain. For example: http://www.example.com:8080/ could be loadedfrom sites/8080.www.example.com/. The port number will be removed according tothe pattern above if no port-specific configuration is found, just like a realsubdomain.

Each site configuration can have its own site-specific modules and themes inaddition to those installed in the standard 'modules'and 'themes' directories.To use site-specific modules or themes, simply create a 'modules' or 'themes'directory within the site configuration directory. For example, ifsub.example.com has a custom theme and a custom module that should not beaccessible to other sites, the setup would look like this:

sites/sub.example.com/:settings.phpthemes/custom_thememodules/custom_module

NOTE: for more information about multiple virtual hosts or the configurationsettings, consult the Drupal handbook at drupal.org.

Permissions

FINALLY, make sure all the directories from /srv/www/htdocs/drupal downwards are accessibleby the web server. On SuSE Linux, execute:

chown -R wwwrun:www /srv/www/htdocs/drupal

to ensure that the directories have the right permissions. The userid (uid) is wwrun and the groupid (gid) is www.

These can also be configured somewhere in Apache. For other Linux distributions, find out aswhat user and group Apache runs as and where the htdocs Apache web server root directory is.

Nothing further can stand in the way of your Drupal development - enjoy.

5 minute multisite using CpanelYou want petermoulding.biz, cjm.net.au, and unlevelhome.com on the same server, or virtualprivate server, using one copy of Drupal and a separate database for each site. You are usingCpanel. The first site will take whatever time you need to upload and install Drupal. The secondand subsequent sites will take 5 minutes each. This example uses Drupal 6. Drupal 7 appears to bethe same.

First siteI assume you have the first site set up. You used WHM to create a database account forpetermoulding.biz then went into Cpanel for petermoulding.biz to set up email and install Drupal.You now have petermoulding.biz working with Drupal 6.

When you created petermoulding.biz, you created a user for the account and I will assume the useris named pb. Use the MySQL Databases option or the wizard. I use the MySQL Databases option.You create a database named drupal and cpanel shows a database named pb_drupal. You create auser named drupal for the database and Cpanel displays user pb_drupal. You then connect userpb_drupal to database pb_drupal with all privileges.

Page 50: Drupal - Installation Guide

You use the Cpanel Email Accounts page to create some email accounts for petermoulding.bizincluding one named boss. You will use boss (at) petermoulding.biz as the email address when youcreate the administration account during the Drupal installation.

When installing Drupal, you create directories /sites/default/ and /sites/default/files/ plus file/sites/default/settings.php. You set the permissions to 777 then run the installation step then set/sites/default/settings.php back to 644. You will repeat this step once for each new site.

Second siteGo into Cpanel on petermoulding.biz and park domain cjm.net.au on petermoulding.biz. While youare there, park unlevelhome.com on petermoulding.biz. If you run into a limit on the number ofparked domains, you can go back into WHM to increase the limit. You want a database perdomain so while in WHM, increase the limit on the number of databases.

Create a database and database user for cjm.net.au, perhaps user pb_cjm connected to databasepb_cjm. Repeate for unlevelhome.com with user pb_unlevel connected to database pb_unlevel.

Go into Email Accounts and create boss (at) cjm.net.au plus boss (at) unlevelhome.com.

You probably used FTP to upload Drupal 6 to petermoulding.biz. I will assume FTP. There is afile manger in Cpanel that does similar things to Filezilla and other FTP programs. Go into /sites/and create directory cjm.net.au. While in /sites/, create directory unlevelhome.com.

Create directories /sites/cjm.net.au/files/ and /sites/unlevelhome.com/files/ with permission 777.

Copy /sites/default/default.settings.php to /sites/cjm.net.au/ and rename the file to settings.php thengive it permission 777. Copy /sites/default/default.settings.php to /sites/unlevelhome.com/ andrename the file to settings.php then give it permission 777.

Do you notice how you are repeating part of the original installation? Yeah, it gets boring if youhave 2000 sites.

Visit http://cjm.net.au/ and up pops the Drupal 6 installation process, exactly the same as happenedwith petermoulding.biz. Answer the same questions. Use the right database name, database username, and password.

Visit http://unlevelhome.com/ and up pops the Drupal 6 installation process, exactly the same asfor petermoulding.biz and cjm.net.au.

Third siteDone! You could do ten at a time if you can keep track of all the passwords. Replace your DrupalBeginner t-shirt with the Drupal Do It In My Sleep t-shirt.

ThemesPut standard themes in /sites/all/themes/ to let every site use the themes. Site specific customthemes go in a /themes/ directory within the site. A cjm theme would go in/sites/cjm.net.au/themes/ as /sites/cjm.net.au/themes/cjm/.

ModulesYou have a separate database for every site so you can activate different modules for each site.Put the modules in /sites/all/modules/ then let each site switch them on or off.

Update notificationsDrupal automatically checks for code updates unless you turn off update notifications. You haveonly one copy of the code so switch off update notifications for all sites after the first.

Ok, darumaki pointed out the case where different sites use different modules. "This might be fineif every site was using the same modules, however, a typical multi-site setup usually involves eachsite using different modules, therefore, it should not be advised to turn off updates on the othersites, because updates only checks the modules that are enabled and not all the modules in themodule directory." You could turn on every single module in your base domain, to get updatenotifications, or you could turn on updates in just those domains with something different.

The same consideration applies to themes because theme updates are detected and notified thesame as module updates. The main saving from turning off updates is when you set up 3550identical sites for the 3550 members of a professional association. They want separate databasesfor client privacy but they all get the same modules and features as specified by their association.

MaintenanceYou have one copy of the code so put all the sites offline before updating the code. You have adatabase for every site so run update.php on every site before switching the sites back online.

Which site goes first?

Page 51: Drupal - Installation Guide

The first site is locked in place while any other sites are parked on top. Use a throwaway site forthe first site. When I registered petermoulding.com, I registered the .biz and some other variationsfor experiments. I used the .biz domain name as the base site for the multisite setup because the.biz domain name will not be visited by anyone but me. Each time I load a new theme into/sites/all/themes/, I can activate it in petermoulding.biz for testing. When one of the added on sitesbecomes to busy for the server, I can move the added on site without disturbing the other sites.

The first site is also the default site your customers will see when there is a setup failure in Drupalor Apache. Put contact information on the first site so people can report failed Web sites.

Cpanel interfaceCpanel provides several themes and each theme shows different combinations of buttons. I usecrimson_smoke for these screen shots.

Domains

Go to the domains section to park your new domain, unlevelhome.com, to your existing domain,petermoulding.biz. Do not use Subdomain or Addon domain for this part of the setup.

Subdomains

You add subdomains in the form x.example.com. For domain unlevelhome.com, you might addforums.unlevelhome.com and shop.unlevelhome.com. First you would park unlevelhome.com onpetermoulding.biz and create unlevelhome.com in Drupal following the instructions on this pagethen you would look at adding forums and shop to unlevelhome.com. Adding subdomains shouldbe covered in another page because there would be considerations around sharing user ids acrossthe domains.

The following image shows the Cpanel subdomain page. You can add, edit, and deletesubdomains. If you leave the document root field empty, the result will be similar to parking adomain and should let you use multisite. Multisiting forums.unlevelhome.com next tounlevelhome.com would require public_html/sites/forums.unlevelhome.com/settings.php, anotherdatabase, and a way to share the login.

Addon domains

Addon domains are similar to parked domains but add more complications. Do not use Addondomains for the procedure in this page, use Parked domains.

The following image shows the Cpanel domain addon page. Notice the password field. Addondomains have a subaccount type arrangement you might use if you want to delegate administrationto someone else. You could put several domains in one WHM account using separatesubdirectories and give each site administrator separate FTP access. The separate FTP access doesnot work with multisite because they all share the same directories. Instead use Parked domainsand control uploading of files using a Drupal module.

If you insist on using Addon domains instead of Parked domains then set Docuement root topublic_html/. Drupal multisite is based on all page requests from all sites going to the samepublic_html/index.php.

Page 52: Drupal - Installation Guide

Parked domains

You can park domain egjhnbhniu.com on example.com and Drupal can separate the two if theyhave separate multisite settings. You use Parked domains without redirection. A request foregjhnbhniu.com/food/turnip goes to public_html/index.php then Drupal looks forpublic_html/sites/egjhnbhniu.com/settings.php and uses the database from the settings file. Ifpublic_html/sites/egjhnbhniu.com/settings.php is missing, Drupal usespublic_html/sites/defaults/settings.php and you see a page from example.com.

The following image shows the simple Cpanel domain parking page. It is simple because their areno passwords or document root settings. This is all you need for multisite.

Redirects

A redirect sends one domain to somewhere on another domain. egjhnbhniu.com could beredirected to example.com/test-sites/egjhnbhniu/. A common use is for personal Web sites. Youcreate example.com/~george then, for your birthday, grandma buys george.com for you. You canredirect george.com to example.com/~george. When visitors visit george.com, they seeexample.com/~george so do not redirect, add george.com as a subdomain with a document root of~george.

Page 53: Drupal - Installation Guide

Drupal in a subdirectoryWhen you install Drupal in /home/example/public_html/, unlevelhome.com is in/home/example/public_html/sites/unlevelhome.com/ and you access Drupal ashttp://unlevelhome.com/. If you install Drupal in a subdirectory, for example/home/example/public_html/drupal-6.13/, you can access Drupal ashttp://unlevelhome.com/drupal-6.13/.

An alternative is to change the way you park the domain. Put /drupal-6.13 the Domain Rootsetting. Set Domain Root to /public_html/drupal-6.13 and access Drupal ashttp://unlevelhome.com/.

Drupal lookup documentationThere are lots of questions about the Drupal lookup sequence to get from a domain name to asettings.php file. The Drupal documentation is in INSTALL.txt under the heading MULTISITECONFIGURATION. The following list is the lookup sequence from Drupal 6.12 INSTALL.txt forwww.sub.example.com/site3. Note that Drupal will not look in sites/sub/settings.php orsites/site3/settings.php.sites/www.sub.example.com.site3/settings.phpsites/sub.example.com.site3/settings.phpsites/example.com.site3/settings.phpsites/www.sub.example.com/settings.phpsites/sub.example.com/settings.phpsites/example.com/settings.phpsites/default/settings.php

Attachment Size

cpanel-domains.png 14.89 KB

cpanel-subdomains.png 12.98 KB

cpanel-addon-domains.png 16.95 KB

cpanel-parked-domains.png 14.3 KB

cpanel-redirects.png 17.45 KB

Access all multisites with www. only[.htaccess]The default .htaccess RewriteRule to redirect every multisite.com to www.multisite.com does notwork properly.

If you have problems with that too, just leave the two lines uncommented, and ADD THE

Page 54: Drupal - Installation Guide

FOLLOWING 3 LINES FOR EVERY MULTISITE you set up:

RewriteCond %{HTTP_HOST} mysite\.com$ [NC]RewriteCond %{HTTP_HOST} !^www\.mysite\.com$ [NC]RewriteRule ^(.*)$ http://www.mysite.com/$1 [L,R=301]

(Thanks to Florian!)

Drupal as a libraryShort introduction on how to share drupal with all users on a shared server (without havingtroubles with file-permissions).

Note: it is still possible to use the Multisite option of drupal.

example server's file-structure:

/path/to/phplibraries/drupal (chmod 644)/home/ user1/ (example.com) lib (symbolic link => /path/to/phplibraries/) public_html/ main/ files/ includes (symbolic link => /home/user1/lib/drupal/includes) misc (symbolic link => /home/user1/lib/drupal/misc) modules (symbolic link => /home/user1/lib/drupal/modules) profiles (symbolic link => /home/user1/lib/drupal/profiles) sites/ all (symbolic link => /home/user1/lib/drupal/sites/all) default (symbolic link =>/home/user1/lib/drupal/sites/default) example.com/ settings.php themes (symbolic link => /home/user1/lib/drupal/themes) .htaccess (copy from drupal/.htaccess) cron.php (copy from drupal/cron.php) index.php (copy from drupal/index.php) install.php (copy from drupal/install.php) robots.txt (copy from drupal/robots.txt) update.php (copy from drupal/update.php) xmlrpc.php (copy from drupal/xmlrpc.php) .htaccess (1) user2/ (example2.com) (same as user1) user3/ (example3.com) (same as user1) etc...

.htaccess (1)this isn't neccessary but it keeps public_hml/ clean when several sites are maintained by one user.When only one site is maintained the contents of the main/ directory could be moved topublic_html/ itself

Options +FollowSymLinks

DirectoryIndex index.php

<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{HTTP_HOST} ^example\.com$ [NC] RewriteRule ^(.*) main/$1 [L,QSA]</IfModule>

Installing virtual hosts for Drupal sites andsubsitesThe purpose of this guide is to concisely summarize how to implement apache vhost settings foreach site or subsite.

All steps for this tutorial were implemented with Debian using Apache version 2.0.54.

1. Gain entrance into your shell system, and su to root or another user that can edit apache2configuration files.

2. Go to your apache configuration files:cd /etc/apache2/sites-available

3. Create a configuration file for your new site. For an example site, www.example.com, wemake the site as such:nano example.com

<VirtualHost *:80> ServerAdmin me@myserver DocumentRoot /home/web/drupal/ ServerName www.example.com ServerAlias example.com *.example.com RewriteEngine On RewriteOptions inherit

Page 55: Drupal - Installation Guide

CustomLog /var/log/apache2/example.com.log combined</VirtualHost><VirtualHost *:443> ServerAdmin me@myserver DocumentRoot /home/web/drupal/ ServerName www.example.com ServerAlias example.com *.example.com RewriteEngine On RewriteOptions inherit CustomLog /var/log/apache2/example.com.log combined # SSL Specific options SSLEngine on SSLCipherSuiteALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL SSLCertificateFile /etc/ssl/apache/CA.crt SSLCertificateKeyFile /etc/ssl/apache/CA.key SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown</VirtualHost>

4. Activate the site's configuration:a2ensite www.example.com

5. Reload Apache's configuration:/etc/init.d/apache2 force-reload

Done!

If you get an apache error '/home/www/drupal5/.htaccess: Option Indexes not allowed here'Assuming that my apache2 DocumentRoot is at /home/www,and that drupal is linked to the doc root byln -s /usr/share/drupal5 /home/www/

add the following to /etc/apache2/conf.d/drupal.conf

<Directory /home/www/drupal5/>Options +FollowSymLinks IndexesAllowOverride Allorder allow,denyallow from all</Directory>

Multi-Site, Single Codebase, Shared Database,Shared Sign-on 5.xThis document is written with assumptions that you have:

installed Drupal 5 beforeaccess to your server via ssh / telnetaccess to MySQL database / you can setup your own MySQL database

In this example, I will setup two sites using:

Drupal 5One database on MySQLLinux-based server

Also:

Website’s url is: www.example.comDrupal is installed in: /var/www/drupalNames of sites are: ‘site_1’ and ‘site_2’

These sites will share session and user-related tables so once users login to one of the sites, theycan view the other site without logging in. User roles and profiles are also shared among the twosites. And to be clear, "shared sign on" means that when you created a user/pass on one site, it willwork on the other site(s). It doesn't mean that you'll be automatically logged in to all sites at once(if that's what you want there are two modules to help: singlesignon and fierce_sso.)

1. Prepare database and database user

1.1. create a database and user

In this example, I will use:

DB name: drupal_dbDB username: druserPassword: twositesAccess right: SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,CREATE TEMPORARY TABLES, LOCK TABLES

2. create and modify site configuration

2.1. duplicate settings folder

Duplicate a folder contains site config information under drupal/sites/

Page 56: Drupal - Installation Guide

dru@/var/www/drupal/sites: cp –R default/ www.example.com.site_1dru@/var/www/drupal/sites: cp –R default/ www.example.com.site_2

2.2. Modify config files

2.2.1. provide DB connection detail

Open settings.php in a folder under www.example.com/site_1. Go to line 93 (or somewherearound there) and you should find a line that goes:

$db_url = 'mysql://username:password@localhost/databasename';

change this line with your DB name, DB user and password. It will look like:$db_url = 'mysql://druser:twosites@localhost/drupal_db';

2.2.2. set prefixes for table names

just below the line we just changed above, there is a line that goes like:

$db_prefix=’’;

Since we want to share a database among two sites but not completely, we decide which tables toshare / not to share. This can be done by adding prefixes to table names. An example given belowis for sharing user-related tables, sequences (this table is a ‘counter’ of users, nodes and otherstuff) and session information.$db_prefix = array('default' => 'site_1_','users' => 'shared_','sessions' => 'shared_','role' => 'shared_','authmap' => 'shared_','sequences' => 'shared_','profile_fields' => 'shared_','profile_values' => 'shared_','users_roles' => 'shared_',);

the second line that goes:

'default' => 'site_1_',

this means tables that are not shared with other sites will have a prefix ‘site_1_’. So for example,table name ‘node’ will be ‘site_1_node’.

Now, when you finish editing this file, open and editdrupal/sites/www.example.com.site_2/settings.php. This time, you enter the exact sameinformation for the database connection. So the line around 93 should look like:

$db_url = 'mysql://druser:twosites@localhost/drupal_db';

Then, you add an array of prefixes, which will look like:$db_prefix = array('default' => 'site_2_','users' => 'shared_','sessions' => 'shared_','role' => 'shared_','authmap' => 'shared_','sequences' => 'shared_','profile_fields' => 'shared_','profile_values' => 'shared_','users_roles' => 'shared_',);

notice a prefix in the second line is now ‘site_2_’. At the installation, all tables will have thisprefix except for the ones that are specifically given a prefix ‘shared_’.

3. create static linksIn order to access site_1 and site_2 from web browser, you have to make static links to drupaldirectory. In the directory /var/www, enter the following commands:

ln -s drupal site_1ln -s drupal site_2

now access ‘www.example.com/site_1’ (and ‘site_2’). If you see a drupalicon and a message like‘Unable to select database’, go back to 2.2.1 of this manual and check if you have all detailscorrect, including a single-quotation and semicolon.

If you see hundreds of messages like ‘Warning: Table 'continuu_test.access' doesn't exist’, you arealmost there. While this may look scary or makes you think you have done something wrong, it isjust saying that it cannot find tables Drupal needs to have access to. This is simply because wehave not yet finished installing Drupal. All the necessary tables will be created in the next step,which is described below.

4. install drupalSince we have entered information for database connection, we can run the install script

Page 57: Drupal - Installation Guide

(install.php) straight away, instead of giving all the detail to installation wizard. From your webbrowser, just access:http://www.example.com/site_1/install.phphttp://www.example.com/site_2/install.php

Installation should complete within a second (or two). If you fail to install:

read the error message and find out what is wrong (wrong DB name, username or password,etc.)make sure $db_url (around line 93 in settings.php) ends with a quotation mark andsemicolon. ( ‘; )

If you have two separate Drupal sites and are thinking about merging them with above method, Iwould recommend you not to do it. Yes, it is not impossible. You can rename tables and modifyvalues in sequence table and so on, but i tried it and had a hell of a hard time... If you have sitesalready setup, using CAS or other authentication services is more appropriate than merging.

Multi-Sites Using XAMPP on Windows XPThis procedure allows you to create multiple sites sharing one common set of Drupal coremodules, and has been tested on Windows XP (SP2), Apache 2.2.3, MySQL 5.0.24a, PHP 5.1.6,Drupal 5.2..... I'm assuming that you have a working Drupal installation already. Please note thatthis hasn't been tested with XAMPP 1.7.1 (MySQL 5.0.51a, PHP 5.2.9 Apache 2.2.11) andDrupal 6.x!

1. Create a new MySQL database with appropriate rights.

eg. mydb

2. Create a new folder in your sites folder by copying the default folder and then renaming it withthe name of your new site.

eg. mysite

3. Create the following sub-folders in the above folder for stuff unique to your new site.

mysite\filesmysite\modulesmysite\themesmysite\tmp

4. Edit the database and base URL in the settings.php file in the folder you have just renamed.

$db_url = 'mysql://username:password@localhost/mydb';$base_url = 'http://mysite'; // NO trailing slash!

5. Create a new host in the Windows XP hosts file with same name as new folder.

127.0.0.1 mysite

6. Create a new Virtual Host in the Apache httpd-vhost.conf file with forward slashes in the fullpathname (include <> tags as per the examples in the file).

VirtualHost *:80DocumentRoot "C:/Program Files/xampp/htdocs/drupal"ServerName mysiteVirtualHost

7. Restart the Apache server to load the virtual hosts.

8. Point your web browser at new folder and install Drupal.

http://mysite/install.php

9. Create your first user and Administer the File System paths to match step three above.

sites/mysite/filessites/mysite/tmp

You can use the Windows Search to find the above files if your not familiar with their locations.

Good luck!

Multi-site setup using CPanelAfter some searching around, I found out how to do multi-site setup using CPanel.

1. Create your initial Drupal site at www.example.com. Drupal 5.x makes this very easy to do, asit will automatically install the database for you -- all you have to do is input the databaseinformation.

2. Create a folder in the sites/ folder that matches the subdomain you want to create (so forsite1.example.com, the folder name would be site1.example.com).

Page 58: Drupal - Installation Guide

3. Duplicate the settings.php file from the default folder and place it in your newly created folderfrom step 2.

4. Edit the settings.php file you just placed in the site1.example.com folder so that it does not pointto a database. You can replace the line that has your other site's database information with this:$db_url = 'mysql://username:password@localhost/databasename';

This will allow step 9 below to load your database tables.

5. In CPanel, set up the subdomain. For the above example of site1.example.com, a folder namedsite1 will be automatically created by CPanel.

6. Delete the folder that was created.

7. Use the following example to create and upload a php file onto your site. An easy way to dothis is to use Notepad, pasting in the text below, editing as necessary, and then saving asmultisite.php. Afterwards, upload via FTP or CPanel's File Manager. Make sure you change thepath to whatever the path to your web root is.

<?phpsymlink( '/home/username/public_html/', 'site1' );?>

8. Go to the location of the php file in your browser (such as www.example.com/multisite.php)

This will create a symlink, allowing your subdomain to work properly.

9. Go to your subdomain. Drupal will ask for your database information and then install the tablesnecessary to run the new site.

10. You're all set to use the new site.

If you run into any problems, or have questions, use the contact form attached to my user accounthere to contact me.

truly simple cPanel multsite setupNo single multisite setup method above got me all the way there; if you have cPanel and Drupalinstalled on your original domain, follow these straightforward instructions to set up a multisite:

For 'www.yourlovelysite.com':

1. in cPanel, go to 'Subdomains'

2. enter a name for you subdomain; this is followed by '.' and your original domain nameautomatically, e.g. 'sub1' becomes 'sub1.yourlovelysite.com'.

3. enter a 'Document Root'; this needs to point to the folder in your directory containing the'index.php' file that a Drupal installation creates, e.g. 'public_html', and Create. Please note cPanelmay automatically insert "public_html/sub1" - delete "sub1".

4. in cPanel, go to 'MySQL Databases'.

5. name a new database and 'Create Database'.

6. scroll down to 'MySQL Users' and 'Add New User' - and insert a username and password(twice) - give the user all privileges. Make a note of username/password.

7. in 'Add User to Database', associate your new username with the name of the database justcreated.

8. in cPanel, go to 'File Manager' - though this can be done using Dreamweaver or other ftpsoftware - create a new folder in the 'sites' folder, which is in the root of the Drupal installation,named after your subdomain, e.g. 'sub1.yourlovelysite.com'.

9. copy the file 'settings.php' from the 'sites/default' folder, which you should have already fromyour original Drupal install, and paste it into your new subdomain folder'sub1.yourlovelysite.com'.

10. grant this new 'settings.php' all permissions.

11. open 'settings.php' and locate the line "$db_url ='mysql://username:password@localhost/databasename';".

12. replace each 'variable' with the respective thing, e.g. $db_url ='mysql://newdatabaseusername:newdatabasepassword@localhost/newdatabasename'; and save.

13. now you have a database for your new subdomain which you access using 'settings.php' inyour new subdomain folder.

14. go to 'sub1.yourlovelysite.com/install.php' and follow the familiar steps for a Drupalinstallation.

That should do it.

You can repeat this method over and over: sub2, sub3... and so on.

Page 59: Drupal - Installation Guide

Important:When you upload files/images to your subdomain, by default, Drupal will place that file in'sites/default/files'. To organise and to avoid your subdomains overwriting each others' files,change the 'file system path' in 'Administer > Site configuration > File system' to something like:'sites/sub1.yourlovelysite.com/files'. This should be remembered/reversed if the subdomain is evermoved to its own site, otherwise your pictures will disappear as Drupal is looking in the wrongplace for them.

Multiple domains or vhosts using differentdatabasesApache supports both IP- and name-based virtual hosts (vhosts). While running more than oneengine (by using vhosts) can be very useful for development and testing purpose, it is most usefulfor hosting companies. Therefore, we support vhosts in the best possible way in order to make thelife of all administrators easier. We do so by making it possible to run an unlimited number ofvhosts on the same physical source tree, through using different configuration files. Moreover, youcan setup multiple configuration files in your includes-directory.

$ ls -l sites/*/*.php-rw-rw-r-- 1 drupal drupal sites/www.example1.com/settings.php-rw-rw-r-- 1 drupal drupal sites/www.example2.com/settings.php

The only thing left to do is to set up the corresponding vhosts in your Apache configuration file.Note that the DocumentRoot points to the same source tree twice:

NameVirtualHost 127.0.0.1

DocumentRoot /home/www/drupalServerName www.example1.comDocumentRoot /home/www/drupalServerName www.example2.com

Remember that, as of Drupal 4.6, you can have site specific modules and themes as well. Justcreate a directory under the sites/www.example1.com called 'modules' and place the site specificmodules in it. The same applies to themes as well.

Consult the INSTALL.txt that came with your Drupal installation for more details.

Note that the same effect can be accomplished without further editing httpd.conf if Apache'sdefault virtual server has the Drupal directory as its document root.

Sharing Drupal tables between databasesusing MySQL5 ViewsProblem: You'd like to share some data between two different drupal websites without changingany Drupal code or otherwise having to lift much of a finger. But you don't want to shareinformation unless it meets certain requirements (for example, only users labeled "foo" insomedatabase.sometable) For our example, we'll use the users table.

Solution: Use MySQL5 Views (http://dev.mysql.com/doc/refman/5.0/en/views.html)

Our "master" users table resides in a database called "master". The database of the site that willhave restricted access to our masters users table is called "banana". Assumming you're startingwith a fresh instance of the Drupal schema in your database "banana", do this:

mysql> use banana;mysql> drop table users;mysql> CREATE VIEW users ASmysql> SELECT *mysql> FROM master.users mysql> WHERE uid IN (mysql> SELECT uidmysql> FROM somedatabase.sometablemysql> WHERE uid = 0mysql> OR label = 'foo'mysql> )

Drupal will use banana.users just as it would a normal users table. No other modifications arenecessary. Now only "foo" users will be included in the users table for your banana website.

Note: Drupal has a dependency that is not really documented. Every users table must have anentry that contains uid=0. It's a "stub" entry that Drupal needs to function properly. A workaroundfor this dependency is to include "user 0" in the results set that defines your view.

See, wasn't that easy?

Multiple domains using the same databaseIf you want to host multiple domains (or subdomains) on top of the same database (e.g.http://example.com/ and http://www.example.com/), simply use symbolic links to setup therequired configuration files:

Page 60: Drupal - Installation Guide

$ ln -s sites/example.com sites/www.example.com

$ ls -l sites-rw-rw-r-- 1 drupal drupal sites/example.comlrwxrwxrrx 1 drupal drupal sites/www.example.com -> sites/example.com

If your installation isn't in the root folder then you need to specify the path to the Drupalinstallation. For example if the URL to your installation is http://www.example.com/drupal/ youwould use sites/www.example.com.drupal with a settings.php file in it.

If you want cookies to be shared between two sites, you will need to set the value of PHP'ssession.cookie_domain correctly. In the case above, set it to ".example.com". You can do thisthrough Drupal's .htaccess file.

Multisite setup using a single Drupal instanceNoteThe downside of the following technique is that no two host can share the same IP and differentSSL certificates for secure login. This opens up vulnerabilities to your drupal installation.

Multi-site/Single InstanceThis article is intended for administrators who want to set up multiple sites (perhaps for multipleclients) running on a single Drupal installation. The goal is to keep everyone's site separate(different themes, content, enabled modules etc...) while sharing a single Drupal codebase.

I won't go into full details on how to install Drupal in a shared hosting environment, there areseveral other articles you can reference on that topic, although knowing the following is helpful:

You will need to setup a new MySql database noting its name. That database should beassigned a user who has full privileges. Make sure you have the username/password for theDB user handy.Under the root/sites/default directory is a file called default.settings.php. This file must bere-named to settings.php and placed on the server and made writable.Certain PHP functions may need to be turned on or off (When running the install script thefirst time it should provide this information) Since many shared hosts run CPanel you shouldbe able to take advantage of php.ini Quick Config a nice non threatening web interface thatis easier to modify compared to adding a php.ini file with custom overrides or doing thesame with your .htaccess file.Although not required, I would recommend that your Drupal implimentation be installed onyour primary domain so that it is placed in the html root (i.e. /public_html/). I'll explain howthis can make your life easier in a bit.

We will assume that you have successfully installed and tested your Drupal installation. Letsassume it is named www.myDupalSite.com. Now it's time to create another site by following thesesteps:

Make sure that www.mysecondsite.com is parked on your server. By default (at least inCPanel) it will point to your root html directory which is exactly what we want.

Assuming the parked domain has propagated typing in www.mysecondsite.com at this pointshould show you your drupal implimentation at www.myDupalSite.comCreate a new MySQL database to house the second sites content and information.Assign a database user (with full permissions) creating this account if necessary. You mayuse the same master user account for all Drupal databases if desired.Create a directory for root/sites/mysecondsite.comCopy the settings.php file in your root/sites/default directory to yourroot/sites/mysecondsite.com directory. Make sure it has the appropriate file permissionsOpen the file and modify the database (and database user) settings to point to your secondweb sites databaseNow you can go to http://www.mysecondsite.com/update.php and run through theimplimentation to populate your new Drupal site database.

Congratulations you should now have 2 separate websites capable of using different themes andwith different content running on a single Drupal instance.

Some good things to be aware of regarding multi-site implementations:

If it is appropriate for all modules and themes to be shared with all sites then you can disableupdate checking on all but your primary Drupal implimentation (which should have allmodules enabled). In instances where some sites may have exclusive access to themesand/or modules you don't wish to make generally available you may need to enable updatechecking for those sites.Themes that you wish to be made available to all sites should be placed in/sites/all/themes/theme_name/. A Theme that should be made available to a specific sites(i.e. mysecondsite.com) should be placed inroot/sites/mysecondsite.com/themes/theme_name/Availability of modules is similar to themes. Utilize root/sites/all/modules when you want amodule to be available to all Drupal instances (each instance can choose to enable or disablethe module).

Page 61: Drupal - Installation Guide

Although you are running a single instance of Drupal you have multiple databases that mayneed to be updated when a new version comes out. Please make sure to disable your sitesand run the update.php file once for each site before re-enabling sites when finished.

Same codebase, completely different contentand usersThis document assumes the following:

You want to create more than one Drupal site using the same codebase (the same basic setof Drupal files, uploaded into one location).You know how to install mysql tables in your database.You know how to set up subdomains/folders/other domains that you want to use.You have already downloaded Drupal 4.7, and set up one MAIN site.

This document contains instructions on how to create completely separate Drupalsite, with different configurations, users and content. Nothing is shared betweenthe installations except the codebase.

Some definitions:

codebase: the basic set of Drupal files, included in the .tar.gzfile. the stuff that makes Drupal work.

database: a collection of tables that stores data.

Affected files:

settings.php (sites/default/...)

database.mysql

For this example, we will assume the following:

www.example.com: the MAIN site, where the codebase has already been uploaded,and settings.php has been properly configured.

sub1.example.com; www.example.com/sub2; www.subexample.com : the other siteswe will create.

1. Create the following folders in your sites directory:

sites/sub1.example.com/

sites/www.example.com.sub2/

sites/www.sub3example.com/

Copy the settings.php file from sites/default into each of the above folders.

2. There are different database files (inside the database folder). Selectthe one that is appropriate for your database version. Copy it to each of thefolders you made in step 1. This is OPTIONAL, but it will help you keep thingsstraight.

3. Decide on SEPARATE PREFIXES for each site. Below is what we will use forthe example:

site database prefix

sub1.example.com sub1_

www.example.com,sub2 sub2_

www.sub3example.com sub3_

4. Configure your settings.php for each site.

This code MUST BE CHANGED FOR EACH SITE:

$db_url = 'mysql://username:password@localhost/databasename';

Note; if you are using the same database as the MAIN site, the $db_url is thesame.

OPTIONAL:

# $base_url = 'http://www.example.com'; // NO trailing slash!

# $conf = array( # 'site_name' => 'My Drupal site', # 'theme_default' => 'pushbutton', # 'anonymous' => 'Visitor' # );

Page 62: Drupal - Installation Guide

For sub1.example.com, the settings would be:

$db_prefix = 'sub1_';

$base_url = 'http://sub1.example.com';

$conf = array( 'site_name' => 'My SUB1 Drupal Site', 'theme_default' => 'pushbutton', 'anonymous' => 'Visitor' );

For www.example.com/sub2, the settings would be:

$db_prefix = 'sub2_';

$base_url = 'http://www.example.com/sub2';

$conf = array( 'site_name' => 'My SUB2 Drupal Site', 'theme_default' => 'fancy', 'anonymous' => 'Anonymous' );

For www.sub3example.com, the settings would be:

$db_prefix = 'sub3_';

$base_url = 'http://www.sub3example.com';

$conf = array( 'site_name' => 'My SUB3 Drupal Site', 'theme_default' => 'marvin', 'anonymous' => 'Guests' );

6. Upload the modified settings.php files in their respective folders.

7. Open the database file you copied into each sites folder. Find the following (don't forget theSPACE at the end!!!):

CREATE TABLEINSERT INTO

Replace each 'create table' and 'insert into' with 'create table dbprefix_' and 'insert into dbprefix_'

For sub1.example.com:

CREATE TABLE >> CREATE TABLE sub1_INSERT INTO >> INSERT INTO sub1_

8. Upload the modified mysql files into the database you specified in your settings.php.

9. Voila!

Setting up multi-site Drupal 5 on Windows orLinux - consolidated instructionsIf you are new to Drupal and Apache, these instructions will walk you through most of the thingsyou need to do, to get Drupal up and running on Linux or Windows. I haven't covered the detailsof setting up a database in MySQL with phpMyAdmin, but I do show you how to configureApache so that this works. For the Linux instructions the file paths are typical for SuSE Linux10.1 - for most other Linuxes the htdocs path is likely to start at a different place, but theprinciples are the same.

We will assume you want to make a local installation on a Windows PC and an installationreachable via the Internet on a Linux server.

Hosts file

You will find the hosts file at the following locations:

- on Windows: c:\windows\system32\drivers\etc\hosts- on Linux: /etc/hosts

In these instructions, we will assume you want to install a number of sites at:

On Windows (local): strawberry.loc and blueberry.siteOn Linux (Internet): yourdomain.com and blueberry.com

The hosts file will look as follows for the Windows example:127.0.0.1 localhost127.0.0.1 strawberry.loc 127.0.0.1 blueberry.site blueberry

For a Linux internet server the hosts file should look as follows:

Page 63: Drupal - Installation Guide

ipaddress yourhostname.yourdomain.com yourhostname127.0.0.1 localhost

Please note that for the Linux server on the Internet you only need to have the Fully QualifiedDomainname (FQD) in the form of yourhostname.yourdomain.com in the hosts file. On a Linuxsystem working with DNS, you DO NOT need to make any entries other than the primary FQD inthe hosts file. If you want to have a local site at blueberry.site on Linux, you should add thefollowing line to the Linux hosts file:127.0.0.1 blueberry.site blueberry

Of course blueberry.site would not be reachable through the Internet, because the Internet DNSsystem would know nothing about it, whereas it would work for a local user on that computerbecause the local system would know how to deal with it by looking up the information in thecomputer's hosts file.

DNS

Set up the DNS entries for every domainname your server is hosting. Each one of these domainsneeds to be resolved to your server's ip address. You will normally be able to configure this withyour domain registrar or hosting provider.

For a local Windows or Linux installation, e.g. for development, no DNS configuration isnecessary - the entries in the hosts file on your computer are sufficient. Please note that the defaultlocalhosts entry in the hosts file is not sufficient to get multi sites working on a Drupal installation.

Apache

Configure Apache for all the different domain names that your web server will be serving.

For Linux (our examples use paths for SuSE Linux > 10.0) the best place to do this is in thevhosts.conf file in the /etc/apache2/vhosts.d directory (you can call this file{anything}.conf). Actually every filename ending in .conf in the vhosts.d directory will be pickedup, so beware of multiple overlapping entries - they will confuse the web server.

The entries can also be placed in the /etc/apache2/httpd.conf file initially to keep thingssimple. Later it is better to do it in the vhosts.conf file - this way, in case of an update of theApache software, if the httpd.conf file is overwritten, your configuration will survive.

For Windows, you can get Apache, MySQL and PHP from:http://www.apachefriends.org/en/xampp-windows.html If you installed XAMPP in the default directory on Windows, the vhosts file will be at:c:\program files\xampp\apache\conf\extra\httpd-vhosts.confThe entries can also be placed in thec:\program files\xampp\apache\conf\httpd.conf file initially to keep things simple.

On Linux (the paths in the example are for SuSE Linux), your vhosts.conf file (or entries at theend of the httpd.conf file) should look as follows:

## First entry of this file should be the NameVirtualHost entry, unless it isalready there# If you want your web server to respond on a different port from the default# replace 80 with that port number # Available alternative port numbers are 8080 and 2222#NameVirtualHost *:80

# For each domain you want to serve up with Drupal, # you need an entry that will match the incoming domain# You do not need a separate entry for each subdomain - Drupal takes care ofthat# The following entry takes care of :# yourdomain.com# www.yourdomain.com# bla.yourdomain.com# gaga.yourdomain.com# etc.## In the following we assume that the Apache htdocs directory is at/srv/www/htdocs# and that Drupal has been installed in /srv/www/htdocs/drupal#

<VirtualHost *:80> DocumentRoot /srv/www/htdocs/drupal ServerName yourdomain.com ServerAlias *.yourdomain.com <Directory /srv/www/htdocs/drupal> Allow from all Options +Includes +Indexes +FollowSymLinks AllowOverride all </Directory></VirtualHost>

## The following entry takes care of :# blueberry.com# www.blueberry.com# bla.blueberry.com# gaga.blueberry.com# etc.

Page 64: Drupal - Installation Guide

## In the following we assume that the Apache htdocs directory is at/srv/www/htdocs# and that Drupal has been installed in /srv/www/htdocs/drupal#

<VirtualHost *:80> DocumentRoot /srv/www/htdocs/drupal ServerName blueberry.com ServerAlias *.blueberry.com <Directory /srv/www/htdocs/drupal> Allow from all Options +Includes +Indexes +FollowSymLinks AllowOverride all </Directory></VirtualHost>

## On Linux, you will also need an entry to ensure that your phpMyAdmin works# - you will need phpMyAdmin to set up and manage your MySQL databases# I assume here that you have unpacked and copied the phpMyAdmin files to # /srv/www/htdocs/phpMyAdmin# Please note that in the following, the DocumentRoot and Directory command# both need to use phpMyAdmin# using phpmyadmin doesn't work even though phpmyadmin# is a symbolic link to phpMyAdmin#<VirtualHost *:80> ServerName phpmyadmin.yourdomain.com DocumentRoot /srv/www/htdocs/phpMyAdmin <Directory /srv/www/htdocs/phpMyAdmin> allow from all Options +Indexes +Includes +FollowSymLinks AllowOverride FileInfo Options </Directory></VirtualHost>

For the local Windows example, your httpd-vhosts.conf file (or entries at the end of thehttpd.conf file) should look as follows:

## First entry of this file should be the NameVirtualHost entry, unless it isalready there# If you want your web server to respond on a different port from the default# replace 80 with that port number # Available alternative port numbers are 8080 and 2222#NameVirtualHost *:80

# For each domain you want to serve up with Drupal, # you need an entry that will match the incoming domain# You do not need a separate entry for each subdomain - Drupal takes care ofthat## The following entry takes care of e.g:# strawberry.loc# www.strawberry.loc# bla.strawberry.loc# gaga.strawberry.loc# etc.## In the following we assume that the Apache htdocs directory is at# c:/program files/xampp/htdocs# and that Drupal has been installed in c:/program files/xampp/htdocs/drupal#

<VirtualHost *:80> DocumentRoot "c:/program files/xampp/htdocs/drupal" ServerName strawberry.loc ServerAlias *.yourdomain.com <Directory "c:/program files/xampp/htdocs/drupal"> Allow from all Options +Includes +Indexes +FollowSymLinks AllowOverride all </Directory></VirtualHost>

# The following entry takes care of e.g:# blueberry.site# www.blueberry.site# bla.blueberry.site# gaga.blueberry.site# etc.## In the following we assume that the Apache htdocs directory is at# c:/program files/xampp/htdocs# and that Drupal has been installed in c:/program files/xampp/htdocs/drupal#

<VirtualHost *:80> DocumentRoot "c:/program files/xampp/htdocs/drupal" ServerName blueberry.site ServerAlias *.blueberry.site <Directory "c:/program files/xampp/htdocs/drupal"> Allow from all Options +Includes +Indexes +FollowSymLinks AllowOverride all </Directory></VirtualHost>

Page 65: Drupal - Installation Guide

It seems that the first entry in vhosts.conf becomes the default Apache server, whereas thelast entry in httpd.conf becomes the default.

On Windows, you get to phpMyAdmin by pointing your browser to http://localhost/phpmyadmin,if it is installed in the default location under the xampp directory.

Drupal

Make sure that the settings.php file in

/srv/www/htdocs/drupal/sites/default on Linux or c:\program files\xampp\htdocs\drupal\sites\default on Windows

is the default file that came with the Drupal distribution. Now point your browser tohttp://yourdomain.com and you will see the Drupal install screen which will walk you through theinstallation for the site http://yourdomain.com.

It will ask you for- the name of the MySQL database- the database user and password, and- ask you to set up the first user who will become the administrator of the site.

It is IMPORTANT that the you use this original settings.php file, OR ELSE the Drupal installprocedure DOES NOT WORK when you go to http://yourdomain.com. The reason for this is thatif you use an existing installations settings.php file, Drupal thinks the site is already configuredand DOES NOT start the one time start up installation.

Do the same for any other domains you intend to use and have configured in Apache.

Independent Site at a subdomain

To have http://bla.yourdomain.com (Linux example) or http://bla.strawberry.loc (Windows local)be a different Drupal site, create a directory called:

/srv/www/htdocs/drupal/sites/bla.yourdomain.com on Linux or c:\program files\xampp\htdocs\drupal\sites\bla.stawberry.loc on Windows

and copy the default settings.php file that came with the Drupal distribution into the abovedirectory.

It is IMPORTANT that the you use this original settings.php file, OR ELSE the easy Drupal installprocedure DOES NOT WORK. Make sure you have created a separate database for this site inMySQL before starting the install. Just point the browser to:

http://bla.yourdomain.com on Linux hosting server or http://bla.strawberry.loc on your Windows server

to start the installation. Again, It will ask you:- for the name of the MySQL database- for the database user and password, and- to set up the first user who will become the administrator of the site.

Repeat the above for any other sub-domains you want to configure such ashttp://hello.blueberry.site on Windows.

Independent site at a sub URL

To set up a separate Drupal site at http://www.yourdomain.com/gugu create a directory called

/srv/www/htdocs/drupal/sites/www.yourdomain.com.gugu c:\program files\xampp\htdocs\drupal\sites\www.stawberry.loc.gugu onWindows

and copy the default settings.php file that came with the Drupal distribution into the abovedirectory.

It is IMPORTANT that the you use this original settings.php file, OR ELSE the Drupal installprocedure DOES NOT WORK. Make sure you have created a separate database for this site inMySQL before starting the install. Just point the browser to:

http://www.yourdomain.com/gugu on Linux or http://www.strawberry.com/gugu on Windows

to start the installation. You will be asked:- for the name of the MySQL database- for the database user and password, and- to set up the first user who will become the administrator of the site.

Mechanism for setting up sub-domain and sub-directory/sub-URL sites

For details on how Drupal uses the sites directory structure, read the INSTALL.txt file in the toplevel drupal directory. Here is the relevant excerpt:

MULTISITE CONFIGURATION

A single Drupal installation can host several Drupal-powered sites, each with

Page 66: Drupal - Installation Guide

its own individual configuration.

Additional site configurations are created in subdirectories within the 'sites'directory. Each subdirectory must have a 'settings.php' file which specifies theconfiguration settings. The easiest way to create additional sites is to copythe 'default' directory and modify the 'settings.php' file as appropriate. Thenew directory name is constructed from the site's URL. The configuration forwww.example.com could be in 'sites/example.com/settings.php' (note that 'www.'should be omitted if users can access your site at http://example.com/).

Sites do not have to have a different domain. You can also use subdomains andsubdirectories for Drupal sites. For example, example.com, sub.example.com,and sub.example.com/site3 can all be defined as independent Drupal sites. Thesetup for a configuration such as this would look like the following:

sites/default/settings.phpsites/example.com/settings.phpsites/sub.example.com/settings.phpsites/sub.example.com.site3/settings.php

When searching for a site configuration (for example www.sub.example.com/site3),Drupal will search for configuration files in the following order, using thefirst configuration it finds:

sites/www.sub.example.com.site3/settings.phpsites/sub.example.com.site3/settings.phpsites/example.com.site3/settings.phpsites/www.sub.example.com/settings.phpsites/sub.example.com/settings.phpsites/example.com/settings.phpsites/default/settings.php

If you are installing on a non-standard port, the port number is treated as thedeepest subdomain. For example: http://www.example.com:8080/ could be loadedfrom sites/8080.www.example.com/. The port number will be removed according tothe pattern above if no port-specific configuration is found, just like a realsubdomain.

Each site configuration can have its own site-specific modules and themes inaddition to those installed in the standard 'modules'and 'themes' directories.To use site-specific modules or themes, simply create a 'modules' or 'themes'directory within the site configuration directory. For example, ifsub.example.com has a custom theme and a custom module that should not beaccessible to other sites, the setup would look like this:

sites/sub.example.com/:settings.phpthemes/custom_thememodules/custom_module

NOTE: for more information about multiple virtual hosts or the configurationsettings, consult the Drupal handbook at drupal.org.

Permissions

FINALLY, make sure all the directories from /srv/www/htdocs/drupal downwards are accessibleby the web server. On SuSE Linux, execute:

chown -R wwwrun:www /srv/www/htdocs/drupal

to ensure that the directories have the right permissions. The userid (uid) is wwrun and the groupid (gid) is www.

These can also be configured somewhere in Apache. For other Linux distributions, find out aswhat user and group Apache runs as and where the htdocs Apache web server root directory is.

Nothing further can stand in the way of your Drupal development - enjoy.

Setup of /sites directory for multi-siteDrupal's multi-site hosting capability is built in with any installation. This is great news for userswho run numerous web sites from a single hosting account. A single Drupal installation can beused to run multiple domains, which makes it much easier to manage and maintain the code base.Even if you are dealing with only one domain, the multi-site capability may be valuable byproviding the ability to run a separate domain or sub-domain for a development version.

This page describes the set-up of the /sites directory for multi-sites.

With version 5.x, the intended location for all non-core elements of a Drupal installation is in aseparate /sites directory inside the Drupal installation.

Directory Contents/drupal/sites/all

Page 67: Drupal - Installation Guide

/drupal/sites/all

(used by all sites)/modules/themes

/drupal/sites/default

(used when there is no /sites/example.com directory)/filessettings.php

/drupal/sites/example1.com

/files/modules/themes/tmpsettings.php

/drupal/sites/example2.com

/files/modules/themes/tmpsettings.php

The intended best practice configuration is to create a /sites/example.com directory for eachdomain. It should contain a site-specific settings.php file and /files directory. Configure Drupal sitesettings to specify 'File System Directory' of 'sites/example.com/files' instead of the default 'files'.It's possible to do this with an existing web site, but moving file uploads around can cause a lot ofconfusion if there are already URLs pointing to the old locations.

Domain specific modules and themes should also be placed in /sites/example.com/modules and/sites/example.com/themes respectively.

Contributed modules and additional themes which are for use by all domains in a multi-siteinstallation should be placed in /sites/all/modules and /sites/all/themes. Note that there shouldn't bea /sites/all/files or /sites/all/settings.php.

The /sites/default directory should contain /files and settings.php, for use if the /sites/example.comdirectory doesn't exist for a domain.

In addition to multiple sites, such as example1.com and example2.com, sub domains are alsoeasily set up. Adding sub3.example2.com and sub3.example2.com/site4, the directory structure forthese four sites would be:

/drupal/sites/all/modules/drupal/sites/all/themes/drupal/sites/default/files/drupal/sites/default/settings.php/drupal/sites/example1.com/files/drupal/sites/example1.com/modules/drupal/sites/example1.com/settings.php/drupal/sites/example1.com/themes/drupal/sites/example1.com/tmp/drupal/sites/example2.com/files/drupal/sites/example2.com/modules/drupal/sites/example2.com/themes/drupal/sites/example2.com/tmp/drupal/sites/example2.com/settings.php/drupal/sites/sub3.example2.com/files/drupal/sites/sub3.example2.com/modules/drupal/sites/sub3.example2.com/settings.php/drupal/sites/sub3.example2.com/themes/drupal/sites/sub3.example2.com/tmp/drupal/sites/sub3.example2.com.site4/files/drupal/sites/sub3.example2.com.site4/modules/drupal/sites/sub3.example2.com.site4/settings.php/drupal/sites/sub3.example2.com.site4/themes/drupal/sites/sub3.example2.com.site4/tmp

Note that Drupal reconizes www.example.com as a sub-domain of example.com.If you wish to point both of them to the same site, use /drupal/sites/example.com/ as yourdirectory, and uncomment the corresponding option in your .htaccess

Once you've done this, the file structure of your site will be cleanly organized:

The main Drupal directory will contain only the standard 'core' files.Themes and modules that are shared among all sites are properly placed in /sites/allSite-specific themes, modules, and files are compartmentalized and properly placed in/sites/example.com, /sites/example1.com, /sites/sub3.example2.com and/sites/sub3.example2.com.site4 ./sites/default/settings.php and /sites/default/files will be used if /sites/example.com directorydoes not exist.Backing up the /sites directory and your Drupal database will give you everything you needto restore the site in the event of a crash, or to move to a new server.Adding a domain is easy: just copy the /sites/default directory to /sites/example5.com

To help keep files organized you may choose to use shortcuts to point relevant files and directoriesthat are stored elsewhere in your Drupal installation. These short-cuts (like a desktop "alias") arereferred to as "symbolic links" on a Web server. Symbolic links can be used for several purposes:

Even if using default settings, a good option is to use links from /sites/example.comdirectory to point to the /sites/default directory. That way, if the settings and /files are everchanged from the default and actually placed in /sites/example.com, their location does not'move' and no links are broken.

Page 68: Drupal - Installation Guide

Links could also be used to point the /sites/default directory to your primary site.A /files directory could easily be shared across two domains without being shared across theremaining domains.A non-domain-name path for /files can be setup. If it is possible that the domain name mightchange (say, from a development name), then you can set up a link from/drupal/sites/moniker to /drupal/sites/example.com, where 'moniker' is a short version of thesite name that will remain constant even if /example.com changes.

If you are working from the command line on a Linux, Unix or OSX server you can create asymbolic link using the following command:$ ln -s /path/to/actual/file/or/directory name_of_shortcut

Although the /sites/default directory could contain a /modules and /themes directory, theseelements should usually be placed in /sites/all or /sites/example.com. Similarly, althoughcontributed modules could be placed in /drupal/modules as was the practice in version 4.7, this isnot recommended.

Multi-site directory setup for sub-domains, including non-standard ports, is described in theinstallation instructions found in INSTALL.txt.

See multidomain for a contributed module that allows spanning one site across multiple domains,so that specific content types appear on specific domains or sub-domains.

Version 4.6 and 4.7: Best practice for multi-site set-up under version 4.6 and 4.7 is similar to 5.x.The primary difference is that there is no /sites/all directory. Instead, /modules and /themes that areavailable for all domains are kept in /drupal/modules and /drupal/themes.

Files DirectoryThe following user-submitted code may be useful in redirecting URLs for the /files directory tothe /sites/example.com/files directory. The following code is added to the[drupal_root]/files/.htaccess file:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule ^(.*)$ /sites/%{HTTP_HOST}/files/$1 [L]

If the .htaccess method doesn't work, try this user-contributed code for use in settings.php, insteadof .htaccess.

In settings.php, put this code:

<?php$conf['file_directory_temp'] = 'sites/' .substr(strrchr(dirname(__FILE__), '/'),1) .'tmp';$conf['file_directory_path'] = 'sites/' .substr(strrchr(dirname(__FILE__), '/'),1) .'/files';?>

Video about Multisite optimizationHere is a video I'm contributing about configuring a Multisite Drupal install within an Apacheserver environment.

It provides a number of tips related to optimizing the httpd.conf file for better security on filessuch as install.php, cron.php and update.php. It also provides tips on managing the multisiteconfiguration by using a dedicated drupal.conf file and controlling access to sensitive areas of thesite (like /admin) using an ip.conf file.

One other valuable tip is temporarily using the apache directive DirectoryIndex (while updatingdrupal) to point all sites managed in the multisite install to a different index page (such asoffline.php) so you don't have to go into every site and turn on maintenance mode (which can be apain).

Share a single database across multiple sitesSome web hosts limit their customers to one database. Thus, no duplicate table names are possible.In order to assure that these admins can still use Drupal, and even use multiple installations ofDrupal, Drupal offers table prefixing.

In order to use this feature, you must currently edit the script database/database.x in order tocreate tables prefixed by the string of your choice. If you are adding contributed modules you willneed to also modify INSERT and REPLACE statements to have a prefix as well. For example,change all statements from the format of

CREATE TABLE accessINSERT INTO system VALUES ('modules/filter.module','filter','module','',1,0,0);

Becomes,CREATE TABLE dr1_accessINSERT INTO dr1_system VALUES('modules/filter.module','filter','module','',1,0,0);

Then use dr1_ (for example) as value of $db_prefix in your sites/example.com/settings.php

Page 69: Drupal - Installation Guide

file.

You can also use the prefix.sh in the scripts subdirectory of your Drupal install to do thisautomatically. You can then update several sites in one swoop with a (bash shell) command-linelike

for F in '' prefix1 prefix2; do \ for S in `find ./modules --name \*mysql`; do \ scripts/dbprefix.sh $F < $S | grep -v DROP |\ mysql -h DBHOST -u DBUSER -pPASSWD DATABASE; \ done; done

NOTE:that not all scripts end in mysql, but you get the idea; the '' prefix tells the script to run withno prefix at all, ie a straight cat - command that just lets me process all my sites together.Here is a PHP script that creates all of the database tables for all sites in /drupal/sites/*. It worksfor DRUPAL-4-6. See the Database Table Creation script issue for more info.

If you want to share users across multiple sites, you'll need to use a $db_prefix along these lines:

<?php$db_prefix = array( 'default' => 'thissite_', 'authmap' => 'shared_', 'profile_fields' => 'shared_', 'profile_values' => 'shared_', 'role' => 'shared_', 'sequences' => 'shared_', 'sessions' => 'shared_', 'users' => 'shared_', 'users_roles' => 'shared_', 'users_uid_seq' => 'shared_', // for pgsql);?>

See the sharing tables and sharing tables across databases sections.

Share tables across instances (notrecommended)Please note: This procedure could result in unexpected results, depending on which tables youchoose to share, including broken version updates and/or security holes.

For instance, if one site is compromised, an attacker could compromise the shared database tablesand compromise your other sites. Think about both the settings to be shared and be aware of therisks involved. You can, however, host multiple sites in the same database (with no shared tables)by using site-wide table prefixes.

By using table prefixes on some tables but not others, you can cause multiple Drupal installationsto share a set of common tables. One interesting application for this is to share the taxonomytables (vocabularies, term_data). Another interesting use is to share users across Drupalinstallations.

In order to use this capability, create two drupal installs in same DB using different databaseprefixes. In this example, one is prefixed 'master_' and the other 'slave1_'. Then edit thesettings.php file of 'slave1_' so that it points some tables to the 'master_'. For sharing users, add thefollowing:

$db_prefix = array( "default" => "slave1_", // the prefix for tables that are not shared. "users" => "master_", "sessions" => "master_", "authmap" => "master_", "sequences" => "master_", "profile_fields" => "master_", "profile_values" => "master_",);

Note: The actual tables that you will share depends on your installation.However, the following tables contain data that is highly site specific and therefore should not beshared:

cachevariable

There is a limitation in that you can only explicitly specify which tables will be shared and not theother way round. The following may fail (however a recently deleted comment on this page bymarcob suggests this has been fixed:

$db_prefix = array( // Be careful of this setup. 'default' => 'primary_', 'cache' => 'slave1_', 'node' => 'slave1_', 'system' => 'slave1_', // etc...);

Page 70: Drupal - Installation Guide

Setup tip for Drupal 5

For Drupal 5+, an easy way to get started with table sharing across instances is to run the installertwice using the same database - it will create the prefixed tables and handle all the initialINSERTS (as with the 'system' and 'menu' tables, etc) for all your different prefixes.

Using schema prefixes with PostgreSQLThis page discusses usage of PostgreSQL schemas for prefixes. "Normal" prefixes can be used inthe same way as in MySQL, so they won't be discussed here.

PostgreSQL has something called 'schemas' (http://www.postgresql.org/docs/current/static/ddl-schemas.html). They can be very handy sometimes, but if you don't know what they are, youprobably don't actually need them and can stop reading here.

Schemas can be used as prefixes within Drupal. That is, with a multisite setup, each site can residein its own schema, and shared tables can reside in a "shared" schema (or even in the publicschema).

There is one annoyance: the upgrade will fail. This is unfortunate, but nothing can be done as the"normal" (not schema) and schema prefixes are just incompatibile. If you are interested in thedetails, please see http://drupal.org/node/40034.

But, don't worry. This can be easily fixed by changing the update script (update.php andupdates.inc) a bit. The problem lies in the CREATE [UNIQUE] INDEX and ALTER TABLE ...DROP/ADD CONSTRAINT statesments. When schema prefixes are used, queries like this areexecuted:

CREATE INDEX prefix.search_total_word_idx ON prefix.search_total(word)ALTER TABLE prefix.boxes DROP CONSTRAINT prefix.boxes_title_keyALTER TABLE test.contact ADD CONSTRAINT test.contact_category_key UNIQUE(category)

The prefix must be removed from the index and constraint name--that is they must be changed to:

CREATE INDEX search_total_word_idx ON prefix.search_total(word)ALTER TABLE prefix.boxes DROP CONSTRAINT boxes_title_keyALTER TABLE test.contact ADD CONSTRAINT contact_category_key UNIQUE (category)

You can easily search for CREATE INDEX, CREATE UNIQUE INDEX and ADD/DROP CONSTRAINTstatements and remove the {} from index/constraint names.

The best way is to run a test upgrade. You'll see a list of failed queries and it will be easier for youto change them.

Another remark: you can't use prefix.sh to prefix the tables, it will produce incorrect CREATE[UNIQUE] INDEX queries. This, also, can be easily fixed, by changing:

s/^CREATE INDEX \(.*\) ON /CREATE INDEX $PREFIX\\1 ON $PREFIX/;s/^CREATE UNIQUE INDEX \(.*\) ON /CREATE UNIQUE INDEX $PREFIX\\1 ON $PREFIX/;

to:

s/^CREATE INDEX \(.*\) ON /CREATE INDEX \\1 ON $PREFIX/;s/^CREATE UNIQUE INDEX \(.*\) ON /CREATE UNIQUE INDEX \\1 ON $PREFIX/;

An alternate approachHere's what you need to do if you want to solve it this way:

1. Add the following at the top of your database.pgsql file:

CREATE SCHEMA schemaname;SET search_path TO schemaname;

2. Edit drupal/includes/database.pgsql.inc, replacing the function db_connect() with:

<?phpfunction db_connect($url) { $url = parse_url($url);

$db_and_schema = explode(".",substr($url['path'], 1));

$conn_string = ' user='. $url['user'] .' dbname='. $db_and_schema['0'] .'password='. $url['pass'] . ' host=' . strtr($url['host'],'+','/'); $conn_string .= isset($url['port']) ? ' port=' . $url['port'] : '';

$connection = pg_connect($conn_string) or die(pg_last_error());

if(!empty($db_and_schema['1'])) pg_query('SET search_path TO'.$db_and_schema['1']);

return $connection;}?>

3. Finally, use a db_url akin to such in your settings.php file(s):

$db_url = 'pgsql://user:password@+tmp/dbname.schemaname';

Page 71: Drupal - Installation Guide

Not thoroughly tested, but works for me (on 4.6.3).This also fixes the inability to specify a Unix socket as the host - the +tmp gets replacedwith /tmp for pg_connect().

Drupal 6.xSQL command after database connect

Actually, as of Drupal 6.9, I couldn't find a file named updates.inc, and a grep 'CONSTRAINT'update.php modules/update/* returned nothing.

In the second solution, the trick is to

* embed the schema name in $dburl (in settings.php), * then modify db_connect() code to o extract the schema name from $dburl o rebuild a suitable connection string (remove it from $db_url) for pg_connect() o build and send a SQL instruction to the engine, telling it to usethe specified schema.

Searching db_connect() in Drupal site, I found this old post #26549: SQL command after databaseconnect ", unfortunately closed. The links it points to restrict the idea to fixing encoding (nowrigidly set to utf-8).

It sounds to me like a cleaner and more flexible version of the second approach described here.

I posted this alternate solution as #375763: Running site-specific SQL commands on databaseconnect

Moving Drupal tables to their dedicated PostgreSQL schemaAfter applying the patch I submitted in #375763: Running site-specific SQL commands ondatabase connect, I created a blog entry, with PHP code input format, and the following bodycontent:

<?php global $db_type;

if ($db_type!='pgsql') die ("This tool is intended for PostgreSQL databases only.Current engine: $db_type");

$res = db_query("SELECT current_schema();" );$pg_schema_active = db_result($res);$pg_schema_new = 'drupal';

if ($pg_schema_active == $pg_schema_new) { echo "<p>Current schema is '$pg_schema_new' already.\n"; echo "The following is useless.</p>\n";}echo <<< EOT<p>To move your Drupal tables from current PostgreSQL schema"<code>$pg_schema_active;</code>" to their dedicated"<code>$pg_schema_new;</code>" namespace, you need to:</p><ol><li>save this code in a file, e.g. "<code>migrate-drupal-schema.sql</code>"</li><li>put your Drupal site offline (maintenance mode).</li><li>Enable PostgreSQL schema support in your Drupal site (Issue [#375763])</li><li>execute sql code with 'psql' or 'phppgadmin' for example</li><li>edit your <code>settings.php</code> file and add (a good place is just below\$db_url and \$db_prefix):<pre>\$db_after_connect_sql = "SET search path TO $pg_schema_new;";<pre></li><li>Put your Drupal site back online.</li></ol>EOT;

$drupal_schema = drupal_get_schema(NULL, TRUE);

$migrate_sql = "CREATE schema $pg_schema_new;\n\n";foreach (array_keys($drupal_schema) as $table_name) { $migrate_sql .= "ALTER TABLE $pg_schema_active.$table_name SET SCHEMA$pg_schema_new;\n";}echo "<textarea cols=\"80\" rows=\"15\" name=\"migrate-drupal-schema\">\n";echo $migrate_sql;echo "</textarea>\n";?>

Its output should be self explanatory. Please post comments in the support forum if you haveproblems.

Define shared variables for all sitesWhen you create a multi-site installation, an important table to duplicate is the variable table.However, by duplicating this table, you will also duplicate some variables that you might prefer

Page 72: Drupal - Installation Guide

not to. To force a set value for these variables, for all of your websites, you can do the following.

First, you will probably have a settings.php file for each site in your installation, likesites/example.com/settings.php. Edit each file and add the following to the end.

include_once ('./sites/default/shared_variables.php');

Now, in the default directory, add a file called sites/default/shared_variables.phpcontaining the following.

<?php/*** These variables are fixed for all sites that have this line of * code in their settings.php file:* * include_once ('./sites/default/shared_variables.php');*/$conf = array( 'site_name' => 'All these sites are belong to us.', 'theme_default' => 'pushbutton', 'anonymous' => 'Visitor');?>

The element names (eg. 'site_name') correspond to a variable in the variable table. So no matterhow many copies of the variable table that you need, each site in your multi-site installation willdefer to the variables that you define in the $conf array in your shared_variables.php file.

The disadvantage is that these variables cannot be edited via the Drupal admin pages.

Clean URLsBy default, Drupal uses and generates URLs for your site's pages that look like"http://www.example.com/?q=node/83." This style of URLs can be hard to read, and can preventsome search engines from indexing all the pages of your site. Research suggests this may not be asgreat an issue for some of the major search engines as it once was; however, it is worth noting therecommendation from Google's webmaster guidelines stating:

If you decide to use dynamic pages (i.e., the URL contains a "?" character), be awarethat not every search engine spider crawls dynamic pages as well as static pages. Ithelps to keep the parameters short and the number of them few.

If you are unhappy with the default URLs in Drupal, you may be able to tell Drupal to use "cleanURLs", eliminating the "?q=" in your site's URLs, and this page explains how to do it. Theinstructions below are largely applicable only for the most common server setup, which is anApache web server running on some flavor of Unix/Linux, with the mod_rewrite Apache moduleconfigured and mod_rewrite enabled in httpd.conf configuration file. If you are running Drupal ona different type of server, check the links section below (just above the Comments section of thispage) to see if there might be something that addresses your server configuration on a differentpage.

Before enabling clean URLs in the Drupal configuration screens (see below), you may need toprepare your server for clean URLs to work. There are two ways to prepare your server for cleanURLs to work in Drupal. If you have complete control of your server, for example because yourun your own server, are installing a development site on your personal computer, or have adedicated server hosting account, then you should enable clean URLs in the httpd.conf file forbetter performance and security. However, if you have a shared hosting account (at DreamHost,BlueHost, HostGator, GoDaddy, 1and1, et al.), you will not be able to modify the httpd.conf fileand should use the Drupal .htaccess file instead.

Enabling Clean URLs in DrupalNote: The standard Drupal installation contains a sample .htaccess file which supports cleanURLs. It is easy to miss copying this file, because of the leading "dot". So before trying to enableClean URLs, make sure this file exists in your Drupal installation.

Drupal 6.x

In Drupal 6, the installer tests for compatibility with Clean URLs as a part of the installationprocess. If the installer was not able to run the test successfully at install time, you can later followthe instructions below for Drupal 5 to get Clean URLs working. There is one minor difference:Drupal 6 will run the clean URL test automatically when you navigate to the Clean URLsconfiguration page and will show the results, in place of giving you a link to run the test manually.

Also note that even if Clean URLs are successfully enabled at install-time, if you have a dedicatedserver you may still want to follow the steps below to enable the more efficient httpd.conf rewritemethod for clean URLs. If you choose to do that, you might want to turn off Clean URLs whileyou are working on the server.

Drupal 5.x

Here are the steps necessary to enable Clean URLs in Drupal 5:

1. Goto the administer >> site configuration >> clean urls section of the administrative

Page 73: Drupal - Installation Guide

interface.2. Look for the paragraph that reads as follows:

This option makes Drupal emit "clean" URLs (i.e. without ?q= in the URL.)Before enabling clean URLs, you must perform a test to determine if yourserver is properly configured. If you are able to see this page again afterclicking the "Run the clean URL test" link, the test has succeeded and the radiobuttons above will be available. If instead you are directed to a "Page notfound" error, you will need to change the configuration of your server. Thehandbook page on Clean URLs has additional troubleshooting information. Runthe clean URL test.

3. Click on the Run the clean URL test link at the end of the above paragraph.4. If the test is successful, set Clean URLs to "enabled" and save the configuration. If the test

is not successful, use the steps below to fix your server configuration and try again.

Prior to Drupal 5.x

For Drupal versions prior to Drupal 5, there is no automatic Clean URLs test or link. Instead, youcan test manually by typing in the Clean URL for your settings page:http://www.example.com/admin/settings (where www.example.com is replaced by yourhostname). If this results in seeing the settings page, and no errors, then Clean URLs are safe toenable, and you can do so with the setting on this page. If there is an error, follow the instructionsbelow to configure your server.

Error recoveryEnabling "Clean URLs" when your server is not properly configured (i.e. if the Clean URLs testsdescribed above fail) can make it difficult to navigate back to administration pages to undo yourmistake, because all the Drupal-generated menus and links will have URLs that do not work. Ifyou find yourself in this situation, you can return to the administrative settings page by typing inthe URL in the 'non-clean' form: http://www.example.com/?q=admin/settings for the adminsettings page in Drupal 4.x, or http://www.example.com/?q=admin/settings/clean-urls toget to the Drupal 5 or Drupal 6 Clean URLs settings page. Once there, you should be able to resetto not using Clean URLs.

There are additional instructions for recovering from malfunctioning Clean URLs the Handbookpage Unset clean URLs.

Server configuration for Clean URLs on a dedicated server,with httpd.confEnabling clean URLs on a dedicated server involves these steps:

1. Enable mod_rewrite for Apache. You can talk to your web host or consult the Apachedocumentation for mod_rewrite to get more information on how to do this. At a minimum,this will involve making sure that mod_rewrite is enabled for your installation of Apache.

To test if mod_rewrite is available in Apache2, you can type the following at a commandprompt, to list all installed Apache modules:

apache2ctl -M

On some systems this command may be:

apachectl -M

In the output, check to see if the rewrite_module is included in the list of modules.

If the rewrite module is not in the list, it will have to be either compiled-in or madeavailable as a loadable module. Generally speaking, you can tell Apache to load the moduleby including

LoadModule rewrite_module modules/mod_rewrite.soAddModule mod_rewrite.c

in your Apache configuration file (see below for information on the configuration file). Besure to uncomment AddModule mod_rewrite.c, if it is in your configuration file but hasbeen commented out. The following may work to enable the module without editing anyfiles:

a2enmod rewrite

Note that these approaches may not work for all combinations of operating system andApache server -- consult the Apache documentation that came with your Apache softwarefor the correct syntax.

Remember to restart Apache for the new configuration to take effect.

2. The next step is to locate the appropriate Apache configuration file for your site. Dependingon your server configuration, the appropriate Apache configuration file could be httpd.conf,a virtual-host-specific file (vhost.conf), a specific site file (e.g. "default"), or apache2.conf.They are usually located in /etc/httpd/conf, /etc/apache2, or a sub-directory; if not, try

Page 74: Drupal - Installation Guide

the command:find /etc -name httpd*

to find the file if it is located elsewhere in your file system.

If you do not have write permissions to these files, and Clean URLs are notworking out-of-the-box for you, you may have to ask your systemsadministrator or hosting provider for help. You may still be able to read theseconfiguration files to troubleshoot a little however.

3. The next step is to copy or include the Drupal-specific settings directly into yourconfiguration file. There are instructions here for how to include the Drupal directives inyour configuration file. Consult the .htaccess file in Drupal page for examples of rules, suchas the following:<Directory /var/www/example.com> RewriteEngine on RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]</Directory>

Note: If you do not want to put the rewrite rules in your Apache configuration file, you can stillsimply use the Drupal .htaccess file (as you would if you were on shared hosting). You will needto have the Allow Override directive set in your Apache configuration file (this will allow local.htaccess overrides on your site):

AllowOverride AllAccessFileName .htaccess

Read "Behind the scenes with Apache's .htaccess for a thorough review of .htaccess; this other sitehas samples of Apache 2 directives.

Note Regarding MultiViews: Apache supports a feature called "MultiViews" (more generally:"Content Negotiation"), which allows navigation to your pages without the need for fileextensions. For instance, if you had a file called "evaluation.txt", a MultiViews-enabled site couldaccess this file with the URL "example.com/evaluation". While MultiViews can be a handyfeature when used knowingly, it can cause problems when Drupal's Clean URLs are enabled.Unless you know what you're doing, you should not use MultiViews if you plan to use the CleanURLs feature of Drupal. However, MultiViews is not enabled in a default Apache installation, soit is likely that this note will not apply. Consult the Apache documentation for further informationabout MultiViews.

Server configuration for Clean URLs on a shared server, with.htaccessThe standard Drupal installation contains a sample .htaccess file which should be sufficient to getClean URLs running. It is easy to miss copying this file, because of the leading "dot". So beforetrying to enable Clean URLs, make sure this file exists in your Drupal installation.

If you have this file installed, but Clean URLs still do not work, you can try some of thetroubleshooting suggestions below. If you still cannot get Clean URLs to work, contact yourhosting provider.

Fixing problems

Check .htaccess is even being used

Apache needs to be explicitly told to respect the instructions in your sites .htaccess file. This is offby default, though most hosts will have turned it on. That is what the AllowOverride Alldirective above does - it makes .htaccess start working.

To check if your host is currently even reading your .htaccess, you can (temporarily) add somegarbage string to the file in an attempt to break it. Your site should immediately start returning a"500 Server Error" when you load a page from that directory due to this misconfiguration.(Remove the garbage string immediately)

If you do this, and your site does not break - then .htaccess is being ignored and you will not beable to use clean URLs until you get support from your hosts. Some hosts allow you to enable thisoption through their site management control panel, so look there first.

RewriteBase setting

The main configuration option which may need to be changed for your site is the RewriteBase.This can be specified in the Drupal .htaccess file or in the httpd.conf file, depending on where youare putting the Drupal rewrite directives (see above). By default, the RewriteBase setting iscommented out of the Drupal .htaccess file, and that works well for many configurations.

If you are having trouble getting Clean URLs to work, you may need to change this setting. Forexample, if your Apache DocumentRoot is /var/www/ (i.e., /var/www/index.html is what isdisplayed when you point your browser at http://www.example.com/) and your Drupalinstallation is installed in the subdirectory /var/www/mysite/, then the RewriteBase could be setto

Page 75: Drupal - Installation Guide

RewriteBase /mysite

and that might help. In some configurations, settingRewriteBase /

will allow clean URLs to work.

Multi-site

RewriteBase works when your Drupal installation serves only one site, or when all the sites itserves are in the same subdirectory of their domains. For example,

RewriteBase /

will work for the following sites:

http://www.example.com/http://www.example2.com/http://www.example3.com/

And

RewriteBase /mysite

will work for the following sites:

http://www.example.com/mysitehttp://www.example2.com/mysitehttp://www.example3.com/mysite

However, if your sites are in different subdirectories, RewriteBase will not work. You will needto create a special rule for each subdirectory. For example, your Drupal installation may serve thefollowing sites:

http://www.example.com/http://www.example.com/mysite

In order to enable clean URLs for both sites, you will need to add

RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteCond %{REQUEST_URI} ^/mysite/(.*)$RewriteRule ^(.*)$ /mysite/index.php?q=$1 [L,QSA]

before the existing rewrite rules.

Location of index.php

For some server configurations, another change to the Drupal .htaccess file may be necessary.Find a line that looks like this, near the end of your Drupal .htaccess file:

RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

You may need to replace index.php with the URL path to your Drupal installation's index.phpfile (only the part after the base URL). For instance, if your site's home page URL ishttp://example.com/subdir/, you might need to use /subdir/index.php instead ofindex.php. If your site's home page URL is http://example.com/, you might need to use/index.php instead of index.php. This is necessary on some, but not all server configurations.

Even cleaner URLs with the Path ModuleUsing Clean URLs will cause Drupal to generate URLs in the form"http://www.example.com/node/83." In order to change the 'node/number' portion of the URL tosomething more like 'news/june-1st-news' a site will need the Path module enabled. See the Pathmodule handbook page for more information on using the path module.

A step-by-step process for enabling cleanURLsI am running vmware workstation with Ubuntu 8.10 with LAMP and Drupal 6.6.

How I was able to enable clean URLs.

1. Enable the Apache Module

Open Terminal and type:

apache2ctl -M

to see if rewrite_moduleis there. If it is not there, first go to the file browser and navigate to/etc/apache2/mods-available

Page 76: Drupal - Installation Guide

folder and confirm that rewrite.load exists. If it does not exist, then the rest of this won't helpuntil it does.

If it does exist, we need to create a symlink from mods-enabled to mods-available. So in Terminaltype or copy/paste:

cd /etc/apache2/mods-enabledln -s ../mods-available/rewrite.load

(that first letter is a lowercase L )If permission is denied, put sudo before lnsudo ln -s ../mods-available/rewrite.load

2. Check the Apache Module

Confirm that rewrite.load is now in the mods-enabled folder by opening the folder and findingit, or typing into Terminal

apache2ctl -M

So far so good? Great!

3. Enable AllowOverride All

Next we need to open sites-enabled in the apache2 folder:/etc/apache2/sites-enabledand right-click the 000-default file and click the permissions tab. If the access is read-only, openTerminal and type:

sudo nautilus /etc

Doing that pops up the file browser as root. Navigate to 000-default again:/etc/apache2/sites-enabled/000-defaultRight-click again, go to permissions and change all the read only's to read and write (minechange back automatically after I close the file directory but you might want to double-check.)

In this file it will say AllowOverride None in several places, each time inside of a differentDirectory tag. Find the one for where you've installed Drupal, and change it to AllowOverrideAll. For instance, if Drupal is installed at /home/username/www/drupal6, then it may be underthe Directory "/home/username/www" grouping.

Explanation AllowOverride All is an Apache directive that tell it to read and setany of the instructions found in .htaccess files. On some servers this is restricted -allowing you to change the error document, but not the directory indexes for example.The .htaccess file that comes with Drupal expects to be able to set a few (reasonablysafe) overrides, so we tell Apache to obey (allow) these instructions.

After this, open Terminal and and restart apache by typing:

sudo /etc/init.d/apache2 restart

You must restart Apache after every change you make to the apache files (if you expect to seechanges in Drupal, for example).

Last but not least, I COULD VERY WELL BE WRONG AND DOING SOMETHINGQUITE AWFUL, but it did work for me.

I figured this out after finding these two sites: http://www.jonathansblog.net/node/22 andhttp://linux.derkeiler.com/Mailing-Lists/Debian/2005-03/2483.html

~Admerin

Configuring clean URLs for various systemsThis section provides instructions for configuring clean URLs on specific hosts.

Apache 2 configuration of clean URLs onDebianNote: This article needs to be updated for Debian "Etch" and "Lenny"releases. (as of March 2009)

If you're running Apache 2 on Debian stable, in order to install the rewrite module you simplyneed to:

# a2enmod rewrite

then restart the webserver:

# /etc/init.d/apache2 restart

then edit either /etc/apache2/sites-enabled/drupal or to your .htaccess and ensure it lookssomething like this:

Page 77: Drupal - Installation Guide

## Apache/PHP/site settings:#

# Protect files and directories from prying eyes:<Files ~"(\.(conf|inc|module|pl|sh|sql|theme|engine|xtmpl)|Entries|Repositories|Root|scripts|updates)$"> order deny,allow deny from all</Files>

# Set some optionsOptions -IndexesOptions +FollowSymLinks

# Customized server error messages:ErrorDocument 404 /index.php

# Set the default handler to index.php:DirectoryIndex index.php

# Overload PHP variables:<IfModule sapi_apache2.c> # If you are using Apache 2, you have to use <IfModule sapi_apache2.c> # instead of <IfModule mod_php4.c>. php_value register_globals 0 php_value track_vars 1 php_value short_open_tag 1 php_value magic_quotes_gpc 0 php_value magic_quotes_runtime 0 php_value magic_quotes_sybase 0 php_value arg_separator.output "&amp;" php_value session.cache_expire 200000 php_value session.gc_maxlifetime 200000 php_value session.cookie_lifetime 2000000 php_value session.auto_start 0 php_value session.save_handler user php_value session.cache_limiter none php_value allow_call_time_pass_reference On</IfModule>

# Various rewrite rules<IfModule mod_rewrite.c> RewriteEngine on Options All

# Modify the RewriteBase if you are using Drupal in a subdirectory and the # rewrite rules are not working properly: RewriteBase /drupal

# Rewrite old-style URLS of the form 'node.php?id=x': RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{QUERY_STRING} ^id=([^&]+)$ RewriteRule node.php index.php?q=node/view/%1 [L]

# Rewrite old-style URLs of the form 'module.php?mod=x': RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{QUERY_STRING} ^mod=([^&]+)$ RewriteRule module.php index.php?q=%1 [L]

# Rewrite URLs of the form 'index.php?q=x': RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]</IfModule>

# $Id: .htaccess,v 1.58 2004/10/09 20:41:49 dries Exp $

This is because the debian package installs the drupal "sites-enabled" virtual host, result being thatdrupal is accessed from http://example.com/drupal, hence the need to uncomment RewriteBase.Change it to the base that corresponds to your system.

ref: http://www.debian-administration.org/articles/136http://drupal.org/node/14322

--Sean K. O'BrienCTOColley Graphics, LLChttp://www.colleygraphics.com

Apache 2 on Debian Lenny w/BackportsDrupal 6.16 (and Squeeze)These instructions enable you to configure apache2 to support Drupal's Clean URLs for a defaultlenny backports installation of drupal 6 (currently drupal6 6.16-1~bpo50+1). Therefore, theseinstructions should also cleanly work for Debian Squeeze (currently in testing). The defaultinstallation serves drupal 6 as http://localhost/drupal6/. These instructions may work for earlierversions of Drupal 6 on Lenny and possibly Etch and possibly Ubuntu versions. Please comment ifyou have success with these other versions.

Page 78: Drupal - Installation Guide

For information about Debian Backports, visit http://www.backports.org/.

How To

To enable Clean URLs in the defalt configuration, first, ensure that the apache2 "Rewrite Module"is enabled:

sudo a2enmod rewrite

Next, edit one and only one file, /etc/apache2/conf.d/drupal6.conf, and make these modswithin the <Directory> block (careful, this file is a symlink: /etc/apache2/conf.d/drupal6.conf ->/etc/drupal/6/apache.conf):

1. Change AllowOverride to None2. Add the Rewrite Module directive RewriteBase, setting it to /drupal63. Include the default drupal 6 .httaccess file, /usr/share/drupal6/.htaccess.

The modified /etc/apache2/conf.d/drupal6.conf file will now look like this (changes in bold-italic):

Alias /drupal6 /usr/share/drupal6

<Directory /usr/share/drupal6/> Options +FollowSymLinks# AllowOverride All AllowOverride None order allow,deny allow from all <IfModule mod_rewrite.c> RewriteBase /drupal6 </IfModule> Include /usr/share/drupal6/.htaccess</Directory>

After changing the file, restart apache2 with the command:

sudo /etc/init.d/apache2 restart

Then navigate to your drupal adminstrative site configuration Clean URLs page, ensure that thesystem is correctly configured, and then enable Clean URLs and test.

Discussion

Changing AllowOveride to None and including the .htaccess file within the <Directory>means that Apache2 will only load the .htaccess file once (at startup).

I recommend against the practice of adding more AllowOveride All directives because this willcause apache2 to read the .htaccess file on every web request, instead of just once on startup.

The RewriteBase /drupal6 directive appears as a comment in the/usr/share/drupal6/.htaccess file, but I recommend putting the directive in theconf.d/drupal6.conf file because why change more config files than necessary?

Apache 2 on UbuntuThere are two methods for setting up Drupal 5.x/6.x with Apache on Ubuntu. The first (preferred)method edits the 'Virtual Host configuration, which is the default setup on Ubuntu (even for asingle-site webserver). The second edits the main apache2.conf, which is typical for an oldersetup.

Method 1: 'Virtual Host' setupFirst, from the linux command line, enable the rewrite module for apache with this command:

sudo a2enmod rewrite

Next, use an editor (such as nano) to edit the appropriate Apache configuration file for yourDrupal site in the /etc/apache2/sites-available/ directory. For a single site, the file is/etc/apache2/sites-available/default; if you have multiple sites, the file names shouldreflect the names of the sites to which they refer. Thus, to edit the default site configuration, use

sudo nano /etc/apache2/sites-available/default

Look for the Directory section referring to the folder where your Drupal site lives (in/etc/apache2/sites-available/default, this is typically <Directory /var/www>), andchange the line:

AllowOverride None

to

AllowOverride All

(See https://help.ubuntu.com/community/EnablingUseOfApacheHtaccessFiles for moreinformation).

Page 79: Drupal - Installation Guide

Save this file and then reload apache.

sudo /etc/init.d/apache2 reload

Sub Domain Setup

An alternative to multiple virtual hosts files is to use subdomains. This allows you to use a wild-card in the Server Alias. This allows for both a simple multi-site Drupal setup, as well as multiDrupal versions. Instead of multiple virtual hosts files, you define a subdomain for each drupalprofile.

Consider the following and modify your configuration file to fit your needs.

1. http://myproject.dr5.example/2. http://myproject.dr6.example/3. http://myproject2.dr6.example/

Here is an example of a partial listing of a virtual host configuration file that would support thelast two lines in the above example. Note this is not intended to be a COMPLETE configurationfile, but rather provide guidance for your development setup.

<VirtualHost *>DocumentRoot "/www/Dr6"ServerName exampleServerAlias *.dr6.example

<Directory "/www/Dr6">AllowOverride All</Directory>

Edit & save your config file to suit your development needs. Assuming the site is already enabled,then reload Apache.

Method 2: apache2.confThen you have to enabled the rewrite module(mod_rewrite). You no longer have to do the:LoadModule rewrite_module modules/mod_rewrite.soAddModule mod_rewrite.c

It's now as easy as:sudo a2enmod rewrite

To disable this module it's just:sudo a2dismod rewrite

with Apache version 2, the httpd.conf has been deprecated and the new file is located at:/etc/apache2/apache2.conf

in this file you need to add your directory and the allow override to give access to your drupal site.so look for a section in your apache2.conf that has Directory tags and just add another section:

<Directory /var/www/drupal_website_install> AllowOverride all</Directory>

*keep in mind that my website is in a subdirectory (drupal_website_install) and so you may needto edit the above to reflect this. By this I mean if i go into my webbrowser I need to go tohttp://localhost/drupal_website_install/

After you edit you apache2.conf as listed above you need to restart the server by:/etc/init.d/apache2 reload

Problems with RewriteIf you are having problems with getting your rewrite to work you can always use logging. To dothat add this to the end of /etc/apache2/apache2.conf:

RewriteLog "/var/log/apache2/rewrite.log"RewriteLogLevel 3

Level 0 is no loggingLevel 9 is log everythingYou can pick the level to determine the amount of output you need.***Security Warning: Make sure to take the log code out, disable it, or put the log file in adirectory that can't be read by normal users (as shown above) otherwise it can result in a securitybreach.***hopefully this helps some people and saves them the time that I spent trying to get it working.

Finish - Enable Clean URLsNow browse to your site, login, click administer, find "Clean URLs" and browse to that page, runthe test for "Clean URLs" (In Drupal 4.6 - 5.x this is buried in the paragraph explaining "cleanUrls").

If your setup is like mine, you should now have Clean URLs in drupal.

Page 80: Drupal - Installation Guide

Boost .htaccess for clean urls on specificshared hostsThis code was taken from the Boost module and modified just a little bit. Please note that thisimplements a static cache of pages for anonymous users on your site. Read the Boostdocumentation to understand what this means.

Various users have reported that this .htaccess file works on the following hosts:

1and1.combyethost.comdotsterehostpros.comehosting.cahostmonster.comIXWebhosting.commediatemple.netsiteground.comSite5.comgodaddy.com

There is no guarantee this will work for you though.

Instructions:

Create a text file, copy and paste the code below and save it as .htaccess

Upload the file and put it in the public_html directory of your site.

Modify "RewriteBase /" in line 68 to "RewriteBase /example" if your site is in subdirectory"example."

## Apache/PHP/Drupal settings:#

# Protect files and directories from prying eyes.<FilesMatch "(\.(engine|inc|install|module|sh|.*sql|theme|tpl(\.php)?|xtmpl)|code-style\.pl|Entries.*|Repository|Root)$"> Order deny,allow Deny from all</FilesMatch>

# Set some options.Options -IndexesOptions +FollowSymLinks

# Customized error messages.ErrorDocument 404 /index.php

# Set the default handler.DirectoryIndex index.php

# Override PHP settings. More in sites/default/settings.php# but the following cannot be changed at runtime.

# PHP 4, Apache 1<IfModule mod_php4.c> php_value magic_quotes_gpc 0 php_value register_globals 0 php_value session.auto_start 0</IfModule>

# PHP 4, Apache 2<IfModule sapi_apache2.c> php_value magic_quotes_gpc 0 php_value register_globals 0 php_value session.auto_start 0</IfModule>

# PHP 5, Apache 1 and 2<IfModule mod_php5.c> php_value magic_quotes_gpc 0 php_value register_globals 0 php_value session.auto_start 0</IfModule>

# Reduce the time dynamically generated pages are cache-able.<IfModule mod_expires.c> ExpiresByType text/html A1</IfModule>

# Various rewrite rules.<IfModule mod_rewrite.c> RewriteEngine on

# If your site can be accessed both with and without the prefix www. # you can use one of the following settings to force user to use only oneoption: # # If you want the site to be accessed WITH the www. only, adapt and uncomment

Page 81: Drupal - Installation Guide

the following: # RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC] # RewriteRule .* http://www.example.com/ [L,R=301] # # If you want the site to be accessed only WITHOUT the www. , adapt anduncomment the following: # RewriteCond %{HTTP_HOST} !^example\.com$ [NC] # RewriteRule .* http://example.com/ [L,R=301]

# Modify the RewriteBase if you are using Drupal in a subdirectory and # the rewrite rules are not working properly. RewriteBase /

# Rewrite old-style URLs of the form 'node.php?id=x'. #RewriteCond %{REQUEST_FILENAME} !-f #RewriteCond %{REQUEST_FILENAME} !-d #RewriteCond %{QUERY_STRING} ^id=([^&]+)$ #RewriteRule node.php index.php?q=node/view/%1 [L]

# Rewrite old-style URLs of the form 'module.php?mod=x'. #RewriteCond %{REQUEST_FILENAME} !-f #RewriteCond %{REQUEST_FILENAME} !-d #RewriteCond %{QUERY_STRING} ^mod=([^&]+)$ #RewriteRule module.php index.php?q=%1 [L]

# Rewrite rules for static page caching provided by the Boost module # BOOST START <IfModule mod_mime.c> AddCharset utf-8 .html </IfModule> RewriteCond %{REQUEST_URI} !^/cache RewriteCond %{REQUEST_URI} !^/user/login RewriteCond %{REQUEST_URI} !^/admin RewriteCond %{HTTP_COOKIE} !DRUPAL_UID RewriteCond %{REQUEST_METHOD} ^GET$ RewriteCond %{QUERY_STRING} ^$ RewriteCond %{DOCUMENT_ROOT}/cache/%{SERVER_NAME}/0/%{REQUEST_URI} -d RewriteCond %{DOCUMENT_ROOT}/cache/%{SERVER_NAME}/0/%{REQUEST_URI}/index.html-f RewriteRule ^(.*)$ cache/%{SERVER_NAME}/0/$1/index.html [L] RewriteCond %{REQUEST_URI} !^/cache RewriteCond %{REQUEST_URI} !^/user/login RewriteCond %{REQUEST_URI} !^/admin RewriteCond %{HTTP_COOKIE} !DRUPAL_UID RewriteCond %{REQUEST_METHOD} ^GET$ RewriteCond %{QUERY_STRING} ^$ RewriteCond %{DOCUMENT_ROOT}/cache/%{SERVER_NAME}/0/%{REQUEST_URI}.html -f RewriteRule ^(.*)$ cache/%{SERVER_NAME}/0/$1.html [L] # BOOST END

# Rewrite current-style URLs of the form 'index.php?q=x'. RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]</IfModule>

# $Id: boosted.txt,v 1.4 2006/12/05 10:39:19 arto Exp $

Drupal 6.xThis .htaccess code works just fine for Drupal 6.4 BUT any internal links in the form'directory/file.xxx' or just 'file.xxx' need to be changed to include a leading '/'.

Clean URL Support in AbyssThis clean URL implementation has been tested on Abyss X1, one which has a properly setCustom Error Page 404 to any arbitrary file that, for this purpose, will be referenced as"/url_rewrite.php". Due to the generalized design of this solution, this method could theoreticallywork on virtually any webserver that can redirect missing URI location onto a php resource. Themethod described here works only on webservers with a singular host configuration.

One esoteric requirement is for the webserver to pass the server variable REQUEST_URIcontaining the value of the original resource requested. For more information on configuringAbyss X1 for this purpose, please visit this Aprelium forum resource.

This solution could be rendered academic if Aprelium finally decides to implement URL rewrite inAbyss internally. This method is useful for Abyss webservers version 2.3.2 and most otherversions prior to this specific release. Another drawback is that the URL rewrite becomes onlyinvisible to the machine but is always visible to the human.

The idea is to pass (or redirect) the missing URI location on the HTTP-404 handler"/url_rewrite.php". For illustrative examples, let's look at the following scenarios:

1. http://www.example.com/node/add => "/node/add" not found, pass to 404 handler"/url_rewrite.php" => "/url_rewrite.php" determines "/index.php?q=node/add" exists andserves that instead.

2. http://www.example.com/admin/settings => "/admin/settings" not found, pass to 404 handler"/url_rewrite.php" => "/url_rewrite.php" determines "/index.php?q=admin/settings" existsand serves that instead.

3. http://www.example.com/no_exist/location => "/no_exist/location" not found, pass to 404

Page 82: Drupal - Installation Guide

handler "/url_rewrite.php" => "/url_rewrite.php" determines "/index.php?q=no_exist/location" exists and serves that instead but lets Drupal display the proper "pagenot found" informational message.

Here are the steps in letting this method apply to your setup.

1. Create the following file and save it as "/url_rewrite.php".<?php/* Add in this array the list of (old path => new path) pairs */$redirection = array( '^(.*)$' => 'index.php?q=$1');if (!file_exists($_SERVER["REQUEST_URI"]))/* Get the URI and trim leading slashes */$uri = ltrim($_SERVER["REQUEST_URI"], "/");{foreach ($redirection as $key => $value){ if (eregi($key, $uri)) { /* Convert the replacement string syntax - $1 -> \1 */ /* and perform the substitution */ $uri = str_replace("index.php","",substr($uri,0)); $new_uri = str_replace("?","&",$uri); $new_uri = "/index.php?q=".$new_uri; $new_uri = str_replace("%26","&",$new_uri); break; }}}if (isset($new_uri)){ header("Status: 307"); header("Location: $new_uri"); exit;}?><!-- Your 404 error page --><HTML><HEAD><TITLE>Not Found</TITLE></HEAD><BODY>The object <tt><?php echo $uri; ?></tt> is not available.</BODY></HTML>

2. In the Abyss web console, enter the Custom Error Pages, add a 404 Status Code entry withthe Associated URL value "/url_rewrite.php". Click OK and restart the Abyss webserver.

3. Test for functionality by querying your website directly with URI's such as:http://www.example.com/admin/settingshttp://www.example.com/node/add

If the redirection works properly, proceed to the next steps. If the redirection would notwork, check if the steps above have been strictly followed. Modify only those things thatyou have absolute knowledge of.

4. Log on to your website and log on to your "/admin/settings" page. Under General Settingssection, enable Clean URLs. If the Clean URLs option is grayed out, add the line"$conf['clean_url'] = 1;" in your settings.php, then repeat this step. Don't forget to click the"Save configuration" button.

5. If things do not work out, completely remove the line "$conf['clean_url'] = 1;" from yoursettings.php. And browse to your http://www.example.com/index.php?q=admin/settingspage to disable Clean URLs properly.

"No Tricks" Clean URL Support in Abyss 2.4and laterVersion 2.4 of Abyss and later offers native URL rewriting support, so using tricks with 404 pagesas outlined on this page is no longer necessary. Here's a better way to do it.

1. Log in to the Web Server Console at http://localhost:9999/ .2. Click the "Configure" button next to the relative host in the list.3. Click on the "URL Rewriting" icon.4. The "URL Rewriting Rules" list will probably be blank. Click the "Add" button at the

bottom to add a new rule.5. Our first rule is going to tell Abyss to not rewrite paths that are comprised of just a slash, or

which contain a dot in them. (Or, more correctly, to rewrite them in exactly the way it foundthem.) The former are going to be requests for your home page, and the latter are mostlikely going to be requests for files which we don't want to pass through Drupal, likeimages, JavaScript files, etc. In the "Virtual Path Regular Expression" field, enter this:(^/$|(.*)\.(.*))

6. Make sure that the "If this rule matches" menu is set to "Perform an internal redirection,"and enter simply this in the "Redirect to" field:$0

7. Check the "Append Query String" box.8. From the "Next Action" menu, select "Stop matching."9. All other check boxes should be left unchecked. Click OK.

10. Abyss will take you back to the "URL Rewriting Rules" list, and probably give you a

Page 83: Drupal - Installation Guide

message that it wants to restart. Ignore it for now until we add the second rule. Click the"Add" button again.

11. In the "Virtual Path Regular Expression" field, enter:^([^\?]*)$

12. Again, we want to "Perform an internal redirection." Put this in the "Redirect to" field:/index.php?q=$1

13. Again, check the "Append Query String" checkbox, and set "Next Action" to "Stopmatching." Click OK.

14. Now, if you see the two rules you created above in the URL Rewriting Rules list, takeAbyss up on its offer to restart the server.

15. Visit your site in a web browser, log in as an administrator, open up the "Clean URLs" pagein the "Site configuration" section, cross your fingers, and turn on clean URLs.

Incidentally, we've found that Abyss works quite well with Drupal when configured this way;however, it was unable to cope with the volume of traffic our site was receiving, and oftenresponded with page load times well into the double digits. I would not recommend using Abyssfor anything but the most lightly-trafficked Drupal installations.

CautionThere are some apparent weaknesses in the approach listed above as: ^/$|(.*)\.(.*). If we usedDrupal's URL aliases feature, for example node 125 is aliased as"/mr.edmons_approach_to_the_tuna_recipe", the rewrite would fail as Abyss would be looking fora physical resource named "/mr.edmons_approach_to_the_tuna_recipe". A better approach hasbeen described in this Abyss forum resource http://www.aprelium.com/forum/viewtopic.php?t=14948.

In addition, the approach used in that solution transforms requests like ^(.*)\?(.*)=(.*)$ into/index.php?q=$1&$2=$3 to support multi-page indexes. And then, it uses REQUEST_FILENAME Isnot a directory and REQUEST_FILENAME Is not a file as conditions, making it moreaccurate in leaving the file and directory requests intact.

Via this approach, special cases can also be covered for Drupal installations located in subpaths.

Clean URL support in XAMPPClean URLs do not work out of the box on XAMPP 1.5.x with PHP4 due to a problem inApache's module load order; mod_rewrite will not work properly. To remedy this you will need toedit the file [path_to_xampp]/apache/conf/httpd.conf.

mod_rewrite location

Remove the # at the beginning of this line:

LoadModule rewrite_module modules/mod_rewrite.so

and move it to just above or below#LoadModule cache_module modules/mod_cache.so

AllowOverride

If the mod_rewrite change does not work, you also need to check that AllowOverride All is setfor the directory Drupal is in. Do this in httpd.conf or extra/httpd-xampp.conf

Open up file \apache\conf\extra\httpd-xampp.conf

Put this code in:

Alias /drupal "C:/Program Files/xampp/htdocs/drupal/" <Directory "C:/Program Files/xampp/htdocs/drupal"> AllowOverride All Order allow,deny Allow from all </Directory>

Remember to change the path to match your installation location.

If you're not sure where to add it, it might be worth putting it under the entry

Alias /security "C:/Program Files/xampp/security/htdocs/" <Directory "C:/Program Files/xampp/security/htdocs"> ... ... </Directory>

which should already exist.

Always restart Apache after you make changes or the changes to its configuration files won'thave an effect.

Drupal Directory

If Drupal is not installed in the document root, the next thing you'll have to do is modify the file.htaccess that comes with Drupal. Remove the commentsign (#) in front of RewriteBase and, if

Page 84: Drupal - Installation Guide

necessary, modify the path:

RewriteBase /drupal

Finally, in Drupal go to Administer » Site Configuration » Clean URLs (admin/settings/clean-urls)and run the clean URL test. Then click the "Enabled" option for Clean URLs and save the settings.

Clean URLs in Mac OS X ServerFor Mac OS X Server 10.4 (Tiger Server) and most likely previous versions as well, do not makechanges to /etc/httpd/httpd.conf expecting the AllowOverride All directive to work. Thecorrect file to add the AllowOverride All directive is in the directory /etc/httpd/sites/. Inthat directory are the virtual host configuration files. Each virtual server has a configuration file inthat directory so it is in those files that you must enable AllowOverride All. If you only have oneweb server on your server configured, then the file you want to modify is/etc/httpd/sites/0000_any_80_.conf.

Clean URLs on IISDrupal can display brief, "clean" URLs like those at drupal.org. For Apache sites, mod_rewritepowers this feature. On IIS you'll use either a third-party module or (on IIS7) Microsoft's URLRewrite module to add this functionality. Refer to your specific IIS version below for details.

Some Third Party ISAPI Rewrite ModulesISAPI Rewrite by Helicon software. There is a free "lite" and a paid version. IIS Aid has anarticle on configuring the Helicon module. There is also an important note about .htaccessfiles with ISAPI_Rewrite 3 here.

Check this thread for some approaches to setting up ISAPI_Rewrite.

Ionic's ISAPI Rewrite FilterMicronovae's IIS Mod-Rewrite (the "standard" version works w/IIS5) (documentation).

IIS7The best method is Microsoft's URL Rewrite Module for IIS7, available via the Web PlatformInstaller on Windows Server 2008 and Vista. Download and documentation are also available onMicrosoft's IIS.Net site. You can also use third party rewrite modules (see list above).

Note: Service Pack 2 for Windows Server 2008 & Vista contained important IIS7 bug fixes(KB954946) that affect how REQUEST_URI works. You can download the patch individually orSP2 from the MS website. IIS7 URL Rewrite Home contains useful explanations and links,including a walkthrough video.

You will also need to enable (if you haven't already) FastCGI.

After setting up the rewrite module and enabling FastCGI you will need to edit your site'sweb.config file. On IIS7, the web.config file replicates and replaces the functionality of .htaccess(which is included in your Drupal distribution). Here is the web.config file provided with theAcquia Drupal distribution for your reference (if you used the Acquia Drupal Web PlatformInstaller this is already included):

<?xml version="1.0" encoding="UTF-8"?><configuration> <system.webServer> <!-- Don't show directory listings for URLs which map to a directory. --> <directoryBrowse enabled="false" />

<!-- Caching configuration was not delegated by default. Some hosters may notdelegate the caching configuration to site owners by default and that may cause errors whenusers install. Uncomment this if you want to and are allowed to enable caching --> <!-- <caching> <profiles> <add extension=".php" policy="DisableCache"kernelCachePolicy="DisableCache" /> <add extension=".html" policy="CacheForTimePeriod"kernelCachePolicy="CacheForTimePeriod" duration="14:00:00" /> </profiles> </caching> -->

<rewrite> <rules> <!-- rule name="postinst-redirect" stopProcessing="true"> <match url="." /> <action type="Rewrite" url="postinst.php"/> </rule -->

<rule name="Protect files and directories from prying eyes"

Page 85: Drupal - Installation Guide

stopProcessing="true"> <matchurl=".(engine|inc|info|install|module|profile|test|po|sh|.sql|postinst.1|theme|tpl(.php)?|xtmpl|svn-base)$|^(code-style.pl|Entries.|Repository|Root|Tag|Template|all-wcprops|entries|format)$" /> <action type="CustomResponse" statusCode="403" subStatusCode="0"statusReason="Forbidden" statusDescription="Access is forbidden." /> </rule> <rule name="Force simple error message for requests for non-existentfavicon.ico" stopProcessing="true"> <match url="favicon.ico" /> <action type="CustomResponse" statusCode="404" subStatusCode="1"statusReason="File Not Found" statusDescription="The requested file favicon.icowas not found" /> </rule> <!-- To redirect all users to access the site WITH the 'www.'prefix, http://example.com/... will be redirected tohttp://www.example.com/...) adapt and uncomment the following: --> <!-- <rule name="Redirect to add www" stopProcessing="true"> <match url="^(.)$" ignoreCase="false" /> <conditions> <add input="{HTTP_HOST}" pattern="^example.com$" /> </conditions> <action type="Redirect" redirectType="Permanent"url="http://www.example.com/{R:1}" /> </rule> --> <!-- To redirect all users to access the site WITHOUT the 'www.'prefix, http://www.example.com/... will be redirected tohttp://example.com/...) adapt and uncomment the following: --> <!-- <rule name="Redirect to remove www" stopProcessing="true"> <match url="^(.)$" ignoreCase="false" /> <conditions> <add input="{HTTP_HOST}" pattern="^www.example.com$" /> </conditions> <action type="Redirect" redirectType="Permanent"url="http://example.com/{R:1}" /> </rule> --> <!-- Rewrite URLs of the form 'x' to the form 'index.php?q=x'. --> <rule name="Short URLS" stopProcessing="true"> <match url="^(.*)$" ignoreCase="false" /> <conditions> <add input="{REQUEST_FILENAME}" matchType="IsFile"ignoreCase="false" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory"ignoreCase="false" negate="true" /> <add input="{URL}" pattern="^/favicon.ico$" ignoreCase="false"negate="true" /> </conditions> <action type="Rewrite" url="index.php?q={R:1}"appendQueryString="true" /> </rule> </rules> </rewrite>

<!-- httpErrors> <remove statusCode="404" subStatusCode="-1" /> <error statusCode="404" prefixLanguageFilePath="" path="/index.php"responseMode="ExecuteURL" /> </httpErrors -->

<defaultDocument> <!-- Set the default document --> <files> <remove value="index.php" /> <add value="index.php" /> </files> </defaultDocument> </system.webServer></configuration>

IIS6On IIS6, you can use third party modules (see above) to add mod_rewrite-like functionality to IIS.You will also want to download and set up the FastCGI module.

IIS5On IIS5, you can use third party modules (see above) to add mod_rewrite-like functionality to IIS.Due to improved application pool security implemented in IIS6+, deployment on IIS6+ isrecommended.

IIS5 Alternative: Creating a Custom Error HandlerNote: This method seems to work for IIS5 but not IIS6+.You probably want to disable logging in IIS, since every page view is considered an error usingthis technique.

make sure your Drupal is working well without clean urls enabled.

Page 86: Drupal - Installation Guide

open your Internet Services Manager or MMC and browse to the root directory of the website where you installed Drupal. You cannot just browse to a subdirectory if you happennedto install to a subdirectory.right click and select properties -> custom errors tabset the HTTP Error 404 and 405 lines to MessageType=URL, URL=/index.php. If you areusing Drupal in a subdirectory, prepend your subdir before /index.phppaste the following code into the bottom of settings.php file, which is usually locatedunder sites/default/. the first two lines should be edited. If you aren't using asubdirectory, set $sub_directory to "". then set $active=1 and enjoy!

<?php

// CONFIGURATION$sub_dir = "/41/"; // enter a subdirectory, if any. otherwise, use ""$active = 0; // set to 1 if using clean URLS with IIS

// CODEif ($active && strstr($_SERVER["QUERY_STRING"], ";")) { $qs = explode(";", $_SERVER["QUERY_STRING"]); $url = array_pop($qs); $parts = parse_url($url); unset($_GET, $_SERVER['QUERY_STRING']); // remove cruft added by IIS if ($sub_dir) { $parts["path"] = substr($parts["path"], strlen($sub_dir)); } $_GET["q"] = trim($parts["path"], "/"); $_SERVER["REQUEST_URI"] = $parts["path"]; if( array_key_exists( "query", $parts ) && $parts["query"] ) { $_SERVER["REQUEST_URI"] .= '?'. $parts["query"]; $_SERVER["QUERY_STRING"] = $parts["query"]; $_SERVER["ARGV"] = array($parts["query"]); parse_str($parts['query'], $arr); $_GET = array_merge($_GET, $arr); $_REQUEST = array_merge($_REQUEST, $arr); }}?>

at this point, you should be able to request clean url pages and receive a proper page inresponse. for example, request the page /node/1 and hopefully you will see your first nodeshown. you should not use the q= syntax; use the clean url syntax. if you get an IIS error,you have a problem. please fix redo the above and then retest.browse to index.php?q=admin/system, enable clean URLS, and press Submit.you may get a php error if your php error reporting in your php.ini file is set to high. Trythis setting in your php.ini file

error_reporting = E_ALL & ~E_NOTICE

IIS CleanURLs using some of the availableISAPI filters.There is a free version called ISAPI_Rewrite Lite that should get clean URLs working for IIS.

General configuration:

1. Make sure IIS_WPG and NETWORK SERVICE have access to the .htaccess file - otherwiseISAPI_Rewrite cannot read the configuration httpd.ini (2.x) or .htaccess (3.x) files.

2. D5: Add $conf['clean_url'] = 1 to your settings.php - to manually enable clean urls.3. D6: There are no changes required - it simply works.

ISAPI_Rewrite 3.x:

You don't need to change the standard Drupal .htaccess file. Helicon ISAPI_Rewrite 3.x wasdesigned to maintain maximum Apache mod_rewrite compatibility. Us the latest version ofISAPI_Rewrite 3.x (>=3.1.0.56 is required) with Drupal. If you cannot get it working out if thebox - enable the LogLevel (http://www.helicontech.com/isapi_rewrite/doc/LogLevel.htm) settingand try to figure out what's broken in ISAPI_Rewrite.

ISAPI_Rewrite 2.x: Configuration example if Drupal is installed inwebservers root

[ISAPI_Rewrite]

# Accept a url with the following directories and pass them through unchanged.RewriteRule /(?:misc|files|modules|themes|sites|uploads)/(.*) $0 [I,L]

# Make URLs saneRewriteRule /cron\.php $0 [I,L]RewriteRule /index\.php.* $0 [I,L]RewriteRule /install\.php.* $0 [I,L]RewriteRule /update\.php.* $0 [I,L]RewriteRule /xmlrpc\.php $0 [I,L]

# activate rewriting for custom modules (for e.g. banner.module)RewriteRule /banner_db\.php $0 [I,L]RewriteRule /banner_file\.php $0 [I,L]

Page 87: Drupal - Installation Guide

# deactivate rewriting for custom modules (for e.g. robotstxt.module)RewriteRule /robots\.txt.* $0 [I,L]

RewriteRule /(.*)\?(.*) /index.php\?q=$1&$2 [I,L]RewriteRule /(.*) /index.php\?q=$1 [I,L]

ISAPI_Rewrite 2.x: Configuration example if Drupal is installed in asubdirectory (Requires ISAPI_Rewrite >=2.9 Build 63)

[ISAPI_Rewrite]

# You must change/remove prefixes if Drupal is not installed in a subdirectory# Specify namespaces with UriMatchPrefix - DO NOT CHANGE ORDERUriMatchPrefix /drupal

# Accept a url with the following directories and pass them through unchanged.RewriteRule /(?:misc|files|modules|themes|sites|uploads)/(.*) $0 [I,L]

# Make URLs saneRewriteRule /cron\.php $0 [I,L]RewriteRule /index\.php.* $0 [I,L]RewriteRule /install\.php.* $0 [I,L]RewriteRule /update\.php.* $0 [I,L]RewriteRule /xmlrpc\.php $0 [I,L]

# activate rewriting for custom modules (for e.g. banner.module)RewriteRule /banner_db\.php $0 [I,L]RewriteRule /banner_file\.php $0 [I,L]

# deactivate rewriting for custom modules (for e.g. robotstxt.module)RewriteRule /robots\.txt.* $0 [I,L]

# specify namespaces with UriFormatPrefix - DO NOT CHANGE ORDERUriFormatPrefix /drupal

RewriteRule /(.*)\?(.*) /index.php\?q=$1&$2 [I,L]RewriteRule /(.*) /index.php\?q=$1 [I,L]

# reset namespaces to defaultUriMatchPrefixUriFormatPrefix

Translating Apache's rewrite rulesRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-d

In plain English: If the REQUEST_FILENAME variable does not exist (not an existing file andnot an existing directory) then apply the rule:RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]"

After much research this exact functionalty does not appear to exist in any ISAPI module for IIS. Ithink the following solution will help solve this issue. It probably works with most "ISAPI rewrite"modules (they just need the "stop the rewriting process" option).

With this approach you basically revert the "Apache Rewrite" logic. First define rules forknown files/folders (like /themes/ ..etc..). Have those "matching rules" exit, so rules processingstops before going to the next rule. With mod_rewrite.dll you can do that with the option [l].

Here is what my rules file looks (so far) like (using mod_rewrite.dll):RewriteRule ^/index.php\?q\=(.*)$ /index.php?q=$1 [l]RewriteRule ^/themes/(.*)$ /themes/$1 [l]RewriteRule ^/misc/(.*)$ /misc/$1 [l]RewriteRule ^/(.*)$ /index.php?q=$1 [l]

Remember, you have to add an "exiting" rule for all known folders/files before hitting the finalrule. The first rule is to avoid recursion and exit immediatly if the URL already has index.php?q=.

To better understand the Apache rules here are the definitions of the main options:'last|L' (last rule)Stop the rewriting process here and don't apply any more rewriting rules. Use this flag to preventthe currently rewritten URL from being rewritten further by following rules.

'qsappend|QSA' (query string append)This flag forces the rewriting engine to append a query string part in the substitution string to theexisting one instead of replacing it. Use this when you want to add more data to the query stringvia a rewrite rule.

REQUEST_FILENAMEThe full local filesystem path to the file or script matching the request.

'-d' (is directory)Treats the TestString as a pathname and tests if it exists and is a directory.'-f' (is regular file)Treats the TestString as a pathname and tests if it exists and is a regular file.

Note: Getting Apache running on MS Windows is not that bad (I had been delaying it for years).In reality it's a matter of a few hours to get going. http://www.sitebuddy.com aims to save youtime in that endeavor.

Page 88: Drupal - Installation Guide

Clean URLs with Easyphp.To get that the clear URLs works in Easyphp 1.8 you have to join the httpd.conf file and changethis two lines:

#LoadModule rewrite_module modules/mod_rewrite.so

and

#AddModule mod_rewrite.c

and leave like this in the same line.

LoadModule rewrite_module modules/mod_rewrite.so

y

AddModule mod_rewrite.c

and Re-start the server.

Easyphp have the mod_rewrite within.

If there is any problem tell me.

Oskar Calvo.

Clean URLs for EasyPHP 2 (with Apache 2)For EsayPHP 21. Uncomment this:#LoadModule rewrite_module modules/mod_rewrite.so

2. Under <Directory "${path}/www"> Change

AllowOverride None toAllowOverride All

Clean URLs with LighttpdFor those who have stepped up a notch in performance and moved from Apache to Lighttpd, youneed to fix you clean URLs. There are two ways to do so:

Using url rewrites

First you can use the following configuration for Lighty's mod_rewrite module:

url.rewrite-final = ( "^/system/test/(.*)$" => "/index.php?q=system/test/$1", "^/([^.?]*)\?(.*)$" => "/index.php?q=$1&$2", "^/([^.?]*)$" => "/index.php?q=$1", "^/rss.xml" => "/index.php?q=rss.xml")

The first line ensures that Drupal's clean URL check (when saving Settings) succeeds (Drupalmakes an HTTP request for a path of the form /system/test/yLgnwqqUu5cWnvPi4Hrz.png). It's aspecial case that must be handled separately (read on for the reason).

The two following lines let Drupal handle any URL that doesn't contain a dot. This is significantbecause we can assume, fairly confidently, that addresses like /node/add are Drupal URLs, butaddresses such as /themes/bluemarine/style.css are physical files. So the above configuration willwork for all cases where this assumption holds true; if there are exceptions to the rule, they can bemanually added to the rewrite configuration.

The last line handles the important exception of rss.xml, a Drupal URL that contains a dot.

See also the related discussion at http://drupal.org/node/20766

Using mod magnet

Second you can use lighty's mod magnet module together with a simple lua scripts. Have a look atthe tutorialshttp://realize.be/drupal-lighttpd-clean-urls-made-easy orhttp://more.zites.net/lighttpd_and_drupal_clean_urls_flexible

This way has the advantage that there are no problems with dots.

Clean URLs with Zeus

Page 89: Drupal - Installation Guide

The Zeus server does not support all aspects of the Apache .htaccess file that ships with Drupal; inparticular, the RewriteRules that allow clean URLs are not interpreted by Zeus.

To set up clean URLs on a Zeus server, create a file called rewrite.script in the root of your Drupalinstallation, and put into it the following script:

RULE_0_START:# get the document rootmap path into SCRATCH:DOCROOT from /# initialize our variablesset SCRATCH:ORIG_URL = %{URL}set SCRATCH:REQUEST_URI = %{URL}

# see if theres any queries in our URLmatch URL into $ with ^(.*)\?(.*)$if matched then set SCRATCH:REQUEST_URI = $1 set SCRATCH:QUERY_STRING = $2endifRULE_0_END:

RULE_1_START:# prepare to search for file, rewrite if its not foundset SCRATCH:REQUEST_FILENAME = %{SCRATCH:DOCROOT}set SCRATCH:REQUEST_FILENAME . %{SCRATCH:REQUEST_URI}

# check to see if the file requested is an actual file or# a directory with possibly an index. don't rewrite if solook for file at %{SCRATCH:REQUEST_FILENAME}if not exists then look for dir at %{SCRATCH:REQUEST_FILENAME} if not exists then set URL = /index.php?q=%{SCRATCH:REQUEST_URI} goto QSA_RULE_START endifendif

# if we made it here then its a file or dir and no rewritegoto ENDRULE_1_END:

QSA_RULE_START:# append the query string if there was one originally# the same as [QSA,L] for apachematch SCRATCH:ORIG_URL into % with \?(.*)$if matched then set URL = %{URL}&%{SCRATCH:QUERY_STRING}endifgoto ENDQSA_RULE_END:

For more details, tweaks, etc, see this forum post: http://drupal.org/node/46508

Enabling Clean URLs on a Netfirms ServerI am setting up a site for a client on a Netfirms server. We need clean URLs, so I made thenecessary changes to the .htaccess file (i.e., set the rewrite base to the proper location). I then wentto the clean URLs page on the site, and ran the test. The URL display indicated that in fact cleanURLs were working.

Yet the radio button that would allow me to select clean URLs remained grey (that is, I could notselect that as an option).

Here is what I did to correct this and enable clean URLs:

1. Use phpMyAdmin to get into the database for the site.

2. Back up the database.

3. Click the SQL tab.

4. Enter the following into the query box:

UPDATE `variable` SET `value` = 's:1:"1";' WHERE `name` = 'clean_url' LIMIT 1 ;

5. Click Go.

6. Return to the clean URLs page on your site and reload the page.

7. If the button is still greyed out, change a setting on your site. For example, go to siteconfiguration, file system, and change public to private. and click Submit.

8. Return to the clean URL page on your site, reload the page, and it should now allow you toenable clean URLs.

9. Return to the file system config page and reset file download method to public.

10. Live happily ever after.

Example Clean URL configuration of

Page 90: Drupal - Installation Guide

httpd.conf for performanceNote the following directions do not adequately cover everything that needs to be included ina site's Apache configuration file to make sure the site is secure. The files directory needs aSetHandler directive per http://drupal.org/files/sa-2006-006/advisory.txt

Enabling .htaccess in Apache requires more work on the part of the server. A full explanation canbe found here:http://www.serverwatch.com/tutorials/article.php/3436911Suffice it to say that it is in your interest to not use .htaccess files and even disable them if you areconcerned about squeezing more performance out of apache.

I moved the rewrite rules (all of the sample .htaccess file really) to /etc/httpd/conf/drupal.conf.Then for each virtual host, one can add the line:

Include conf/drupal.conf

The rewrite rules change slightly: # Rewrite current-style URLs of the form 'index.php?q=x'. RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]

Note that I added %{DOCUMENT_ROOT} and a leading slash in front of index.php -- because Ihave index.php installed in my document root. If you install it in another directory, you will wantto give the relative path to it from document root with the leading slash.

Important: If you forget the leading slash (more specifically, forget to give the relative path withleading slash), Apache will give you a "400 Bad Request" error.

This is better. But we still have a problem where every request will check for the existence of afile and a directory before we apply the rewrite rule. The OS may be able to cache some of thatinformation, but it would still be better to avoid the two file-system checks in the first place.

There are some directories that we should not rewrite. And there are certain extensions that weshould not rewrite. Using this information, we can update the rewrite rule to send everything toindex.php that does not fall into this category. The first rule excludes the directories "files","misc", and "uploads". The second rule excludes the extensions you see. Add more if you haveother extensions in your directory that should not get passed to index.php.

RewriteCond %{REQUEST_FILENAME} !^/$ RewriteCond %{REQUEST_FILENAME} !^/(files|misc|uploads)(/.*)? RewriteCond %{REQUEST_FILENAME} !\.(php|ico|png|jpg|gif|css|js|html?)(\W.*)? RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]

Note: This sort of directive will disable ImageCache and any other modules that depend onpassing requests for files that are not found to index.php.

Compliance with SA-2006-006

Add this to your http.conf file; be sure to change the webroot path /var/www/html/ so it matchesyour webroot path. Also be aware that if your running drupal in multiple sub directories then youneed to add this in for each one. (/var/www/html/sitea, /var/www/html/siteb, /var/www/html/sitec,...etc). This is compatible with mulitsite due to the * in sites/*/files.

<Directory /var/www/html/sites/*/files> SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006 Options None Options +FollowSymLinks</Directory>

See Directory Directive for the * syntax and other tips.

Getting Clean URLS Working on Mac OSXTiger (Client not Server)The Apache htdocs directory in Mac OSX is by default located in /Library/Webserver/Documents.If you copied your Drupal files to this folder via the Finder, you will miss the .htaccess file withthe mod_rewrite rules to allow clean urls because .htaccess is a hidden file that Finder does notsee.

To remedy this, open the Terminal in your /Applications/Utilities folder and type the following(this example assumes you have a copy of Drupal 5.2 on your Desktop):

$ cd ~/Desktop/drupal-5.2/$ cp .htaccess /Library/Webserver/Documents

Now go back and enable clean urls and you should be good to go.

Extra infoActually there's another issue caused by the default Apache configuration where the

Page 91: Drupal - Installation Guide

AllowOverride value is set to None

Open your httpd.conf file (I use the command pico /etc/httpd/httpd.conf)look for:

# This controls which options the .htaccess files in directories can# override. Can also be "All", or any combination of "Options", "FileInfo",# "AuthConfig", and "Limit" AllowOverride None

and set allowoverride to All

Save, restart apache and you're set!

Setting up clean URLs above web documentroot on virtual private serversTo set up clean URLs above web document root on virtual private servers, you need to change asetting in httpd.conf.

(default setting)Options FollowSymLinksAllowOverride None

Change it toOptions FollowSymLinksAllowOverride All

None of the other changes discussed in this section of the handbook were necessary (and in facthad to be undone).

The hosting provide said this does not provide any security issues (no guarantees).

reboot vps after making changeThis is excellent advice. I installed a test site at /var/www/test. My live site is at /var/www/html.The live site worked fine. In the test site i went to set clean url's and got an apache error.

This fixed it.

One minor note. I had to reset the vps before the changes took affect. With my hosting companythis is simply a menu selection in their control panel, so if you have this setup and make thechange and it does not work.

Ask your provider to reset your Virtual Private Server. This is simular to stopping and startingApache on a Windows install.

Burn a searchable site to CD using Server2GoServer2Go is a Webserver that runs out of the box without any installation and on write protectedmedia. This means that you can use Server2Go to develop your Drupal site locally (or copy over aDrupal site you have already made) and then burn it to a CD. The CD version will be fullysearchable and will run all Drupal's php magic!

The clever part is that Server2Go copies all the databases to a temp folder once the CD islaunched. This means your Drupal site will behave as if it is live so it can be searched etc.However, although you can also add content to the site when it is launched from the CD this willobviously not be recorded to the CD as the CD is read only! The next time you launch the CDyou'll be back with your original burnt site.

This tutorial is quite long, but the result is worth it in the end.

1. Download server2go mini package (NOTE: this tutorial has only been confirmed to workwith the mini package [Apache 2.0.61], the package with the latest version of Apache didnot work)

2. Unzip where you want it. The folder will be called 'server2go_a2_psm_mini'. In this tutorialwe will rename the folder 'Drupal_S2G' to make file addresses easier to write out.Check Server2Go is working by double clicking the Server2Go.exe file. You should get thesplash screen saying "congratulations...." opening up in Internet Explorer.

3. OPTIONAL STEP. You can skip this step if you can assume that anyone launching yoursite on CD will be happy using Internet Explorer. However, you can have Portable Firefoxas the browser included on the CD. To do this:

a. Download the latest version of Portable Firefox (tested working with Firefox 2 and 3).b. Install Portable Firefox in the 'Drupal_S2G' folder (click on 'Browse' to locate the

folder on your computer).c. Launch Portable Firefox by clicking on FirefoxPortable.exe in (Drupal_S2G >

FirefoxPortable). You can choose to disable session store. You can choose a blankpage as the firefox home page in 'Options' and hide the Bookmarks Toolbar so youhave a cleaner looking browser window when it launches. Close Portable Firefox.Opening and closing the application is important!

Page 92: Drupal - Installation Guide

d. Go to (Drupal_S2G > FirefoxPortable > App > firefox) and rename firefox.exe toffp.exe IMPORTANT: Leave the FirefoxPortable.exe in (Drupal_S2G >FirefoxPortable) unchanged!

e. Create a file FirefoxPortable.ini in (Drupal_S2G > FirefoxPortable). You can use aprogram like Notepad++ to do this.

f. Paste the following in the file:

[FirefoxPortable]FirefoxDirectory=App\firefoxProfileDirectory=Data\profileSettingsDirectory=Data\settingsPluginsDirectory=Data\pluginsFirefoxExecutable=ffp.EXEAdditionalParameters=LocalHomepage=WaitForFirefox=trueDisableSplashScreen=trueAllowMultipleInstances=trueDisableIntelligentStart=falseSkipChromeFix=falseSkipCompregFix=falseRunLocally=false

NOTE: THESE SETTINGS ARE FOR SITE DEVELOPMENT. THEY WILL NEEDTO BE CHANGED WHEN BURNING THE SITE TO CD (see instructions below).

g. Open the pms_config.ini in (Drupal_S2G) and change the following:[line 52] BrowserType=PORTABLEFIREFOX[line 56] BrowserPath=FirefoxPortable/FirefoxPortable.EXE

h. Check it works by launching the Server2Go.exe4. Change the following settings in the pms_config.ini file in (Drupal_S2G) the main folder

(use a program like Notepad++ to change it):a. [line 21] StartLocal=1 (this is for using when you want to develop the website and

have to write files. If you want to use server2go to run off a read-only CD at a laterpoint, you will have to change it back to =0)

b. [line 61] BrowserSize=MAXIMIZE NOTE: INTERNET EXPLORER ONLY.IGNORE IF USING PORTABLE FIREFOX

c. [line 69] LocalMirror=0 this is so that the things you do to build your site are savedrather than carried out in a temporary folder

d. Make a note of this value: 'HostName=127.0.0.1' [line 33] and this'MySQLPort=7188' [line 80] as we need them later.

5. Make the following changes in (Drupal_S2G > server > config_tpl > php.ini)to make sureApache has the right settings to run Drupal, and can provide clean-urls:

a. [line 201] max_execution_time = 60 (instead of 30)b. [line 202] memory_limit = 64M (instead of 8M)

6. Change the following setting in (Drupal_S2G > server > config_tpl > httpd.conf)a. [line 164] Remove the '#' so it reads LoadModule rewrite_module

modules/mod_rewrite.so7. Download Drupal 6.X (latest version) and unzip it into the htdocs folder. You can unzip it

so that it sits in a folder inside the htdocs folder. This means you'll have a folder insidehtdocs called 'drupal.6.4' or something similar.

NOTE: YOU CAN IMPORT A SITE YOU HAVE ALREADY DEVELOPED. SEARCHTHE DRUPAL HANDBOOK FOR ADVICE ON IMPORTING A DRUPAL SITE TO ALOCAL INSTALLATION.

You can rename it to anything you want, but in this case we'll call it 'drupal' so all Drupal'sfiles will sit in (Drupal_S2G > htdocs > drupal )

8. Do the things the Drupal set up will tell you to do which are:a. Create a folder called 'files' in the main drupal folder i.e.(Drupal_S2G > htdocs >

drupal > files)b. Create a 'modules' folder and a 'themes' folder in the default folder, this is where you

will place your add-on modules and themes i.e. (Drupal_S2G > htdocs > drupal >sites > all> modules) and (Drupal_S2G > htdocs > drupal > sites > all > themes)

c. Copy the default settings file and rename it settings i.e. copy (Drupal_S2G > htdocs >drupal > sites > default > default.settings.php) and paste it in the same folder,re-naming it to settings.php

9. Now we're going to add the database that Drupal needs to run.a. Start server2go.exe in the 'Drupal_S2G' folder. It should open up the Server2Go start-

page in a new browser (Internet Explorer if you didn't do the Firefox Portable Appschange)

b. Go to the phpmyadmin link under 'Tools' on the right-hand side.c. Click on privelegesd. Click on 'Add user'e. Under username put 'admin' (or whatever you want to call your user); set 'host' as

'local' and set your own password (write it down!)f. Under database for user choose 'none'g. Under 'global priveleges' click on 'check all'h. Click on 'Go'. You should get a message saying 'You have added a new user'i. Click on the databases link and you'll see a box at the bottom of the page that says

'create database'. Put in the name of your database. Let's call it 'drupal' and press'create'. You should get a message saying 'Database drupal has been created.'

Page 93: Drupal - Installation Guide

j. Click on the picture of a house to go to the phpmyadmin home page. Then select'databases' and click on 'drupal'.

k. Click on the 'priveleges' tab at the top of the page and check that 'admin' is one of theusers listed as having access to the database. All done!

NOTE: READ OTHER DRUPAL HANDBOOK INFORMATION ABOUTSECURITY AND CREATING DATABASES. THIS IS A QUICK METHOD ANDNOT NECESSARILY VERY SECURE...

10. Now we're going to set up Drupal. Go to http://127.0.0.1:4001/drupal/ (orhttp://127.0.0.1:4001/whatever-you-called-the-folder-you-unzipped-drupal...) and youshould see the Drupal set-up page.

a. After you've selected which language you are installing Drupal in, you will be askedto fill in the database details. In our case the database name is 'drupal'; the databaseusername is 'admin'; and the password is whatever password you chose.

b. Click on the 'Advanced options'. In 'Database host' put: 127.0.0.1 and in 'Databaseport' put 7188, the settings we noted earlier.

c. Save and continue.d. Follow all the rest of the stuff as in the Drupal Handbook.e. As you're installing on a local site, you'll probably get this message:

warning: mail() [function.mail]: Failed to connect to mailserver at"localhost" port 25, verify your "SMTP" and "smtp_port" setting inphp.ini

Try this: http://drupal.org/project/smtp

11. To check everything works, add some test content to your site and then close the browser.Restart Server2Go.exe once the server has shut down. If your content is there, bingo! Itworks!

Settings for burning site to a CDIf you want to run some tests without wasting loads of CDs you can create an ISO of your files(you should be burning all the files INSIDE 'Drupal_S2G' and not just copying the 'Drupal_S2G'folder itself onto CD, otherwise the autorun will not work) by using software such as PowerISO(the free version will create ISOs up to 300MB in size, which should be enough for testing).

There are lots of nice settings to change, including the splash screen (Drupal_S2G > splash.png)which you could replace with any graphic you like and you can even change the name of theserver i.e. replace 'Server2Go' with 'My Drupal Site on CD'. See the Server2Go website for moreinfo. The following settings MUST be changed to make your site work on CD

1. In the pms_config.ini file in the (Drupal_S2G) folder:a. [line 21] StartLocal=0b. [line 39] DefaultFile=drupal/ (or whatever the folder is called where you have your

drupal files. Don't forget the trailing slash)c. [line 69] LocalMirror=1

If you are using Firefox portable, you will also have to change the following. Annoyingly,you can't be running firefox already when you start the CD and closing the browser will notshut down the server, this has to be done from the tray icon instead.

2. In the pms_config.ini file in the (Drupal_S2G) folder.a. [line 14] KeepRunningAfterBrowserClose=1b. [line 17] ShowTrayIcon=1 (you need this to be able to shut down the server once

you've finished with the CD).3. In the FirefoxPortable.ini in (Drupal_S2G > FirefoxPortable ):

a. AllowMultipleInstances=falseb. RunLocally=true

Comments welcome on this as the method has only been tested briefly.

Creating multiple sites on the same domainwithout using symlinks with ApacheWe were searching for a way to support multi-site installations (subsites) on the same domain, thatis, to have:

www.example.com/www.example.com/siteawww.example.com/sitebwww.example.com/sitecetc.

with different content/themes/modules etc. but on the same Drupal 5.x installation. The normalway to do this is to create the appropriate

/sites/www.example.com.sitea/settings.phpetc...

files and then to create recursive symlinks for each subsite, eg.

Page 94: Drupal - Installation Guide

ln -s drupal/. drupal/sitea

etc..

The problem with this approach is that for multiple sites, it permits for recursive urls(http://www.example.com/sitea/siteb/sitea/siteb/content) which can play havoc with GooglePageRank. For us a secondary problem was that is caused our IDE (eclipse) to loose it frequently,presumably since it wasn't able to distinguish the symlinks from real directories and so wasrecursively parsing the entire drupal directory until it eventually ran out of memory. And finallysymlinks don't often seem to translate well in our versioning system, which means we needed tocreate a script to build the symlinks across different dev environments.

What we wanted to do was achieve mutlisites on the same domain, but without using recursivesymlinks. Instead our solution was to use an Apache RewriteRule for each site. eg.

RewriteRule ^sitea(.*)$ $1 [PT]

This sits neatly in the .htaccess file (before the final 'RewriteRule ^(.*)$ index.php?q=$1[L,QSA,PT]'), and can be versioned easily.

The problem with this approach is that Drupal uses the SCRIPT_NAME environment variable(normally /index.php) from the server to figure out which site config file to use. With symlinks theserver is 'tricked' into thinking it's actually accessing index.php at a different location(/sitea/index.php) than it actually is, so the SCRIPT_NAME is valid and the correct site file isfound.

RewriteRules don't affect SCRIPT_NAME though. In fact we weren't able to find any way toreliably modify SCRIPT_NAME just through Apache, so instead we patched bootstrap.inc to lookat REQUEST_URI instead of SCRIPT_NAME (see attached patch file). This seems to work quitewell, assuming you've set $base_url correctly for each site in it's settings.php file. (Editor's note:mod_rewrite has an 'env|E=VAR:VAL' (set environment variable) flag, add that to [L,QSA,PT] asappropriate)

This solution is easilly versionable, requires no symlinks and doesn't lead to recursive URLS.

Before you use this be aware of some known caveats of this approach:

We've tried it this morning, it's hardly a tried and tested approach. There may well be issueswe haven't uncovered.There are doubtless more elegant ways of doing this, and we'd love to hear from anyonewho has done so. Solutions from the community seems rather sparse on this issue right nowthough, hence this post.This will only work on servers that set REQUEST_URI, as far as I know only Apacheactually does thisYou'll need to make sure all links in your subsites add the appropriate $base_path to them.

Attachment Size

bootstrap.inc_.patch 1.3 KB

File and directory managementThese are general guidelines.

1. For Drupal 5.x and later: a new feature/best practice. For a normal (single site) installation,you should put all non-core modules or themes in the sites/all/modules orsites/all/themes folders. For a multi-site installation, put modules or themes insites/all that you wish to have available for all sites.

2. Multisite setups allow you to have a modules directory specific to the site in thesites/www.example.com/modules directory. You can still put modules in directories undersites/all/modules if you want them available to all sites. The most specific module or versionfound is the one that gets used. If you have different versions of image.module stored inboth sites/thatsite/modules/image and sites/all/modules/image, then 'thatsite' will use theversion found in 'thatsite' directory, while the others will use the other one.

3. Leave the CHANGELOG.txt file in your root directory as it has the Drupal versioninformation in it. If you manage more than one site, consider putting a version.txt file in theroot of your drupal directory with the Drupal version, date and modules you are using. Ifyou only manage a few sites you will probably remember them all, but if you set them up forother people, these reminders can help you if you are asked back to do additional work.Also, it can help the next site admin if you move on.

4. Rename update.php if you want. There are protections for it in the update script in that youhave to be logged in with UID1. As of 4.7 update.php is now required for various moduleinstallations and other tasks so if you move/rename it for whatever reason do not forget toput it back to it's original state before module installs/updates.

5. Remove install.php if you want. This file is only needed during installation.

Other Tips

Modules that are not part of core may or may not be supported by their contributor for aDrupal version upgrade.Avoid spaces in any directory name.

Installing Drupal 7 on an OLPC laptop

Page 95: Drupal - Installation Guide

Installing Drupal 7 on an OLPC laptopThis post has been moved to the Drupal for OLPC group on http://groups.drupal.org

http://groups.drupal.org/node/24188

Run Drupal on multiple web servers behind aload balancerWhen running large Drupal installations, you may find yourself with a web server cluster that livesbehind a load balancer. The pages here contain tips for configuring Drupal in this setup, as well asexample configurations for various load balancers.

In addition to a large selection of commercial options, various open source load balancers exist:Pound, Varnish, ffproxy, tinyproxy, etc. Apache can also be configured as a reverse proxy.

The basic layout you can expect in most high-availability environments will look something likethis:

Browser ──! HTTP Reverse Proxy ┌─!──┼─! └─!

Web server 1Web server 2Web server 3

By way of explanation:

Browsers will connect to a reverse proxy using HTTP or HTTPS. The proxy will in turnconnect to web servers via HTTP.Web servers will likely be on private IP addresses. Use of a private network allows webservers to share a database and/or NFS server that need not be exposed to the Internet on apublic IP address.If HTTPS is required, it is configured on the proxy, not the web server.

Most HTTP reverse proxies will also "clean" requests in some way. For example, they'll requirethat a browser include a valid User-Agent string, or that the requested URL contain standardcharacters.

In the case of Drupal, it is highly recommended that all web servers share identical copies of theDrupal DocumentRoot in use, to insure version consistency between themes and modules. Thebest way to achieve this is to use an NFS mount to hold your Drupal files.

Note:

If you plan to install Drupal on a web server that is accessible from the outside via HTTPS,there's an outstanding issue you'll want to check (#313145: Support X-Forwarded-ProtoHTTP header). At this time, Drupal's AJAX callbacks use URLs based on the protocol usedat the web server, regardless of the protocol used at the proxy. Your workaround is eitherthis patch, or to avoid relying on AJAX on your site. Unfortunately, the Drupal installerrelies on AJAX, so you'll either need to install the patch at the issue above, or install viaHTTP instead of HTTPS.

Virtual sites: Create multiple sites based onone Drupal installation without using Drupal'smulti-site featureVirtual sites offers almost the same (and more) functionality as the Drupal multi-site featurewithout the need for FTP or SSH. Depending on conditions (e.g. requested url or user role)handeld by the Condition(s) module, you can override theme, site information, menu's and more tovirtually present the visitor with a different website.

What it can doCreate virtual sites with different theme, site information, menu's etcetera.No need for FTP or SSH, like with Drupal's multi-site feature.Determine when to show what site based on (sub)domain, path, user role, taxonomy or anyother condition.Add custom conditions by writing a plug-in for the condition module.Add custom virtual site features by writing a plug-in.

Features a virtual site can have

Each virtual site can override (of your default Drupal site) the following settings:

Set the source for the primary linksSet the source for the secondary linksSet the default site languageForce a base URL (e.g. domain)Add HTML, JS and CSS to the page template

Page 96: Drupal - Installation Guide

Set all site information settings (admin/settings/site-information) like name, slogan andfront-pageSet themeSet all theme-specific settings (admin/build/themes/settings/theme) like logo and evensettings offered by the theme itselfAny Drupal variable, using the easy INI syntax.

What it cannot doFor the following settings you'd still need Drupal's multi-site feature:

Database URL (DSN).Table prefix(es).PHP configuration and cookie_domain.String overrides.

Adding a virtual site featureIt's really easy to add new settings (features) than can be applied to any virtual site you create. Forthis you can create a new module, just like the included virtual_site_common.module we willuse here as an example. Like with any hook, replace virtual_site_common with the name ofyour module.

Hook in to the virtual sites moduleThis can be achieved by writing an implementation of hook_feature_info().

<?phpfunction virtual_site_common_feature_info() { return array( // The name of the method that will apply the settings. 'virtual_site_common_feature' => array( // The name for the settings as the title of the settings form. 'name' => t('Common'), // A description as it will be displayed on top of the settings form. 'description' => t('Set common settings for a virtual site.'), ), );}?>

As you might note, one module can offer multiples features. Just add another one to the returnedarray.

Return the form to set the feature settingsVirtual sites will expect a method begins with the name of the specified 'apply method', but thenpostfixed with _form. This method receives an array just like the one it will return in the followingparagraph and is expected to return a form array that will be displayed to set the feature settings.

<?phpfunction virtual_site_common_feature_form($context) {

// ... (took out some code to make it more simple and clear) $menu_options = menu_get_menus(); $primary = isset($context['menu_primary_links_source']) ?$context['menu_primary_links_source'] :variable_get('menu_primary_links_source', 'primary-links'); $primary_options = array_merge($menu_options, array('' => t('No primarylinks'))); $form['menu_primary_links_source'] = array( '#type' => 'select', '#title' => t('Source for the primary links'), '#default_value' => $primary, '#options' => $primary_options, '#description' => t('Select what should be displayed as the primarylinks.'), ); // ..

return $form;}?>

Return the settings to be saved for the virtual siteVirtual sites will expect a method begins with the name of the specified 'apply method', but thenpostfixed with _submit. This method receives the &$form en $form_state variables like any formand is expected return the variable (mostly an array) to be saved with the virtual site to be used inthe following paragraph.

<?phpfunction virtual_site_common_feature_submit($form, &$form_state) { return $form_state['values'];

Page 97: Drupal - Installation Guide

}?>

Appliying the feature to the virtual siteThe 'apply method' specified in the hook_feature_info() method will be called if a virtual site isdue. The method receives the same variable it returned one paragraph earlier and is expected toapply it's feature. Most of the time, this means overriding a setting in Drupal's $conf globalvariable.

<?phpfunction virtual_site_common_feature($context) { global $conf; if (is_array($context)) { $conf['menu_primary_links_source'] = $context['menu_primary_links_source']; }}?>

Setting up a virtual siteUnderstanding the Virtual Site moduleWhat the Virtual Site module does is basicly overriding Drupal settings. This is also what Drupal'smulti-site feature does at core-level (bootstrap), but than at run-time level (hook_init()). Thisdifference is why Virtual Site cannot change database settings, because these are already initializedwhen Virtual Site comes in.

Understanding a single Virtual SiteEach Virtual Site you create can be seen as a group of settings to override Drupal settings with. Todetermine when which Virtual Site settings are applied, the module depends on the Conditionmodule. A condition can be seen as a group of requirements. When all requirements are met, thecondition is TRUE.

A real-life exampleLet's say I want to have a different theme and site title for all pages that have a path alias startingwith subsite/.

Install both the Virtual Site and the Condition module.Go to admin/settings/condition/add and choose a name.Expand Requirement: Pages, set Validate to Only... and enter subsite/*.Press Save settings.Go to admin/build/sites/add and choose a name.Set Criteria to When ANY selected condition is met.Check the newly created condition and press Save settings.Find the newly created virtual site in the list and click the edit link.Go to the Information tab, change the default site name and press Save settings.Go to the Theme tab, select a theme and press Save settings.Optionally, change any theme settings and press Save settings.Create or go to a page having an alias starting with subsite/.

Handling multiple (sub)domains with Virtual SitesJust like with Drupal's multi-site feature, the key is to point all the (sub)domains to the main publicHTML directory. You can ask your host to point all domains to the same public HTML directoryor use symbolic links. Once set, you can create a new condition for every domain and use thehostname requirement to enter the domain you want the condition to be valid for.

Using CVS to maintain a Drupal websiteWhy maintain a site from CVS?Maintaining a site from CVS helps in two main areas:

1. Upgrades: Normally, when it comes time to upgrade Drupal to a new version, there's a longlist of upgrade steps that you need to follow. New tarballs need to be downloaded andextracted not only for Drupal core, but for all contributed modules as well. Repeat for eachDrupal site you maintain. With CVS, this is just a single command.

2. Access to bug fixes: New releases of Drupal are only made after major bugs (generallysecurity issues) are fixed. These bugs (along with dozens of smaller bugs) are always fixedin CVS first.

How to maintain a site using CVSAssuming you've already grabbed the core code and your favorite contrib modules using the

Page 98: Drupal - Installation Guide

instructions on the checking out core from CVS and checking out contrib modules from CVSpages, you can update your files at any time using a couple of CVS commands.

Checking for updates to core and contribs

cvs -nq update -dP

If updates are available, this will display output similar to:

U modules/taxonomy/taxonomy.moduleU modules/upload/upload.module

The 'U' means that the listed file is newer, or "updated" from the one you have in your local copy.

Updating the site

To pull in the changes from CVS that will update your site to the latest Drupal "HEAD" versionand dev versions for contributed modules:

1. Enter the command:cvs update -dP

This will update your site to the latest development versions of Drupal core and contributedmodules.

2. While logged in as user/1, navigate to example.com/update.php to launch the databaseupdate utility to pick up any database changes.

Upgrading to a specific version of Drupal

Your installation must have been installed via CVS in order to upgrade it via CVS. Let's say you'dlike to upgrade from Drupal 6.6 to 6.8. (This will only update Drupal core, not contributedmodules):

1. Enter the command:cvs update -r DRUPAL-6-8 -dP

2. While logged in as user/1, navigate to example.com/update.php to launch the databaseupdate utility to pick up any database changes.

Note that if you are doing a major release upgrade (e.g. from Drupal 4.7 to 5.x or from Drupal 5.xto Drupal 6.x) you need to check on your contributed modules to make sure they have been portedfor that major version of Drupal.

Upgrading to a specific version of a Drupal contributed module

You can upgrade contributed modules to a specific version if those modules were installed viaCVS:

1. Navigate to the directory at the root level of the contributed module.2. enter the command:

cvs update -r DRUPAL-5--1-4 -dP

where DRUPAL-5--1-4 is the "CVS Tag" as listed on the release notes for the module.3. While logged in as user/1, navigate to example.com/update.php to launch the database

update utility to pick up any database changes.

Note: Core tags differ slightly from contribution tags. See Overview of core branches and tags andOverview of contribution branches and tags

TipsHaving a test site is highly recommended; new changes from CVS could potentially bringin additional bugs or changes which break your site (particularly with contributed modules).Testing these updates on a copy of your live server before moving them over is a great idea.Using a version control system for your Drupal code such as CVS or Subversion is also agood idea; this way, you can keep track of what changes were made and when.The CVS deploy module is useful for printing more user-friendly version strings on thesystem modules page, and for interacting with the Update status module (included in core in6.x and beyond, and via a contributed module for 5.x).

Apt-drup - Preserves original CVS keywordsPreserving cvs keywords from Drupal (like $Id: drupal.js,v 1.29 2006/10/14 02:39:48 unconedExp$) are essential to track down versions of files you originally used and to be able to patch yourlocal copy of drupal in case you found a suitable patch on drupal.org. To be able to patch, youneed to know which version of files we want to patch.

These keywords might get lost when we import this to your own CVS and replaced with yourkeywords substitution: $Id: drupal.js, v 1.1 2007/01/15 11:30:00 owahab Exp$.

This script does a "cvs export" from Drupal CVS for a version you can specify to a folder you canspecify then it adds CVS keywords making the folder ready for a "cvs import" to your CVS, yetpreserving Drupal's original CVS keywords.

Page 99: Drupal - Installation Guide

The script also can be used to download Drupal modules the same way.1. Download the attached file.2. $ chmod +x apt-drup.sh3. $ ./apt-drup.sh folder 5.1

You can substitute: folder with any folder name and 5.1 with any version of drupal.Note: you can directly request downloading a module a folder that doesn't exist and in this casedrupal will be downloaded too.$ ./apt-drup.sh folder 5.1 eventor$ ./apt-drup.sh folder 5.1 buddylist 1.0

http://cvs.drupal.org/viewcvs/drupal/contributions/sandbox/owahab/apt-dr...

cvsdrupal - checkout and maintain a localCVS repositoryThis sophisticated script will check out Drupal and any number of contrib modules into a multisite(optionally) directory tree.

It does check out the most recent files for tag selected in $REL, so if you do not want this, you'llhave to cvs up to the tag you want.

The file is attached for download - just change it from a .txt to a .sh file.

#!/bin/sh## cvsdrupal v0.0.3 20071101 [email protected]## Multisite CVS Drupal Manager## Initializes and maintains a multisite Drupal installation# from the CVS codebase. Additionally, this script manages# global and per-site modules and themes in the same manner.## Run this daily or weekly with cron to keep your checkouts# up to date with all bug fixes and security patches# applied to your release in CVS.# # You define your site configurations in newline-delineated# string arrays. There are three classes of such configuration# arrays used in this script: SITES, _MODULES, _THEMES.## For instance, you want to host two websites with shared# modules, example.net and www.example.com:# SITES="# all# example.net# www.example.com# "## The pseudo-site 'all' creates an 'all' subdirectory of 'sites'# in your Drupal installation. This is the parent of all shared# modules, themes, profiles, etc.## Thus, you can create shared resources# all_MODULES="# subversion# svn# "# all_THEMES="# meta# "## Each website you define (in SITES) is allowed its own modules# and themes independent of the other sites in your installation,# or it may use shared resources, or both. The decision is left# to you.## Or, to continue our example, you can create per-site resources# example_net_MODULES="# image# img_assist# "# example_net_THEMES="# dichotomy# "# www_example_com_MODULES="# diff# pathauto# "# www_example_com_THEMES="# combustion# "## Be sure to replace the dots with underscores in the names of the# per-site configurations. Also, note that any or all of these# configurations can be blank or left out altogether.## The configuration above has been included as a skeleton for your# own website(s). See these included examples for further usage# details in context of the code.

Page 100: Drupal - Installation Guide

## License: http://www.gnu.org/licenses/gpl.txt# Change these settings to suit your environment:## REL the CVS codebase version you want to checkout,# leave as is for a stable release or change to# HEAD for the very latest developments## BASE root path in which the "drupal" folder resides## UGID the local user:group file permissions,# set empty to ignore## CHANGELOG:# 2007-11-01 Cody Ray <[email protected]># * adapted for multisite usage# * with more sensible defaults## 2006-06-28 Mark Constable <[email protected]># * initial implementation#

REL=DRUPAL-5BASE=/var/wwwUGID=www-data:www-data

# Add your sites

SITES=" all example.net www.example.com"# Add shared modules

all_MODULES=" subversion svn"# Add site-specific modules

example_net_MODULES=" image img_assist"www_example_com_MODULES=" diff pathauto"# Add shared themes

all_THEMES=" meta"# Add site-specific themes

example_net_THEMES=" dichotomy"www_example_com_THEMES=" combustion"# Below here should remain untouched

SRC=:pserver:anonymous:[email protected]:/cvs/drupalexport CVSROOT=$SRC

[ -d $BASE/drupal/sites/all/modules ] || mkdir -p$BASE/drupal/sites/all/modules[ -d $BASE/drupal/sites/all/themes/engines ] || mkdir -p$BASE/drupal/sites/all/themes/engines[ -d $BASE/drupal/sites/all/themes/custom ] || mkdir -p$BASE/drupal/sites/all/themes/custom[ -d $BASE/drupal/sites/all/themes/contrib ] || mkdir -p$BASE/drupal/sites/all/themes/contrib[ -d $BASE/drupal/sites/default/modules ] || mkdir -p$BASE/drupal/sites/default/modules[ -d $BASE/drupal/sites/default/themes/custom ] || mkdir -p$BASE/drupal/sites/default/themes/custom[ -d $BASE/drupal/sites/default/themes/contrib ] || mkdir -p$BASE/drupal/sites/default/themes/contrib

if [ -d $BASE/drupal/CVS ]; then cd $BASE/drupal cvs -z6 up . -PAd -r $RELelse cd $BASE cvs -z6 co -r $REL drupalfi

for S in $SITES; do [ -d $BASE/drupal/sites/$S ] || cp -a $BASE/drupal/sites/default$BASE/drupal/sites/$Sdone

export CVSROOT=${SRC}-contrib

for S in $SITES; do N=`echo $S|sed -e 's/\./_/g'` for M in $(eval echo \$${N}_MODULES); do

Page 101: Drupal - Installation Guide

if [ -d $BASE/drupal/sites/$S/modules/$M/CVS ]; then cd $BASE/drupal/sites/$S/modules/$M cvs -z6 up . -PAd else cd $BASE/drupal/sites/$S/modules cvs -z6 co -d $M contributions/modules/$M fi donedone

for S in $SITES; do N=`echo $S|sed -e 's/\./_/g'` for T in $(eval echo \$${N}_THEMES); do if [ -d $BASE/drupal/sites/$S/themes/$T/CVS ]; then cd $BASE/drupal/sites/$S/themes/$T cvs -z6 up . -PAd else cd $BASE/drupal/sites/$S/themes cvs -z6 co -d $T contributions/themes/$T fi donedone

[ ! -z $UGID ] && chown $UGID -R $BASE/drupal

# vim: ts=4 sw=4 noet sts=4

Attachment Size

cvsdrupal.sh_.txt 4.9 KB

Advanced: Using a repository to track localchanges to Drupal codeNote: many people use subversion (SVN) as their local repository even though drupal.org usesCVS. Hopefully someone will writeup the process here

Note: The following assumes you have both basic knowledge of CVS and your own localrepository set up and working.

If you've been modifying the Drupal source code for your own purposes (or developing a moduleor theme) and manually applying your changes to the Drupal source every time it updates, youmay be glad to learn that CVS can help make this easier.

This is usually referred to as 'tracking third-party sources' and requires knowledge of the CVSconcepts branching, release tags, and the vendor tag. We'll work through an example here andexplain these concepts as we go.

ExampleLets assume we'd like to track current Drupal CVS HEAD, and start by downloading the source.In this case we'll export using anonymous CVS (we could also just download a tarball).

Begin by logging in to the anonymous CVS server, the required password is 'anonymous':

cvs -d:pserver:[email protected]:/cvs/drupal login

Then export the newest development version of drupal using the HEAD release tag:

cvs -d:pserver:[email protected]:/cvs/drupal export -r HEAD drupal

Now that we have a local copy of the drupal source we can import it into our own CVS repository.In this example we import with a log message including the date '-m "message text"', a modulelocation/name of 'sites/drupal' (customize that to suit your own CVS repository), a vendor tagof 'drupal' and a release tag of 'HEAD20040110'. We also use the -ko option to prevent keywordexpansion (this preserves the CVS $ Id $ tags used on drupal.org):

cd drupalcvs import -ko -m "Import CVS HEAD on Jan 10th 2004" sites/drupal drupalHEAD20040110

Before we can customize we need to checkout into a working directory. Then we can modify a fileor files and commit:

cvs checkout drupalcd drupal...modify a file or files...cvs commit

We now have a drupal module with a special 'vendor branch' (identified by the vendor tag), whichcontains the drupal source files we imported, and a main trunk with our modified files. Any filesmodified at this point are now HEAD on the main trunk of the module, whilst the unmodified filesremain HEAD on the vendor branch (HEAD being what is produced by cvs update). For anindividual file (fileone.php) the version history now looks like something like this:

HEAD +-----+

Page 102: Drupal - Installation Guide

[Main trunk] fileone.php *------------+ 1.2 + \ +-----+ +---------+[Vendor Branch] + 1.1.1.1 + +---------+ (tag:HEAD20040110)

Windows CVSNT

On Windows using CVSNT, if you're having problems with binary files being imported as text (sothat e.g. your *.png image files end up corrupted when you check them out), try cvs import -k+o... instead of cvs import -ko ....

Some experimentation (in CVSNT 2.5.03 on Vista) suggests that specifying "-ko" on the commandline may override the default "-k 'b'" flag specified for *.png files in $CVSROOT/cvswrappers,while "-k+o" works OK.

See also: http://www.cvsnt.org/manual/html/Wrappers.html. (Note that this will not change flagsfor files you have already imported into a repository, seehttp://www.cvsnt.org/manual/html/Binary-howto.html for information on how to fix theseindividually).

Additional resourcesArticle by Nick Patavalis: The mechanics and a methodology for tracking 3rd party sourceswith CVSThe section “Tracking third-party sources” in the CVS manualThe section “Tracking third-party sources” in a book on CVS

Managing contributionsNow I've been thinking about the best way to extend this method to incorporate contributions (eg,modules from the separate drupal.org contributions CVS repository or any other non-drupal-corecode). I would welcome comments/suggestions on a good model.

The model I'm currently using:

1. Maintain updated working copies of drupal HEAD and contributions HEAD from drupal.orglocally, something like:[HOST:~/drupal]$ ls -1contributionsdrupalimports

2. Import drupal into my local CVS repository with vendor/release tags as per method outlinedabove.

3. Maintain customized versions of drupal using CVS branches which can be diff'd/updatedagainst the latest drupal I've imported into my local CVS repository as suggested at the endof the method above.

4. Make a temporary copy of the complete, updated directory of whatever contribution I wantto add to drupal's core in a different and otherwise empty local directory so I can import itto my local CVS repository alone. For example, say I want to include the event module:[MP:~/drupal/contributions/modules]$ cp -r event ../../imports[MP:~/drupal/contributions/modules]$ cd ../../imports/[MP:~/drupal/imports]$ ls -1a...event

5. Import the contribution with its own vendor/release tags into the proper place in the HEADbranch of drupal I already have in my local CVS repository. In this example, I import theentire event module from the temporary directory that contains the event module directoryand only that directory. Note how the event module is imported into the proper directory (ie,"drupal/modules") of the drupal project in my local CVS repository:[MP:~/drupal/imports]$ cvs import -ko -m "Import module event HEAD on 04OCT 2004" drupal/modules module_event MODULE_EVENT_20041004cvs import: Importing /home/mediaped/repos/drupal/modules/eventI drupal/modules/event/CVSN drupal/modules/event/CHANGELOGN drupal/modules/event/CREDITSN drupal/modules/event/INSTALLN drupal/modules/event/LICENSEN drupal/modules/event/READMEN drupal/modules/event/TODON drupal/modules/event/event.cssN drupal/modules/event/event.moduleN drupal/modules/event/event.mysqlN drupal/modules/event/event.pgsqlN drupal/modules/event/fields.inccvs import: Importing /home/mediaped/repos/drupal/modules/event/poI drupal/modules/event/po/CVSN drupal/modules/event/po/event.potN drupal/modules/event/po/de.poN drupal/modules/event/po/es.poN drupal/modules/event/po/he.poN drupal/modules/event/po/hu.poNo conflicts created by this import

6. Now the contribution is included in the HEAD of the drupal project in my local CVSrepository, so if I update a working copy of that local drupal project (using the update -d

Page 103: Drupal - Installation Guide

option to ensure I get any new contribution directories) or checkout a new HEAD workingcopy, the newly added contribution will be in that working copy.

7. And, if I would like to add the contribution to one of the branches I have to maintaincustomized, separate versions of drupal, I just need to update a working copy of that branchwith the release tag I established when importing the contribution into my local CVSrepository. For example, to get the event module in a working copy of a branch tagged"drupalcustomA":[MP:~/projects/drupalcustomA]$ cvs -q up -d -j MODULE_EVENT_20041004U modules/event/CHANGELOGU modules/event/CREDITSU modules/event/INSTALLU modules/event/LICENSEU modules/event/READMEU modules/event/TODOU modules/event/event.cssU modules/event/event.moduleU modules/event/event.mysqlU modules/event/event.pgsqlU modules/event/fields.incU modules/event/po/de.poU modules/event/po/es.poU modules/event/po/event.potU modules/event/po/he.poU modules/event/po/hu.po

Note: if you try an update using your new tag and cvs complains that the tag doesn't exist,apparently you have to keep trying different cvs commands using that tag until cvs updatesCVSROOT/val-tags. Once you get the tag to work once, it will work from then on. See thesection here on error "cvs [checkout aborted]: no such tag".

8. This adds the event module files to that working copy, but I still have to commit them tothat branch in my local CVS repository:[MP:~/projects/drupalcustomA]$ cvs -q ci -m "adding event module"Checking in modules/event/......done

9. Then I can see that the event module is now a part of that branch by checking the status -vof one of the event module files:[MP:~/projects/drupalcustomA]$ cvs st -v modules/event/INSTALL ===================================================================File: INSTALL Status: Up-to-date

Working revision: 1.1.2.1 Tue Oct 5 06:46:30 2004 Repository revision: 1.1.2.1 /repos/drupal/modules/event/INSTALL,v Sticky Tag: drupalcustomA (branch: 1.1.2) Sticky Date: (none) Sticky Options: -ko

Existing Tags: drupalcustomA (branch: 1.1.2) MODULE_EVENT_20041004 (revision: 1.1.1.1) module_event (branch: 1.1.1)

10. Later, if there are significant changes to the event module, I'll update it using the samevendor tag, but a different release tag, just as it is demonstrated in the method above fordrupal itself. My local drupal head will get the latest event module and I can get it in mycustomized branches by updating them with the new release tag I make when importing thenew event module.

11. I will import every contribution I wish to include in my local CVS repository this way,giving unique vendor/release tags to each. That way I can pick and choose whichcontributions are included in any of my customized branches of drupal by updating eachbranch with the release tags of only the contributions I want in that branch.

Updating the vendor branchAt some later point the drupal source code will have been updated and we'll want to add theupdated version to our repository. We do this by repeating the process described above, we get afresh copy of the source from drupal.org, and import using the same vendor tag but change therelease tag from 'HEAD20040110' to reflect the newer version:

cvs import -ko -m "Import CVS HEAD on Jan 11th 2004" sites/drupal drupalHEAD20040111

This updates the vendor branch, a single files revision history can now appear four different ways,depending on whether it has been modified by us, by the vendor (drupal.org), by both, or not at all.

If the file was modified only by us, our modified version remains the head revision:

HEAD +-----+[Main trunk] fileone.php *------------+ 1.2 + \ +-----+ \ +---------+[Vendor Branch] + 1.1.1.1 + +---------+ (tag:HEAD20040110)

If the file was modified only by the vendor, the new version becomes the HEAD revision:

[Main trunk] filetwo.php *

Page 104: Drupal - Installation Guide

\ \ HEAD +---------+ +---------+[Vendor Branch] + 1.1.1.1 +----------+ 1.1.1.2 + +---------+ +---------+ (tag:HEAD20040110) (tag:HEAD20040111)

And if the file was modified by both us and the vendor:

HEAD +-----+[Main trunk] filethree.php *------------+ 1.2 + \ +-----+ \ +---------+ +---------+[Vendor Branch] + 1.1.1.1 +----------+ 1.1.1.2 + +---------+ +---------+ (tag:HEAD20040110) (tag:HEAD20040111)

Our version of filethree.php remains the HEAD revision, but this is clearly not desirable since itdoesn't carry the latest changes. In fact, during our import of the latest source CVS would havewarned us of conflicts between the two versions of filethree.php, we need to merge the changes toremove this conflict:

cvs checkout -jHEAD20040110 -jHEAD20040111 drupal

Examine the merged file to ensure the changes CVS made were sane and then ‘cvs commit’ thechanges back to the main trunk. Leaving us with a new revision which becomes HEAD:

HEAD +-----+ +-----+[Main trunk] filethree.php *------------+ 1.2 +-------+ 1.3 + \ +-----+ +-----+ \ +---------+ +---------+[Vendor Branch] + 1.1.1.1 +----------+ 1.1.1.2 + +---------+ +---------+ (tag:HEAD20040110) (tag:HEAD20040111)

SummaryIt should now be clear that using the CVS vendor tag to create a vendor branch in your own drupalmodule you can track changes to the drupal source code whilst also maintaining and developingyour own customizations and new features for drupal. This example has been kept very simple forthe purposes of explanation, but the basic process can be used to achieve many different things,some examples:

Track a specific release of Drupal (e.g. 4.3, or 4.2), instead of the development (CVSHEAD) version.Maintain your customized sites with modules, themes, static pages, images etc all added toyour CVS repository, whilst still tracking and importing updates to the drupal core.Branch your module to maintain several customized web sites off a single tracked branch ofthe drupal core.

Reading the following additional resources is highly recommended.

Configuring Apache and PHP for Drupal in aShared EnvironmentThese are some simple guidlines for setting up Drupal on a classic Linux-Apache-MySQL-PHP(LAMP) stack that provides a fair amount of security for the rest of your system.

PHP ConfigurationTo start, some common PHP configuration options can be optimized. On some systems, thesesettings may already be set, but it never hurts to add them yourself just in case.

PHP settings can be controlled in a number of ways. If you have access to the php.iniconfiguration file (usually found at /etc/php.ini), you can simply edit this file to cause system-wide changes. If you'd prefer to make these changes just for your Drupal installation, however, thebest place to do so is in your Drupal installation's settings.php file.

1. First, increase PHP's memory limit to avoid getting out-of-memory errors when you beginto add a few modules. These errors may look something like this:

Fatal error: Allowed memory size of 8388608 bytes exhausted (tried toallocate 30720 bytes) in /path/to/drupal/modules/system/system.module online 1022

2. In your php.ini file, include a line that reads: memory_limit = 16M. Or…3. …in your settings.php file, include a line that reads:

<?phpini_set('memory_limit', '16M');?>

Page 105: Drupal - Installation Guide

Apache Virtual Host ConfigurationIf you have access to your system's Apache configuration files (typically/etc/httpd/httpd.conf or /etc/apache2/httpd.conf), you can also make some simplechanges to simplify Drupal's multisite configuration for subdomains.

ServerName example.com

# Including a wildcard ServerAlias will direct all traffic to your end# users site and simplifies using Drupal's multisite configuration for# subdomains.

ServerAlias *.example.com

# This path will vary depending on your system. If you are using debian# make sure you drop the default images alias. Leaving it can be very# annoying to users on shared servers.

DocumentRoot /var/www/example.com/public_html

# Place the log where your end users can see them, and make sure they# are at the least readable to an end user.## Performance option:# You can move the Apache logs to another partition or drive to# get some small increases in disk i/o on heavily loaded servers.# You can symlink the log files to /var/www/example.com/logs/# to keep the persistent user interface, however it doesn't work in# chroot environments.

ErrorLog /srv/www/example.com/logs/error.logCustomLog /srv/www/example.com/logs/access.log combined

# Allow end users to manipulate their virtual hosts to their# hearts' content by enabling .htaccess files for them.

AllowOverride All

# Since mod_php doesn't like you to respect su_exec, and safe_mode is just# too paranoid to be usable, restrict php to the proper vhost but to alevel# above the DocumentRoot so users have some private file space for# .htpasswd, Drupal files, backups, etc.

php_admin_value open_basedir /var/www/example.com

# Move PHP's temporary files into the open_basedir restricted space.

php_admin_value upload_tmp_dir /var/www/example.com/tmp

# session.save path isn't really necessary for drupal since it# stores sessions in the database, but for general php enabled#vhosts it keeps session data tied to each vhost.php_admin_value session.save_path /var/www/example.com/tmp

MySQL Performance OptimizationTweaking the configurations for your MySQL database server can give you a boost inperformance. The MySQL configuration file is typically /etc/my.cnf.

# big ol mysql.querycache(128M) (be aware of your systems memorylimitations)query_cache_size = 134217728

# boost mysql max connections (min = (20*number of drupal sites))set-variable=max_connections=512

eacclerator

ModSecurity ConsiderationsModSecurity is an Apache module that applies a set of rules to the activities of software runon Apache. It is used by some hosting environments to assure security, but some rules caninterfere with the normal operation of Drupal. Because each ModSecurity administrator canwrite their own rules it is impossible to be certain that Drupal does not get caught up inthese rules.

It is possible for Drupal to get caught correctly. Before implementing the solutions below toturn of part or all of ModSecurity, be sure that Drupal is being caught improperly. Be certainthat the activity being stopped is not due to some malicious or potentially dangerous activityand that the security of your site will not be compromised.

It is possible, given the right permission or cooperation from your hosting company, toeither turn off specific rules for your site or turn ModSecurity off entirely for yourVirtualHost.

Turning off a Rule

If you can find the errors put in the logs when your Drupal installation fails, you can identifythe Rule ID and the location. Using this information you can disable a rule based on a path.

Page 106: Drupal - Installation Guide

Here is an example based on a rule ID of 990011 that interferes with the Drupal updatescript at /update.php. In many environments, these log entries are not available to the hosteeand must be examined by the hoster.

Here is an example of a what will appear in the logs. You'll note the Rule ID and path arebold.

[Wed Jan 20 11:43:01 2010] [error] [client 2.1.6.1] ModSecurity: Access deniedwith code 501 (phase 2). Match of "rx (?:^(?:application\\\\/x-www-form-urlencoded(?:;(?:\\\\s?charset\\\\s?=\\\\s?[\\\\w\\\\d\\\\-]{1,18})?)??$|multipart/form-data;)|text/xml)" against "REQUEST_HEADERS:Content-Type" required. [file"/etc/apache2/modsecurity_crs/modsecurity_crs_30_http_policy.conf"] [line"69"] [id "960011"] [msg "Request content type is not allowed by policy"][severity "WARNING"] [tag "POLICY/ENCODING_NOT_ALLOWED"][hostname "d6test.domain.com"] [uri "/update.php"] [unique_id "R5esoc-ASakAAHGeOqAAAAAI"]

<LocationMatch "/update.php"> SecRuleRemoveById 990011</LocationMatch>

Turning ModSecurity Off

If you can change the VirtualHost record, this may be used to turn off ModSecurity for aspecific VirtualHost.

<ifModule mod_security2.c> SecRuleEngine off</ifModule>

Enable hosting of multiple sites from a singleinstallationIf you are running more than one Drupal site, you can simplify management and upgrading of yoursites by using the multi-site feature. Multi-site allows you to share a single Drupal installation(including contributed modules and themes) among several sites. This is particularly useful formanaging the code since each upgrade only needs to be done once.

Each site would continue to have its own database and its own configuration settings so each sitewould have entirely different content and you can still specify the theme, modules and othersettings for each site.

Configure a new site

To create a new site using a shared code base you must complete the following steps:

1. Create a new database for the site.2. Create a new subdirectory of the 'sites' directory with the name of your new site.3. Copy the file sites/default/default.settings.php into the folder you created in the

previous step. Rename the new file to settings.php.4. Adjust the permissions of the new site directory, and grant write permissions on the

configuration file5. In a web browser, navigate to the URL of the new site and continue with the standard

Drupal installation procedure.

It may also be necessary to modify your Web server's configuration file (often named httpd.conffor Apache) to allow Drupal to override Apache's settings. This is true for all installations ofDrupal and is not specific to the multi-site install. Additional information is available in the BestPractices: Configuring Apache and PHP for Drupal in a Shared Environment section of theInstallation Guide.

Domains and URLs

The new directory name is constructed from the site's URL. The configuration forwww.example.com would be in sites/example.com/settings.php. You do not need to include'www' as part of the directory name.

Any sub-domain of example.com, including www, is served from that directory's settings unlessthere is an alternative, matching sub-domain sites directory. Installing a separate site in a sub-folder is also possible. For example, example.com, sub.example.com, and sub.example.com/site3can all be defined as independent Drupal sites using the following directory setup:

sites/example.com/settings.phpsites/sub.example.com/settings.phpsites/sub.example.com/site3/settings.php

Installing Drupal in a sub-folder is accomplished by adding a slash after the domain name andthen the name of the sub-folder, as in the site3 example above.

If you are installing on a non-standard port, the port number is treated as the deepest sub-domain.For example:

Page 107: Drupal - Installation Guide

http://www.example.com:8080could be loaded from sites/8080.example.com. The portnumber will be removed according to the pattern above if no port-specific configuration is found,just like a real sub-domain.

Domain-specific modules and themes

Each site configuration can have its own site-specific modules and themes in addition to thoseinstalled in the standard 'modules' and 'themes' directories. To use site-specific modules or themes,simply create a 'modules' or 'themes' directory within the site configuration directory. For example,if sub.example.com has a custom theme and a custom module that should not be accessible toother sites, the setup would look like this:

sites/sub.example.com/settings.phpsites/sub.example.com/themes/custom_themesites/sub.example.com/modules/custom_module

Document root

One area of frequent confusion is that in a Drupal multisite installation the webserver documentroot is the same for all sites. For example with the following three sites: example.com,sub.example.com and example.com/site3 there will be a single Drupal folder and all sites will becalling the same index.php file.

Some webhosts automatically create a folder (i.e. example.com) when creating a new domain. Inthis case it is necessary to create a symbolic link to the main Drupal folder.

Localhost

On many systems it is possible to create entries in a "hosts" file to create aliases for the localhostname for a local workstation. By creating aliases for localhost it is possible to create names suchas localdev1.example.com and localdev2.example.com, both for the local computer.

Domain name changes

Once a site is in production under the folder sites, it should not be renamed, even if the Web siteURL changes. This is because several database tables (for example: system, and files) includereferences to "sites/www.mydomain.com." Of course, instead of renaming the sites directory, youcan create a symlink to the new URL from the old one. Navigate to the sites directory and thenuse the following command:$ ln -s /path/to/drupal/sites/old.domainname.com new.domainname.com

Comprehensive Multi-site VideoRunning a successful multi-site install requires knowledge of how Drupal handles multiple sitesand how various features of Apache can be leveraged to make the multi-site much easier tomanage.

The video at this link provides a great deal of detail and comprehensive conf files for an Apachemulti-site install of Drupal

Video about Multisites vs. Multiple Sites at GotDrupal.com

Multi-site how-tosDo I need to copy each of these pages over to d7 or just reference them?

Do we need to prune or rearrange them?

Some of it seems redundant to other pages already created.

http://drupal.org/node/43816

Multi-site on LinuxSoftware installed:

Drupal 7Apache 1.3Red Hat 6.1 (Although other distributions will work)PHP5PostgreSQL 7.4

The process:

1. Install the Drupal core download from Drupal.org.2. Install default Drupal site. I created mine with a "dummyUSER" user and "dummyDB"

database with Drupal code in apache/htdocs/drupal3. Once you have this working then create a new dir "example1.com" directly under "sites" dir.

Page 108: Drupal - Installation Guide

mkdir sites/example1.com

cp -R sites/default/* sites/example1.com/

4. Create a new database "example1DB" and new user "example1USER" in database.5. Edit the sites/example1.com/settings.php and change the following:

$db_url = 'pgsql://dummyUSER:dummyPSSWDl@localhost/dummyDB';

to $db_url ='pgsql://example1USER:example1PSSWDl@localhost/example1DB';

(this step is optional, normally Drupal will recognise the base url automatically):# $base_url = 'http://www.example.com';

to $base_url = 'http://www.example1.com'; (Remove the '#' [comment])6. cp apache/htdocs/drupal/install.php to

apache/htdocs/drupal/sites/example1.com/

7. Point your browser to www.example1.com. Drupal will show you lot of errors.8. Once it shows you errors you are all good. Just point your browser to

www.example1.com/install.php and it will present you the installation screen. Install fromthere on.

9. Repeat the above process for www.example2.com

NoteIf it says the site is offline then your database information in settings.php is not correct. If it sayssite not found then your base url in settings.php is not correct.

Multi-site on MacTo get multi-sites working on apache on a Mac, see "HowTo: Configure your local workstation toserve multiple sites using Drupal's multisite configurations and Apache's VirtualHost".

Multi-site on Windows-ApacheSoftware

This guide assumes you have installed WAMPServer, which you can download below:

WampServer - includes Apache, PHP, and MySQL.

Alternatively, you can install another WAMP package, but you will need to adjust the paths as necessary.

Process

1. Set up Drupal as usual1. Install WampServer (or another 'WAMP' package) and make sure that Apache and

MySQL services are running.2. open phpMyAdmin in your browser localhost/phpmyadmin (or it can be launched via

the WampServer icon in your system tray.)3. Create a new database -- we'll call it drupal6 because this will be our base installation

which we will leave untouched. While you're here create a second and third database,which we'll call site1 and site2. You can also change the database privileges if youwant, but to keep things simple here, we'll stick with the default user root and nopassword.

4. Download Drupal 6 into WampServer's wamp/www folder (or the htdocs folder inXampp and some other packages). (You'll need a tool like 7-zip to unpack the Drupaltar.gz file).

5. Do your first Drupal installation by pointing your browser to your Drupal folder,which should be something like http://localhost/drupal-6.x. Enter the drupal6 databaseand user settings (root and no password in this example). Complete the installation,but then leave it alone.

2. Prepare the files for your new multi-sites1. Find Drupal's sites folder, make a copy of the default folder and rename it to the URL

you want for your first test site. To keep it simple, we'll make it the same as the firsttest site database: site1. While you're here, create files, tmp and themes sub-folderswithin this new folder. The themes sub-folder will be used for any custom theme youcreate specifically for this site. Similarly, you can create a modules sub-folder for anymodule you use only with this site. However, generally, I find it easier to keep allcontributed modules together in the sites/all/modules folder so I can use them with allmy test sites.

2. Use a text editor to open the settings.php file in your new site1 folder and change$db_url line to reflect your first test site database, and the database user name andpassword, eg:mysql://username:password@localhost/site1

Also, change the $base_url to the above site URL, eg:$base_url = 'http://site1'; // NO trailing slash!

3. Repeat the above 2 steps for the other test site (site2)3. Adjust windows so it can find the new site at a new made-up name

Find the Windows hosts file, which should be in Windows' System32/drivers/etc folder,make a backup of that file and then open the hosts file in a text editor. Here, add new linesmapping your localhost IP address to match the URLs of your test sites and your originalDrupal site. In our example, it would look like this:

127.0.0.1 localhost127.0.0.1 site1

Page 109: Drupal - Installation Guide

127.0.0.1 site2127.0.0.1 drupal6

This is telling Windows Networking that http://site1/ is a name for this machine.

4. Adjust Apache so it responds to requests for the new names1. Find the Apache httpd.conf file which, in WampServer, should be in the

wamp/bin/ApacheX.X/conf folder (where X.X is the Apache version number). Sorry, Ican't remember where Xampp installs this, but it will be in the Apache folder.Anyway, all you need to do with this file is make sure the "Virtual hosts" line is activeby removing the # before Include conf/extra/httpd-vhosts.conf.

2. Make a backup of that httpd-vhosts.conf file (which is in Apache's conf/extra folder),then open httpd-vhosts.conf with a text editor and add these lines:<VirtualHost *:80>DocumentRoot C:/wamp/www/drupal-6.xServerName site1</VirtualHost>

where C:/wamp/www/drupal-6.x is the path to the Drupal installation folder and site1is the URL for your first test site. Add another entry for your other test site, anotherentry for your original Drupal installation and another entry for WampServer'slocalhost URL (if you want to keep this active), eg:<VirtualHost *:80>DocumentRoot C:/wamp/www/drupal-6.xServerName site2</VirtualHost>

<VirtualHost *:80>DocumentRoot C:/wamp/www/drupal-6.xServerName drupal6</VirtualHost>

<VirtualHost *:80>DocumentRoot C:/wamp/wwwServerName localhost</VirtualHost>

3. Restart Apache for the changes to take effect. With WampServer, this is done byselecting the WampServer icon in the system tray and then "Restart all services".

5. Now you're ready to install each Drupal test site using your browser, eg:http://site1/install.phphttp://site2/install.php

And that's it. You can access your two test sites anytime WampServer is running by using thehttp://site1 and http://site1 URLs.

As I said, it's not exactly simple, but it is well worth the effort. Now you can do whatever you likewith your test sites. If you mess up with, say, site1, just delete the site1 folder, the site1 databasein phpMyAdmin and the site1 entries in the Windows hosts and Apache httpd-vhosts.conf files andstart again. Alternatively, if a site works out and you want to go live with it, the multi-siteapproach makes this easier (in my opinion).One final caveat: I'm no expert. This technique works for me (apart from one corporateenvironment with a particularly annoying proxy server), but I'd welcome any feedback, especiallyif there are any accuracies.

Multi-site on Windows-IISPrerequisitesThis guide assumes you have the following installed and running:

Microsoft's Internet Information Services web server 6 or 7PhP 5.2 or higher with PDO dlls enabled.The IIS FastCGI Module (IIS6 version here - in IIS7 it's an integrated module that needs tobe enabled).MySQLIf you want clean urls, you'll also need the URL Rewrite module (IIS7) or a third-party url-rewrite module set up at some point, though you can do this afterward.

Process1. Install a site. This will be the parent site, providing the code-base for all the child sites.

IIS7: be sure your parent site has a web.config file (see this for more info). Child sites willuse the settings in the parent site's web.config file. To override these settings, put aweb.config file with just the settings you want to override in the child site's folder (egsites/site2.com/).

2. Create child site folders. Decide how you want people to navigate to your sub-site. In theparent site's /sites/ folder, create sub-folders for each new site you wish to install.

Example 1: parentsite.com/subsite/ - in parent /sites/ folder, create/sites/parentsite.com.subsiteExample 2: subsite.parentsite.com - in parent /sites/ folder, create/sites/subsite.parentsite.comExample 3: subsite.com - in parent /sites/ folder, create /sites/subsite.com

Page 110: Drupal - Installation Guide

3. Copy the files & private subfolders. Go into the parent site's sites/default folder, and copythe /files and /private folders. Navigate to each new child site's folder (egsites/parentsite.com/subsite/) and paste them.

4. Create child site settings.php file(s). Into each child site folder copy the parent's/sites/default/settings.php. Make each settings.php writable to IIS_WPG (IIS6) orIIS_IUSRS(IIS7).

5. Create IIS Site Mapping or Virtual Directory, depending on how you set up your sitestructure.

IIS7 - Start the IIS Manager.

Example 1: parentsite.com/subsite/ - Right-click on parentsite.com | Add virtualdirectory. Alias: [new site name, eg subsite]. Physical path: [parent site's physicalpath]. Click OK.Example 2: subsite.parentsite.com - Right-click on Sites | Add web site. Site name:[new site name, eg site2]. Click to select the application pool, and select the parentsite. Physical path: enter the parent site's physical path. Host name: [new site url, egsite2.localhost]. Click OK.Example 3: subsite.com - add a web site as example 2, calling the host namesubsite.com.

6. Set up the database(s).

Multiple databases - If you want each site to have it's own database, create them now.

For each child site, change settings.php to include each site's database name, username, andpassword:

$databases['default']['default'] = array(<br /> 'driver' => 'mysql',<br /> 'database' => 'databasename',<br /> 'username' => 'username',<br /> 'password' => 'password',<br /> 'host' => 'localhost',<br /> );

Single database - See this tutorial.

7. Run the setup script for each site, eg http://site2.localhost/install.php.

Multi-site with single codebase, differentcontent databases, shared user database,shared sign-onIMPORTANT NEW INFORMATION - In light of this comment regarding the ability of Drupalto handle different databases this HOWTO has been re-written. You do not need to use MySQLviews at all to achieve this functionality.

WARNING - Following this approach will make updates potentially trickier. It's not a majorissue, but you must be mindful that you are sharing some tables amongst several Drupal instances,so you will need to be aware of install and update hooks which want to make changes to anyshared tables. For example, it is possible for the update or install scripts of a module unique to oneinstance to break other instances if it makes changes to shared tables. There are other multi-sitesolutions, so plan carefully before selecting which one is right for you.

This tutorial makes two assumptions:

1. You are _not_ a total newbie2. You have downloaded MySQL GUI Tools (to make life easier) - clearly this is not a pre-requisite - if you know and prefer command line MySQL then you can replicate the steps I provideeasily enough:http://dev.mysql.com/downloads/gui-tools/5.0.html

Make a copy of /sites/default to /sites/site1 and another to /sites/site2. You may add modules andthemes directories in these new directories in the usual way for site-specific configurations. A filesdirectory should be there already but create it if not. Rename /sites/site1/default.settings.php tosettings.php and /sites/site2/default.settings.php to settings.php (and, for Linux, make sure bothnew files directories are writeable by the web user).

Add these lines to your hosts files:

127.0.0.1 site1127.0.0.1 site2

Create three empty MySQL databases:

drupal_site1drupal_site2drupal_shared_tables

Go to http://site1 and run through the install process in the normal way, using the database name'drupal_site1'.

In MySQL Administrator create a new back-up project of the 'drupal_site1' database containing

Page 111: Drupal - Installation Guide

In MySQL Administrator create a new back-up project of the 'drupal_site1' database containing_only_ the tables you want to share, save it and run it. The result should be a .sql file somewhereon your computer. For reference, the Drupal 6.x tables for sharing users are as follows:

authmapprofile_fieldsprofile_valuesrolesessionsusers

(This is not a definitive list. Nothing stops you from sharing taxonomy, etc. For example, with thisconfiguration permissions are _not_ shared - each site has its own permissions matrix - but youmight want to share one across all sites. Ditto with enabled modules.)

Edit the .sql script you created and update the database name within to 'drupal_shared_tables'.Using the Restore interface, run the .sql script. You should now have a database called'drupal_shared_tables' containing only the list of tables above.

Go to http://site2 and run through the install process in the normal way, using the database name'drupal_site2'.

Go back to your original 'drupal_site1' database and drop the same list of tables from the schema.Ditto for the 'drupal_site2' database.

Now our databases are ready.

Browse to your Drupal application and edit /sites/site1/settings.php. Change these lines (usuallystarting at line 93 in Drupal 6.3):

<?php$db_url = 'mysqli://user:password@localhost/drupal_site1';$db_prefix = '';?>

To:

<?php$db_url = 'mysqli://user:password@localhost/drupal_site1';$db_prefix = array( 'default' => '', 'authmap' => 'drupal_shared_tables.', 'profile_fields' => 'drupal_shared_tables.', 'profile_values' => 'drupal_shared_tables.', 'role' => 'drupal_shared_tables.', 'sessions' => 'drupal_shared_tables.', 'users' => 'drupal_shared_tables.',);?>

Note the all important trailing dot on the end of drupal_shared_tables - this is vital! You're pre-pending table name info to Drupal's default table name, so you need the dot or Drupal will try toselect:

drupal_site_1.drupal_shared_tablesauthmap

Instead of the desired:

drupal_shared_tables.authmap

Do the same for /sites/site2/settings.php, but with $db_url set to drupal_site2.

You should now be able to login as the super user on both sites separately (http://site1/user orhttp://site2/user), using the credentials you entered when you installed site1, give them bothdifferent settings, modules, permissions and content but use the same user credentials. Moreover,if you create a user on site1, you will see them in users in site2, but with an entirely independentset of permissions you can decide on a site level.

Now for the shared logins. Download and unzip the Shared Sign-On module in to/sites/all/modules. Enable it in both sites and go to the settings (admin/settings/singlesignon). Setthe 'Master URL' to http://site1 for both sites. (Note, you could have two sets of sites with different'Master URL' settings, effectively two shared sign-on groups - this is untested by me.) Savesettings and logout. Clear your cookies to avoid any hang-overs from pre-shared-sign-on days.

Go to http://site1/user and login. Now go to http://site2. You should stay logged in. Logout againand see you are logged out in both locations. Reverse it so you login on site2 and visit site1. Neat,huh? =)

Need a new site? Take a copy of /sites/default to /sites/new-site, make the necessary vhosts(optional, see below) and DNS/hosts changes, create a blank database, run the Drupal installer,drop the tables you don't want from your new database (the shared ones), edit settings.php addingthe $db_prefix array as above, configure Shared Sign-On and you're done!

Optional Apache settings

If you would like to set different Apache settings for your various sites (e.g. different access anderror logs for each) add a vhost entry to Apache looking something like this:

<VirtualHost *:80> DocumentRoot "c:/path/to/drupal" ServerName site1

Page 112: Drupal - Installation Guide

ServerAlias site2 <IfModule log_config_module> CustomLog logs/d6_access_log.log common </IfModule> ErrorLog logs/d6_error_log.log <Directory "c:/path/to/drupal"> Options +Indexes AllowOverride All Allow from all </Directory> </VirtualHost>

This is not usually necessary.

IMPORTANT - if you provide web services, the site hosting them _must_ have a line in the'Target URL' box of Shared Sign-On settings (admin/settings/singlesignon) referring to eachendpoint your site provides, for example:

\/services\/xmlrpc$

This example is for the XML-RPC server provided with the Services module. Adjust to suit yourendpoint(s). You do not need to do this if your site hosting the web services is also the 'MasterURL'.

Notes on Multi-sites with Separate Code basesA simple Multi-Site install uses different databases for each site that the installation is hosting. Ina nutshell, a simple Multi-Site extends a "Singular-Site" installation by the web developer (that'syou) adding folders for each site that is served by the installation, in the "sites" directory.

The "default" FolderWhen you install a fresh copy of Drupal, a "default" folder is created inside"theRootOfYourInstallation/sites". Inside this folder resides a file called "settings.php" whichcontains this line of code:$db_url = 'mysql://username:password@pathTodataBase'; tosecurely access your database.

During the initial database installation wizard, Drupal populates that particular line of code withvalues you entered into the fields.

The reason this is called "default" is because, well, this is the default folder that Drupal looks intoto find (in the "settings.php" file) they keys to access the databases. The "default" folder can alsocontain other items, such as a folder called "files" that contains the files for the default installation.

The Key to Understanding Multi-SitesFor continuity, I will use "example.com" as the domain name for the "default"installation / folder and "doesthiswork.com" as the domain name for the site we areadding to this installation.

Now that you know about the "default" folder, you can begin to understand how to add multiplesites to one installation: to add another site to this installation,

1. Create a sibling of the "default" folder with the domain name of "doesthiswork.com" . It isway important to use the extenstion (the .com or .edu, or .org).

2. Inside this folder, you will include a fresh version of "settings.php" (renamed from a"default.settings.php" taken from the zipped files of fresh Drupal core files)

3. Make sure that you have a fresh database created with no tables in it. Write down the path tothe database, the username and password

4. Now you are ready to point your site to the root of the installation. The tricky part of this"simple" instruction is find where your DNS provider lets you point to another site. Anexample of a solution to this step is this: Say my "default" domain name (that goes to thedefault folder) is http://www.example.com and a domain /site that I want to add to thisinstallation is http://www.doesthiswork.com. In the DNS panel forhttp://www.doesthiswork.com, I would point the CNAME to http://www.example.com.When Drupal gets a request for "doesthiswork.com", it will find the doesthiswork.com folderin sites.

5. The first time you go to "doesthiswork.com", you will be greeted with the welcoming DrupalInstallation Wizard". Once you finish the installation wizard, the keys to your databasekingdom will be saved an you will be free to enter your new Drupal site.

So, what's the key to understanding how this works? It is: for every site that you add on thisinstallation, you will need to create a separate domain name folder in sites with (at least) a"settings.php" file. Each folder/settings.php file points to a different database installation.Drupal uses the files stored on the multisite server, in addition to the data in each database to serveup the site.

For each new site that you add, you will have to run through the installation wizard, setting up thesite and adding content. (See installation profiles to make your life easier!) To reiterate: when youupdate a module, you will have to run "http://www.example.com/update.php" and"http://www.doesthiswork.com/update.php" (and other update.php's for each site on your multi-siteinstall) to update EACH database. You might think that this is still alot of work... but it really is atime saver.

Page 113: Drupal - Installation Guide

Remember to:

put your sites in maintainence mode (admin/settings/site-maintenance)beforerun cron manually (admin/reports/status/run-cron)and clear the cache (admin/settings/performance)

after you run update.php !

Additional Files to place inside your "default" siblingYou can also have

FilesThemeModules

as folders in the "doesthiswork.com" folders. Those items will only be seen by the"doesthiswork.com" installation. As you might have guessed, items in the"theRootOfYourInstallation/sites/all" folder will be avaliable to ALL the site in your Multi-siteinstall.

If you place all your modules in the "theRootOfYourInstallation/sites/all" folder, when youupgrade to an newer version, you only have to replace the module there. However, you need to"update.php" on all sites in your multi-site... including your default site.

One of the things that can trip you up is forgetting to create a "files" folder in your"doesthiswork.com" folder. Make sure you have done that to keep separate files from "different"sites.

Installation how-to articlesVarious special situations (e.g., installing Drupal behind a firewall, installing Drupal in asubdirectory of the webserver's document root) are discussed in this section. Information specificto particular operating systems or database platforms may be found elsewhere.

Beginner's guide for Cron on a shared hostingproviderThis guide is excerpted from the original article on ThemeBot.com: Time to talk about Cron - a beginner's guide

If you have downloaded and installed Drupal 5, you will notice that there is an error in theadministrative log when you first sign in with your administrative account.

One or more problems were detected with your Drupal installation. Check thestatus report for more information.

When you look at the status report you can go ahead and click the link "run cron manually" andthis will remove the error. However, you will eventually want to set up a Cron job to do this.Having the Cron maintenance run regularly on an automatic schedule is important for keepingyour site indexed. If this is not done, new content that is added will not be included in searchresults. Cron can also perform other tasks in Drupal, such as cleaning up log files. Also, some ofthe contributed modules require that Cron maintenance is run regularly.

With the Drupal 5 installation package, there is a script included for Cron and it is called cron.php.This file is located in the root directory of your Drupal installation. You can actually run Cronmaintenance by entering, for example, the URL "http://www.yourwebsite.com/cron.php" into aweb browser.

We want to get this done automatically. You can achieve this one of two ways: using the cronservice on your server or use the Poor man's Cron module. If you have the cron service availableon your host, this is recommended since it will run more regularly. This example will use cron andthe Lynx browser. Lynx is a text browser that is often installed on servers. You will need tocontact your hosting provider to make sure that they have Lynx installed (most probably do).

Once you know that Lynx is installed, you will need to find the configuration panel for setting up aCron job in your hosting account.

The first thing to do is enter the command. The following example is the command I use to makeLynx run cron.php:

lynx -source http://www.example.com/cron.php

You may need to adjust this command depending on your hosting provider.

The next step is to decide on a schedule to have this Cron job run. Running Cron does use systemresources, so you don't want to have it running every minute if you don't need to. It is up to you todecide on an appropriate schedule for having each Cron job run. Understanding the format forentering a schedule can take a little getting used to. Here is a quick rundown on schedulingoptions that can be entered:

Page 114: Drupal - Installation Guide

Minute — any integer from 00 to 59 (specifies the minute the job will be run on)Hour — any integer from 0 to 23 (specifies the hour the job will be run on)Day — any integer from 1 to 31 (must be a valid day if a month is specified)Month — any integer from 1 to 12Weekday — any integer from 0 to 7, where 0 or 7 represents Sunday

The asterik (*) specifies that the task should be run every time for any sub-constraint. Thisstatement doesn't even make sense to me so let's just have a look at the examples to figure it out.You can also use the command */ to have jobs run every interval. Here the examples to help youget the hang of it.

Run cron.php task every 30 minutes:*/30 * * * * lynx -source http://www.example.com/cron.php

Run cron.php task once a week at 1:00 am every sunday (you can see that sunday isrepresented by 0):00 1 * * 0 lynx -source http://www.example.com/cron.php

Run cron.php task on the first day of every month at 12:00 am (midnight) :00 0 01 * * lynx -source http://www.example.com/cron.php

I hope this is helpful for beginners who have installed Drupal and are wondering how to setupCron.

More information can be found under the Configuring cron jobs page in the handbooks.

Checklist for migrating to a new serverSome things to look for when moving Drupal to a new host and taking your site live.This checklist is targeted at folk who have already successfully got a site running either locally oron a hosted server but need to move it to another host or architecture. There's (quite) a few thingsthat can be different on different servers or versions, so there's a lot of extra testing that needs tobe done, even if you think your site was solid to begin with.It looks like a big list, but most of these issues should be set correctly already. But they need to beconfirmed before you can be confident your transfer will go without a hitch. Many you will havedone before but you now need to remember to do again.

If you've already uploaded without following this checklist and are now a bit stuck, you may findit neccessary to unset clean-urls manually before you can proceed with troubleshooting.

Server basics

Verify Clean-Urls in Apache. Confirm AllowOverride All is in effect, and mod_rewrite isavailable.Ensure that when you uploaded, the Drupal .htaccess file went up as well. On some systemsthis file is hidden.Check DB support via phpinfoD7 requires not just MySQL but pdo_mysql as well.Check GD image toolkit support in phpinfo, or in the Drupal admin status page.Decent php memory_limit (32 M) (phpinfo, php.ini)Decent php upload_max_filesize, post_max_size (phpinfo, php.ini) For Drupal to behave asexpected, post_max_size must be 2x upload_max_filesizeCheck allow_url_fopen for updates and aggregation if required.Check that the include_path contains '.'Check that safe_mode is offCheck the error_reporting level. You may want it on when installing, but remember to turn itoff on production.This and more is covered in the Drupal 'requirements' doc and of course INSTALL.txt is thefirst reference to look at.Set up cron! Remember!If your host is Debian/Ubuntu less than php5/5.2.6-2 PHP sessions may not get cleared correctly, and you mayneed a workaround for Debian session garbage collection

Drupal UI

TEST an upload.TEST an image derivative rebuild.Review access control settings for admin/editor/authenticated/anonymous users. Log in aseach role and check a few things like the ability to upload big files, use input filters.I've been stung a few times by setting up as user #1 and handing over to an 'editor' role client who then found theystill had incorrect upload size limits etc.

Permissions checks

Adjust write-access to sites/${SITENAME} (if installing) and sites/${SITENAME}/filesCheck at admin/settings/file-system, it'll warn you if there's a problem.What you need to do and what you CAN do to adjust permissions on the server willvary between systems.

check write-access to /tmp . Change it to sites/${SITENAME}/files/tmp (no leadingslash) if needed.

Page 115: Drupal - Installation Guide

Security tweaks

Once you are set up, consider locking all the code to read-only for security.See more at File Permissions and Ownership For Security.Check the owner and group of any newly created files and foldersls -la files/

If the owner of web-process created files is the same as your login username (not www-data), that means it'stheoretically possible for web scripts to modify themselves. This is a hack vector, and could be a concern.Check access to your settings.php. It contains your database password in plaintext, and itwould be good to NOT have that readable by anyone other than your web process.Unfortunately that means it's readable by anyone running the web process on that machine.For this reason, it would be good to have your :- Admin-control panel-ssh login password different from your- database password different from your- Drupal user #1 password....even though that's a pain.If you have enough rights, consider shifting htaccess directives into apache configurationfiles for performance.Remove phpinfo.php if you had one.

Testing

TEST directory browsing is disabled for files/ (by attempting to access it in a browser)TEST that www.example.com and example.com perform the same, preferably by redirectingone to the other. See .htaccess [handbook doc needed?]TEST email sending. Email setup is different for different hosts, but should be configuredalready by the sysadmin.Check the email:from headers and see what you can do to avoid system emails going into aspam bucket

More testing ideas.

Best Practice Extras

Run a links checker. Xenu is simple for windows. linklint is adequate for commandline.Visit your admin/reports after running a link checker and see what shows up. Other errors,not just 404s may appear there and need attention.Consider benchmarking Drupal Performance. apachebench (ab) is OK, but needs root andjust whacks one page. siege is better (can script a session), but needs installing.If you have a high level of control on the server, Consider other tuning issues like PHPaccelerators.Consider your backup plan.TEST your backup recovery.Remember to configure and test any non-Drupal logging tool you may want to use. eg,Webalizer, Google Analytics or something provided by your host.Now is a good time to locate your server logs, and make sure you have access to them from your host. When youneed them to troubleshoot problems it's too late to find that they don't exist.Document every password, path and IP you can find. Domain registration, Control Panellogin, User account info, FTP server, MySQL connection string, location of the config filesfor your backups, contact details for key parties etc. Put it all in a document with a DATE init. Print that off and save it in three SAFE places.Review your hosts policies on overages. It's much better if your host provides a warning &throttle service when/if you overrun your bandwidth or storage allocation than if they let itrun then charge and penalize you (or just shut you down). Some hosts also punish 'excessive'use of the database or processor - which Drupal can be guilty of. Read the fine print.

References:Server and database configuration settings

Complete Drupal install shown by screencastThe screencast at http://mrdychko.info/node/38 gives a complete walkthrough for installing Drupalon shared hosting with Hostmonster.com. It was recorded live during a professional developmentsession for high school teachers. It includes: sign-up process, uploading and extracting files,creating a MySQL database, running the Drupal install script, installing modules, configuringphp.ini to allow larger file uploads, creating a new content type which includes a file upload field,creating a view (with the Views module) to display uploaded files, and setting up a cron job. Allin 42 min and 24 seconds!

Configure .htaccess to allow awstats to workwith clean URL'sWhen I installed Drupal with clean url's it made my Awstats (within the cgi-bin) not work and justreturn a Drupal page not found error.

Drupal is installed in the root directory (public_html) of my web space so is the cgi-bin folder thatAwstats is in.

Page 116: Drupal - Installation Guide

I fixed the problem by changing the protect files and adding 1 rewriteCond line to the .htaccess fileas follows:

In the FilesMatch section, find " |code-style\.pl " without the quotes and remove it from thefollowing code:

# Protect files and directories from prying eyes.<FilesMatch "(\.(engine|inc|install|module|sh|.*sql|theme|tpl(\.php)?|xtmpl)|Entries.*|Repository|Root)$"> Order deny,allow Deny from all</FilesMatch>

Now add this line (RewriteCond %{REQUEST_URI} "!cgi-bin/") to the following:

# Rewrite current-style URLs of the form 'index.php?q=x'. RewriteCond %{REQUEST_URI} "!cgi-bin/"

RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

This was all done on the default install of Drupal w/.htaccess.

Configuring .htaccess to ignore specificsubfoldersIgnoring Subfolders that exist in the DocumentRootWith clean URL's enabled, when running other software applications in subfolders (subdirectories)of a Drupal root installation. your .htaccess file may rewrite those URL's to Drupal. This may be aparticular problem for those with a Drupal installation in the root of their domain using Cpaneland Fantastico where Fantastico installs other software into subfolders. For example,phpSurveyor's admin interface as installed by Fantastico will not work with Drupal's default.htaccess settings. The URL for the admin interface is inaccessible and will return a "page notfound" page in your Drupal site.

The trick is to modify .htaccess to ignore specific files/folders. So for example, if you have twofolders, <folder1> and <folder2> in the root of your Drupal installation, modify your .htaccess fileby inserting the following code directly after the "RewriteEngine on" directive, before the Drupalrewrites:

=========[ start of .htaccess snippet]==========<IfModule mod_rewrite.c> RewriteEngine on # # stuff to let through (ignore) RewriteCond %{REQUEST_URI} "/folder1/" [OR] RewriteCond %{REQUEST_URI} "/folder2/" RewriteRule (.*) $1 [L] #====================[ end ]=====================

For each folder you want to bypass, add a RewriteCond line, and end all but the finalRewriteCond with [OR]. Note that the [L] in the rewrite rule tells it to stop there and bypass therest of the rewrite rules.

Ignoring subfolders that are included via Apache AliasdirectivesAs of 4.7, files and directories should be automatically allowed through in drupal's .htaccess setup.Thats what the !-f and !-d lines do.

However if you are working with Apache Alias or similar directives the file doesn't actually existso drupal will take over like it should. The best way around it is to just add one more conditionalthat matches your location and make it skip it too. Thats what the ! means. Please see below:

RewriteCond %{REQUEST_URI} !^/yourDirectoryNameRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

It essentially means Apply this rule if the REQUEST_URI doesn't start with /yourDirectoryNameand the REQUEST_FILENAME isn't a real file or a real folder. Which is exactly what you want.There is an implied "AND" between the lines of that rule. The ! says "not like this".

Restore support for other Directory Index Files (index.htm)Drupals .htaccess file also includes a line (DirectoryIndex) that gives instructions "If asked for adirectory path, return the index.php file found in that directory". This replaces the normalwebserver behaviour that usually says "return the index.htm file found there".

The good news, it that it's easy to say both. And that's what we need to do to allow other folders of

Page 117: Drupal - Installation Guide

HTML content to co-exist with Drupal and server them as expected.

Method 1 - Allow index.html anywhere

Edit Drupals .htaccess file and change the DirectoryIndex line to read:

DirectoryIndex index.php index.html index.htm

Now index.htm and .html files may be served if no index.php is found. You can add otherfilenames as needed.

Method 2 - Allow html (and folder listings) in the subdirectory

You may also avoid changing Drupals .htaccess, and just set the preferences for the relevantsubfolder. This is a little more specific, accurate, and maybe secure.

Create a new .htaccess file in the target folder, eg folder1/.htaccessAdd the lines

DirectoryIndex index.php index.html index.htmOptions +Indexes

Now index.htm and .html files may be served from there.Additionally, the default Apache 'raw folder listing' behaviour has been restored, so you can seewhere you are even if there is no index file in the folder. This is optional, but may be useful toyou. It is advised you do not allow folder listings at the Drupal level.

There's a heap more possible, but it's all in the Apache Docs so go there for more info andexamples.You may also want to adjust the 404 behaviour for that subfolder too.

Create Drupal database using PleskCreate the databaseLogin and select Services » Databases

This loads a page with an overview of databases. Depending on your host a database may alreadyhave been created. This is often the case with low-budget hosts, where you are limited to onedatabase. In that case, use table prefixing. If no limits exists it is best to create a new database forDrupal via: Add New Database.

Click on the name of the database you wish to use. In the overview page you'll see all users forthis database. Again, depending on your host, you need to create a new user via: Add NewDatabase User.

If you do not have the option to create new database users, use a pre-existing one.

Load the Drupal database schemeFrom the database users overview page click DB WebAdmin

The icon is a blue stack with a monkey wrench. Note that this opens phpmyadmin in a pop-upthat may be blocked by your browser.

First make sure the relevant database is selected. If necessary, click Databases in the phpmyadminstart screen and then the database name.

Go to the SQL screen via a small button labelled SQL in the left pane of the phpmyadmin screen.

If you've created a new user for the Drupal database, you need to grant priviliges to the user:execute the SQL query:

GRANT ALL PRIVILEGES ON databasename.* TO username@localhost IDENTIFIED BY'password';

where

'databasename' is the name of your database'username@localhost' is the username of your MySQL account'password' is the password required for that username

This may not complete successfully; in that case you'll have to assume / hope the user was createdwith the necessary privileges.

To create the database layout, select the tab import files. Upload the filedatabase/database.mysql with the database scheme.

Having had the virtual server I use upgraded to Plesk 7.5.4, I attempted to install drupal. I amhaving no joy, which is a pretty big disclaimer to my comment here - seehttp://drupal.org/node/20397 - but I think it is unrelated to this.

I can't grant all privs to the mysql user as per this page. I think this article is out of date as a) thedb user plesk creates doesn't have the grant privs so there's a difference in Plesk versions going onhere and b) there is no way for the end-user to set this so it follows that Plesk does this for you,which ties up with the fact I can upload the schema and the users are being added.

Page 118: Drupal - Installation Guide

I checked the mysql documentation and couldn't find a command to report the priviledges a userhas, so I couldn't verify this directly.

Create a custom php.iniThis article explains how to set up a custom php.ini that overides your servers default php.ini,providing an easier alternative (in the long run) than using .htaccess to overide php.ini settings.Itassumes that you have a ssh account set-up and are using a ssh client (e.g. putty -http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html). You are also expected tologically replace directory structures given here, with your own, if they are different.

Procedure for allowing php.ini configuration for a website (shows changing file upload max)

1/ Create a cgi-bin Directory

First you’ll need a cgi-bin directory:

mkdir ~/[your website directory]/cgi-bin/

This directory will be hosting your copy of php and your php.ini file.

2/ Create a script to retrieve the latest copy of php.cgi and php.ini

Make a file in ~/ called php-copy.sh containing the following, where 100M contains whatever filesize limit you like, and [your website directory] is appropriately substituted.

For PHP4:

#!/bin/shCGIFILE="$HOME/[your website directory]/cgi-bin/php.cgi"INIFILE="$HOME/[your website directory]/cgi-bin/php.ini"rsync -a /dh/cgi-system/php.cgi "$CGIFILE"# REMOVE THE FOLLOWING LINE TO CREATE THE UPDATE-ONLY SCRIPT:cp /etc/php/cgi/php.ini "$INIFILE"

perl -p -i -e 's/.*post_max_size.*/post_max_size = 100M/;s/.*upload_max_filesize.*/upload_max_filesize = 100M/;' "$INIFILE"

For PHP5:

#!/bin/shCGIFILE="$HOME/[your website directory]/cgi-bin/php.cgi"INIFILE="$HOME/[your website directory]/cgi-bin/php.ini"rsync -a /dh/cgi-system/php5.cgi "$CGIFILE"# REMOVE THE FOLLOWING LINE TO CREATE THE UPDATE-ONLY SCRIPT:cp /etc/php5/cgi/php.ini "$INIFILE"

perl -p -i -e 's/.*post_max_size.*/post_max_size = 100M/;s/.*upload_max_filesize.*/upload_max_filesize = 100M/;' "$INIFILE"

A more general script with options (for references purposes only, do not do this):

#!/bin/sh

test $# = 0 && exit 1while test "$1";do case $1 in -php5) PHP=php5 ;; -sm) shift; SM=$1 ;; -rg) shift; RG=$1 ;; -pms) shift; PMS=$1 ;; -umfs) shift; UMFS=$1 ;; -mqg) shift; MQG=$1 ;; -met) shift; MET=$1 ;; -mit) shift; MIT=$1 ;; -ml) shift; ML=$1 ;; *) D=$1 ;; esac shiftdonetest "$D" || exit 1test -d "$HOME/$D" || exit 1CGI="$HOME/$D/cgi-bin"mkdir -m0755 -p $CGI || exit 2

PHP=${PHP:-php}SM=${SM:-On}RG=${RG:-Off}PMS=${PMS:-8M}UMFS=${UMFS:-7M}MQG=${MQG:-Off}MET=${MET:-30}MIT=${MET:-60}ML=${ML:-8M}

CGIFILE="$CGI/$PHP.cgi"INIFILE="$CGI/php.ini"

echo "CGI=$CGI MQG=${MQG} UMFS=${UMFS} PMS=${PMS} RG=${RG} SM=${SM} MET=${MET}

Page 119: Drupal - Installation Guide

MIT=${MIT} ML=${ML}" >&2

rsync -au /dh/cgi-system/$PHP.cgi "$CGIFILE"[ -s /etc/$PHP/cgi/php.ini ] && \ sed -e "s/^safe_mode[ ]*=.*/safe_mode = $SM/" \ -e "s/register_globals[ ]*=.*/register_globals = $RG/" \ -e "s/magic_quotes_gpc[ ]*=.*/magic_quotes_gpc = $MQG/" \ -e "s/.*post_max_size.*/post_max_size = $PMS/" \ -e "s/.*upload_max_filesize.*/upload_max_filesize = $UMFS/" \ -e "s/.*max_execution_time.*/max_execution_time = $MET/" \ -e "s/.*max_input_time.*/max_input_time = $MIT/" \ -e "s/.*memory_limit.*/memory_limit= $ML/" \ # REMOVE THE FOLLOWING LINE TO CREATE THE UPDATE-ONLY SCRIPT: /etc/$PHP/cgi/php.ini > "$INIFILE"

chmod 0755 "$CGIFILE"chmod 0644 "$INIFILE"[ -s $CGI/.htaccess ] || echo "Options -Indexes" > $CGI/.htaccesstouch $HOME/$D/.htaccessif grep -q '^Options' $HOME/$D/.htaccess; then grep -q '+ExecCGI' $HOME/$D/.htaccess || \ sed -i 's/^Options\(.*\)/Options\1 +ExecCGI/' $HOME/$D/.htaccesselse echo "Options +ExecCGI" >> $HOME/$D/.htaccessfigrep -q '^AddHandler[ ]\+php-cgi[ ]\+.php' $HOME/$D/.htaccess || echo "AddHandler php-cgi .php" >> $HOME/$D/.htaccessif grep -q '^Action[ ]\+php-cgi' $HOME/$D/.htaccess; then sed -i "s@^Action[ ]\+php-cgi.*@Action php-cgi /cgi-bin/$PHP.cgi@" \ $HOME/$D/.htaccesselse echo "Action php-cgi /cgi-bin/$PHP.cgi" >> $HOME/$D/.htaccessfi

3/ Prepare script for execution

Execute the following commands into the shell. This will give you permission to execute the php-copy.sh that we just created.

chmod +x php-copy.sh

This calls our new shell script to copy the php.cgi and php.ini files into our cgi-bin directory.

./php-copy.sh

If you get the error message: "bad interpreter: No such file or directory", there is probably anunseen problem with the formatting of the file.

Run the following command to convert it to proper Unix format before calling the script again:dos2unix php-copy.sh

4/ Test your new PHP setup

Open one of your existing PHP pages in your browser to ensure that your newly-installed localcopy of PHP is functioning properly. If there is a problem, go back over the prior steps and useyour debugging skills and your mastery of PHP, shell scripts and Linux to get your newly-copiedPHP interpreter working! Once everything works properly, go on to the next step.

5/ Create a shell script to make a fresh copy of php (for future use)

cp php-copy.sh php-update.sh

Open the newly-created php-update.sh script in your favorite text editor and find this line:

# REMOVE THE FOLLOWING LINE TO CREATE THE UPDATE-ONLY SCRIPT:

Delete that line as well as the line following it. Then save php-update.sh

If you got a "bad interpreter: No such file or directory" error message when you executed ./php-copy.sh previously, remember to convert the new file to unix format by running the followingcommand: dos2unix php-update.sh

6/ Set up a cron task to keep php up to date

Type:

crontab -e

And then enter the following in the text editor that shows up (replacing 'myusername' with yourspecific username):

@weekly /home/myusername/php-update.sh

This will update the php binary and config file once a week.

7/ Configure your website to use new the php.ini that we just set up

Create the file ~/[your website directory]/.htaccess which contains the lines:

Options +ExecCGIAddHandler php-cgi .phpAction php-cgi /cgi-bin/php.cgi

Page 120: Drupal - Installation Guide

This is telling Apache (the webserver) to use the php.cgi and php.ini that php-update.sh copied into~/[your website directory]/cgi-bin.

How to create a custom php.ini file whennothing else worksI recently needed to increase the memory_limit, upload_max_filesize and post_max_sizevalues to something higher than the measly amount set by a particular webhost's default php.inifile. This account was set up with cPanel and overriding the php.ini defaults the usual way (byadding various lines to the .htaccess or settings.php files) didn't work at all. If you've had the sameexperience, you may find that this how-to works for you.

This how-to is for any version of Drupal running on Linux and Apache. No Drupal modules areneeded, but the devel module certainly helps.

1. Get and modify your custom php.ini fileIt's best to use a php.ini file that somewhat resembles the one already running on your server. Youcan probably find one at /usr/local/lib/php.ini or /usr/local/Zend/etc/php.ini and just copy it intoyour account's web folder (it may be called "public_html" or "www" or "htdocs" -- you know theone).

Edit your php.ini file and save your changes. There are handbook pages on increasing memory andupload size if you need help on the syntax.

2. Creating your CGI scriptNow create a small script and put it in your cgi-bin directory. In your web folder, create anotherfolder called "cgi-bin" if it's not there already. Using your preferred text editor, create a file name"php.cgi" and put the following into it:

#!/bin/shexec /usr/local/cpanel/cgi-sys/php5 -c /path/to/drupal/

If you don't have cPanel on your account, try /etc/php5 instead. In any case, replace the/path/to/drupal/ part with the full path to your Drupal installation, such as/home/youraccount/public_html/ or /home/youraccount/public_html/drupal/

Since this is a script that needs to run as an executable file, use the chmod command and type thisat the command line:

chmod -x php.cgi

Don't have shell access? That's outside the scope of this how-to, but you can use an FTP programthat can change permissions of files, ask your webhost to make the php.cgi script executable foryou, or make it executable with some PHP code (perhaps with the devel module's Execute PHPblock).

3. Modifying your .htaccess fileAdd this one line to your .htaccess file:

Action application/x-httpd-php5 /cgi-bin/php.cgi

This tells Apache to perform an action each time it encounters a file of file type "application/x-httpd-php5" -- if you're using a version of PHP older than PHP5, you'll need to change this to"application/x-httpd-php" (or upgrade to PHP5 -- ask your webhost).

Finally, scroll down to the part that says "# Protect files and directories from prying eyes" and add"ini|" to the <FilesMatch> directive so it looks something like:

<FilesMatch"(\.(ini|engine|inc|info|install|module|profile|po|sh|.*sql|theme|tpl(\.p hp)?|xtmpl)|code-style\.pl|Entries.*|Repository|Root|Tag|Template)$"> Order allow,deny</FilesMatch>

Notice the "ini|" on the first line? This will prevent your custom php.ini file (and anything elseending in .ini) from being accessible to the entire world. (The character after the "ini" part is apipe, by the way, not an L.)

4. Test your siteLoad up your website and see if it works. If it does, good job! If it doesn't, go back to step 2 or 3and check to see what version of PHP your site is using. You can also ask your webhost for help.

If you increased your post_max_size or upload_max_size, then look at youradmin/settings/uploads admin page and see how big your uploads can be. If you increasedyour memory_limit, check phpinfo or devel module's phpinfo() page at admin/logs/status/php

Page 121: Drupal - Installation Guide

Deploy to non-writable mediaCD Deploy is a Webserver for Drupal that runs from a CD/DVD media on Microsoft Windows9x/ME/XP and Vista.

HOW TO USE

Structure

The 'app' folder is the right place to copy your Drupal site.The 'lib' folder is used to save any 3rd party software needed to create the Webserver executable.This forder contains a Makefile which have instructions to create the folder 'server'.The 'db' folder should be created manually, containing a copy of your Drupal site's MySQLDatabase.

Install 3rd Party Software

By default, CD Deploy comes without any 3rd party software, have to be downloaded from theInternet using the Makefile script available in folder 'lib':

$ cd lib$ make all

Install Database

1. Copy DatabaseCreate the folder 'db', and copy there all files of your MySQL database.$ mkdir 'db'$ lsapp db lib LICENSE.txt Makefile Start.nsi

2. Register database for DrupalThis might be the hardest step but is done only once:

Once you have installed 3rd party software (see Install 3rd Party Software above),copy the folder 'lib/server' into a windows box.Run the program 'Start' (or Start.exe)Create directory www into server folderStart Apache and MySQL, using menu in tray icon with symbol [1]Open a web browser and go to http://localhost/apanel/phpMyAdmin/Create a database named 'cddeploy'Stop Apache and MySQL, using menu in tray icon with symbol [1]Overwrite database 'mysql' from Windows box, it is located at usr/local/mysql/dataCopy the actual files of database 'cddeploy' to 'db' folder (see Install Database, step 1)

Copy Drupal Files

1. Copy DatabaseCreate the folder 'www' into folder 'app'$ cd app$ mkdir www$ lsAUTORUN.INF www

2. Copy your Drupal files. As reference, file index.php should appear right into folder 'www'.

Configure Settings.php

Connection string of file settings.php should use following grants:user: rootpassword: rootdatabase: cddeploy

Personalize AUTORUN

Edit file AUTORUN.INF, see more about this kind of files here.

Deployment

1. Use the main Makefile$ make all

2. Burn the contents of folder 'app' to a your non-writable media (i.e: Business Card CD)

Run Test

Insert your non-writable media into a Linux box and let me know the results :)

Drupal Performance Measurement &BenchmarkingBenchmarking in simplistic terms is the process where you compare your current performance

Page 122: Drupal - Installation Guide

with that of a better process to improve the overall standard of performance.

This HOWTO sets out the methods to measure the performance of your web server for siteadministrators to implement changes to the server or Drupal configuration in order to produceperformance improvements.

MeasurementFor the purposes of this HOWTO, we are focusing on the use of ab, the Apache HTTP serverbenchmarking tool. ab is often found pre installed with many Linux distributions, and is designedto give you an impression of how your current Apache installation performs.

For Windows users, the ab tool can usually be found somewhere in the installation path of yourApache-based web server. For example, in WAMP it can be found in c:/<path toWAMP>/bin/apache/Apache<version here>/bin. Using the Windows command prompt (accessibleby going to "Start", "Run" and typing "cmd"), navigate to the directory containing ab and then youcan use the tool as outlined in the examples below. Alternatively, you can place the path toApache's bin folder in your PATH variable, thus making the ab tool accessible without the need tonavigate to it's directory every time you launch the command prompt.

For the examples below we used the following command;

ab -n 100 -c 10 http://yourserver.com/

Where;

-nNumber of requests to perform for the benchmarking session. (option = 100)

-cNumber of multiple requests to perform at a time. (option = 10)

Optimizing DrupalBy default, Drupal has two settings to improve performace;

Page CacheThe normal cache mode is suitable for most sites and does not cause any side effects. Theaggressive cache mode causes Drupal to skip the loading (init) and unloading (exit) ofenabled modules when serving a cached page. This results in an additional performanceboost but can cause unwanted side effects.Bandwidth optimizations - Aggregate and compress CSS filesSome Drupal modules include their own CSS files. When these modules are enabled, eachmodule's CSS file adds an additional HTTP request to the page, which can increase the loadtime of each page. These HTTP requests can also slightly increase server load. It isrecommended to only turn this option on when your site is in production, as it can interferewith theme development.

Where to find Drupal's performace settings

http://yourserver.com/admin/settings/performance

CSS Aggregation OFF, Page Cache OFF

Concurrency Level: 10Time taken for tests: 35.160824 secondsComplete requests: 100Failed requests: 0Write errors: 0Total transferred: 1631700 bytesHTML transferred: 1582800 bytesRequests per second: 2.84 [#/sec] (mean)Time per request: 3516.082 [ms] (mean)Time per request: 351.608 [ms] (mean, across all concurrent requests)Transfer rate: 45.31 [Kbytes/sec] received

CSS Aggregation ON, Page Cache OFF

Concurrency Level: 10Time taken for tests: 34.796567 secondsComplete requests: 100Failed requests: 1 (Connect: 0, Length: 1, Exceptions: 0)Write errors: 0Non-2xx responses: 1Total transferred: 1469540 bytesHTML transferred: 1420867 bytesRequests per second: 2.87 [#/sec] (mean)Time per request: 3479.657 [ms] (mean)Time per request: 347.966 [ms] (mean, across all concurrent requests)Transfer rate: 41.24 [Kbytes/sec] received

CSS Aggregation ON, Page Cache ON

Concurrency Level: 10Time taken for tests: 5.461753 secondsComplete requests: 100

Page 123: Drupal - Installation Guide

Failed requests: 0Write errors: 0Total transferred: 1525206 bytesHTML transferred: 1476505 bytesRequests per second: 18.31 [#/sec] (mean)Time per request: 546.175 [ms] (mean)Time per request: 54.618 [ms] (mean, across all concurrent requests)Transfer rate: 272.62 [Kbytes/sec] received

See also

Server tuning considerations

External links

http://wimleers.com/article/improving-drupals-page-loading-performancehttp://www.mostlygeek.com/2006/08/29/how-to-make-drupal-run-85x-faster-i...http://buytaert.net/drupal-vs-joomla-performance

Drupal on OpenBSDOpenBSD is slightly different, since Apache runs in a chroot.

Installation of Apache, PHP and MySQL can be taken fromhttp://freeyourbox.org/tutorials/bsd/obsd3.8_apache_php_mysql.html.A /tmp directory must be created in the chroot for file uploads to work:

# mkdir -p /var/www/tmp# chown www:daemon /var/www/tmp

Drupal with safe mode enabled and openbasedirThis is still undergooing some changes as I'm doing more tests...But it works on a clean drupal 4.7.3 install...

I haven't tested all modules yet, so please help me out...

Simply: use safe mode based on groups rather then owner and give access to my central code basefor virtual hosts so that open base dir works...

You need to be logged in using ssh as root...And mind you my examples are from a plesk based system...With a central code base located in /var/www/apps/drupaland the virtual hosts directory in /var/www/vhosts/{domain}.{tld}/httpdocs/

1) create a group and a user called drupal...After -d you can put any home directory you like, but I choose the directory where my drupal codeis installed...after the passwd you need to give a GOOD password for the user...

groupadd drupaluseradd -d /var/www/apps/drupal -g drupal drupalpasswd drupal

2) Change the owner and the group of the single code base...If you don't have a single code base, only changing the group (chgrp) is enough

chgrp drupal -R /var/www/apps/drupalchown drupal -R /var/www/apps/drupal

3) For the virtual hosts, change the group of the sites directoryAlso all directories under sites should be chmod to 2775: 2 puts all new subfiles createdautomatically into the group of the folder they are placed in (drupal in our case) + 7 for owner(root or drupal or ftpusername) + 7 for group (drupal) + 5 for guestsIf you have any more directories under sites, chmod them too

chgrp drupal -R /var/www/vhosts/{domain}.{tld}/httpdocs/siteschmod 2775 /var/www/vhosts/{domain}.{tld}/httpdocs/siteschmod 2775 /var/www/vhosts/{domain}.{tld}/httpdocs/sites/default

4) Add the users to the groupPlesk has a psaserv group don't worry if you don't have it...The drupal group needs the psaadm and psaftp only if you run plesk

vi /etc/group psaserv:x:2523:apache,psaftp,psaadm,drupaldrupal:x:10002:drupal,apache,psaftp,psaadm,{user_of_ftp_account_of_virtual_host}restart service apache

5) correct the tmp dir by creating a sub directory and putting the drupal group and user on it...

mkdir /tmp/drupalchmod 2775 /tmp/drupalchgrp drupal /tmp/drupal

Page 124: Drupal - Installation Guide

chgrp drupal /tmp/drupal==> in admin change to /tmp/drupal

6) alter the code of file.inc so directories are made using 2775 rather then 775

find: @chmod($directory, 0775);replace: @chmod($directory, 02775);

Actually my version of PHP has a bug and doesn't put the 2!!!I have to remember to chmod myself then...

7) change your virtual host settings of httpd.confIn plesk this is done in: /var/www/vhosts/{domain}.{tld}/conf/vhost.confOther systems might have another place for the conf which is the configuration for your httpdserver..With this code I have made sure that only the drupal directories benefit from group based safemode (safe_mode_gid)... all other directories still use the default safe modeRemove the second DirectoryMatch in case you want all files and folders to benefit from groupbased safe mode...As I have a central code base in /var/www/apps/drupal, I need to add this dir to the open basedir...and again only for the drupal directories off course...

## allow all documents below this dir access to drupal core#

<DirectoryMatch "^/var/www/vhosts/{domain}.{tld}/httpdocs"> <IfModule sapi_apache2.c> php_admin_flag safe_mode on php_admin_flag safe_mode_gid on php_admin_value open_basedir"/var/www/apps/drupal:/var/www/vhosts/{domain}.{tld}/httpdocs:/tmp" </IfModule> <IfModule mod_php5.c> php_admin_flag safe_mode on php_admin_flag safe_mode_gid on php_admin_value open_basedir"/var/www/apps/drupal:/var/www/vhosts/{domain}.{tld}/httpdocs:/tmp" </IfModule></DirectoryMatch>

## now limit for all directories below root that are not includes or modules# users want other apps installed too... so no access to drupal#

<DirectoryMatch"^(/var/www/vhosts/{domain}.{tld}/httpdocs/)(?!includes/|modules/).*/"> <IfModule sapi_apache2.c> php_admin_flag safe_mode on php_admin_flag safe_mode_gid off php_admin_value open_basedir"/var/www/vhosts/{domain}.{tld}/httpdocs:/tmp" </IfModule> <IfModule mod_php5.c> php_admin_flag safe_mode on php_admin_flag safe_mode_gid off php_admin_value open_basedir"/var/www/vhosts/{domain}.{tld}/httpdocs:/tmp" </IfModule></DirectoryMatch>

How to degrade your Drupal db from MySQL4.1.X/5.0.X to MySQL 4.0.XI came across this issue when was developing a site for a client. I have MySQL 5.0.X at mylocalhost and staging host but client's hosting still uses MySQL 4.0.X.

So here is the solution:

0. Always make backup first.

1. Drop tables "accesslog", "cache" and "watchdog"

(DROP TABLE accesslog, cache, watchdog;)

2. Recreate tables from Drupal mysql dump for v4.0

CREATE TABLE accesslog ( aid int(10) NOT NULL auto_increment, sid varchar(32) NOT NULL default '', title varchar(255) default NULL, path varchar(255) default NULL, url varchar(255) default NULL, hostname varchar(128) default NULL, uid int(10) unsigned default '0', timer int(10) unsigned NOT NULL default '0', timestamp int(11) unsigned NOT NULL default '0', KEY accesslog_timestamp (timestamp), PRIMARY KEY (aid));

Page 125: Drupal - Installation Guide

CREATE TABLE cache ( cid varchar(255) NOT NULL default '', data longblob, expire int(11) NOT NULL default '0', created int(11) NOT NULL default '0', headers text, PRIMARY KEY (cid), INDEX expire (expire));

CREATE TABLE watchdog ( wid int(5) NOT NULL auto_increment, uid int(10) NOT NULL default '0', type varchar(16) NOT NULL default '', message longtext NOT NULL, severity tinyint(3) unsigned NOT NULL default '0', link varchar(255) NOT NULL default '', location varchar(128) NOT NULL default '', referer varchar(128) NOT NULL default '', hostname varchar(128) NOT NULL default '', timestamp int(11) NOT NULL default '0', PRIMARY KEY (wid));

3. Make a dump for MySQL 4.0.Xmysqldump -u root -p -h localhost --compatible=mysql40 mydatabase >mydatabase.sql

4. Upload this dump to your MySQL 4.0.X server.

5. Refresh your browser a couple of times. Enjoy!

How-To: Virtual Hosting with DrupalIntroductionThis book explaines how I've enabled Drupal hosting for my customers.I hope it is helpfull for other Drupal hosters...

Environmentthis is the environment used to setup my drupal hosting

linux RHEL 4plesk 8.0.1php 4.3.9mysql 4.1.12apache 2.0.52drupal 4.7.x

Requirementskeep safe mode on at all times without the need for chmod 777keep base dir restriction on at all timesintegrate into plesk so that backup, databases, quotas,etc keeps workingdrupal must run as managed application

updates done once for all vhosts :: use single code baseapproved modules and themes available for vhosts to select frompre-activate drupal modules that enhance basic content management:SEO, security, ...

eaccelerator must speed up php processing efficiently :: use single codebaseEach individual vhost

should be able to use its own themes and modulesshould be accessible trough different URLs ::drupal multisite optionshould also be able to use other applications then drupal within thesame siteshould experience drupal no different as if we would install drupalfor each vhost seperatly

Enhance security if needed on the drupal packageSingle code base should be included in the normal backup mechanism available in plesk

Next pagesAs the book seems to order the sub pages by date, I list here the order of further reading:

1. Solution overview: http://drupal.org/node/901442. Prepare environment: http://drupal.org/node/90207

How-To: Virtual Hosting with Drupal ::

Page 126: Drupal - Installation Guide

How-To: Virtual Hosting with Drupal ::Prepare environmentIntroductionOn this page I will explain some preparations of the environment like creating the drupal group, atempory files location, application reference location, etc.

Please read previous pages:

Requirements: http://drupal.org/node/80472Solution overview: http://drupal.org/node/90144

The drupal groupAs we will enable the safe mode in group mode, we are in need of a system group.SSH into the server as SU (super user or root)

add the group

$ groupadd drupal

add the apache, psaftp and psaadm users to the groupthe group id (10002) could be different$ vi /etc/group drupal:x:10002:apache,psaftp,psaadm

The temp directoryAlso within the temp directory we need a matching group because uploaded files are temporarlysaved there and then copied to the final destination.Therefore we will create a seperate directory and chmod it so that each file created theirautomatically receives the drupal group. The latter is achieved by addin 2000 to the chmodcommand.

$ mkdir /tmp/drupal$ chmod 2775 /tmp/drupal$ chgrp drupal /tmp/drupal

You will see an s appear instead of the x at the group part:drwxrwsr-x 2 root drupal 4096 Oct 16 15:09 drupal

The reference locationThis is a directory where all symlinks are placed that point to the current version of an application.It is this location that all vhosts will reference so that they don't depend on the current version.When switching versions, we only need to alter the symlinks at this location and all vhosts will beupdated automatically. See further pages for more info.SSH into the server as SU (super user or root)

$ mkdir /var/www/apps

NavigationAs the book seems to order the sub pages by date, I list here the order of further reading:

Previous: Solution Overview: http://drupal.org/node/90144Next: Single code base: Comming soon...

How-To: Virtual Hosting with Drupal ::Solution OverviewIntroductionOn this page I will explain in general what solutions are provided for the different requirements

Please read previous Requirements page: http://drupal.org/node/80472

Safe modeEnabling Safe Mode imposes several restrictions on PHP scripts. These restrictions are mostlyconcerned with file access, access to environment variables and controlling the execution ofexternal processes.There are problems which may be encountered when this mechanism is turned on, notably whenattempting to work with files owned by different users and files which have been created atruntime by the script (which will be owned by the owner of the web server process).

In Plesk (and most other virtual hosts system) each vhost gets its own owner (FTP user) that is set

Page 127: Drupal - Installation Guide

when files are uploaded to the server. As we want a single code base located in a central place, theowner of the files within that central place will be different then the owner of the files in thevhost's location.

In order to work around these issues, a relaxed form of the file permission checking is alsoprovided by Safe Mode. Using the php.ini directive safe_mode_gid, it is possible to relax the userID check to a group ID check.That is, if the script has the same group ID as the file on which a file operation was requested, theoperation will succeed. If the script owners and the web server are members of the same group,and all hosted files are owned by this group, the file operations will succeed regardless of user ID.

Thus, we will create a group "drupal" that will cover all drupal related filesacross vhosts and enable the safe_mode_gid. By doing so we will still have amore secure system then when we would disable the safe mode.

Information taken from here: http://www.acunetix.com/websitesecurity/php-security-5.htm

Open BasedirOpen Basedir limits the files that can be opened by PHP to the specified directory-tree, includingthe file itself. This directive is NOT affected by whether Safe Mode is turned On or Off.

When a script tries to open a file with, for example, fopen() or gzopen(), the location of the file ischecked. When the file is outside the specified directory-tree, PHP will refuse to open it. Allsymbolic links are resolved, so it's not possible to avoid this restriction with a symlink.

In Plesk (and most other virtual hosts system) each vhost gets its own open_basedir restriction thatrestricts the opening of files to the httpdocs directory and the /tmp directory. As we want a singlecode base located in a central place, that location will not be accepted trough this restriction.

Thus, we will alter the open basedir restriction so that it includes the singlecode base location. But as we want other applications to be installed within thesame vhost, we will add the location only for directories using drupal.

Plesk integrationThe plesk control panel works great as long as you keep the directory structure and security as it isprovided by plesk. Therefore we need to merge the single code base and each vhost within theprovided structure.

The single code base will be installed as a normal vhost but limiting web accessto the domain. As such a backup of the single code base can be scheduled and FTPcan be enabled to upload new modules and themes. Each vhost will have his own local "sites" directory and will create itsdatabase trough the plesk interface.

Managed applicationAs the single code base resides as a single vhost, we can upgrade the code, add modules andthemes into one location. To make upgrading easier we need to make sure that each vhost that usesdrupal, references one single point independent of the drupal version.

We will make subdirectories per drupal version in the single code base locationand have one single reference that we can switch when going to a new version. Thus their will be a symbolic link called "drupal" pointing towards a drupalversion "drupal-4.7.3" and each vhost that uses drupal will have symbolic linkspointing towards the "drupal" symbolic link. When we change version, we onlyneed to change the "drupal" symbolic link once and all vhosts will be adjustedaccordingly.

eAcceleratorThe eAccelerator speeds up the execution of the php script by precompiling them and putting theminto memory. The disadvantage is that you need to have the memory and the more you have themore php files can be kept for fast execution.Therefore we need to limit the number of php files on the server.

By using the single code base, every vhosts uses the same files and thus memoryusage can be limited and all php scripts run faster.

more on eAccelerator can be found here: http://eaccelerator.net

Each individual vhost requirementsas noted above in the "Plesk Integration" part, each vhost gets his own "sites" directory thatenables them to add their own modules and themes. Also as natively available by drupal, themultisites mechanism will work for the same reason.Using symbolic links and this "sites" directory will give the user the feeling that it is a full drupalinstall on their system.

The local "sites" directory will allow the flexibility required

Navigation

Page 128: Drupal - Installation Guide

As the book seems to order the sub pages by date, I list here the order of further reading:

Previous: Requirements: http://drupal.org/node/80472Next: Prepare environment: http://drupal.org/node/90207

Installing Drupal behind an Actiontec GT701-WG routerThe popular Actiontec GT701-WG (and possibly other routers) DSL modem/router has a peculiarbehavior that affects how base_url must be set up in sites/default/settings.php. Thesolution is to replace the PHP code that sets base_url with some code that is available below.

Here's the scenario: you are using computer A to access and use your Drupal site, computer B isthe server that is hosting the Drupal site, and both computers are plugged into a GT701 router,which in turn is linked to the Internet. Internet users can access your server from the outside bytyping in www.example.com (because you set up port forwarding on the GT701). However, theGT701 will not allow you to type that address in from computer A, because the GT701 interpretssuch an action as a request to view the GT701'a administrative interface. Instead, you must type inthe local network IP address (usually 192.168.0.xxx) of computer B to access and use your Drupalsite.

However, this causes a problem because base_url is used by Drupal to create all the site's links.If base_url is set for www.example.com, you will be unable to use the site from computer A (evenif you type in the local IP). If base_url is set for the local network IP address, Internet users willnot be able to use the site.

In other words, base_url has to be different for internal network users (computer A) and Internetusers. To do this, replace the line $base_url = "http://www.example.com"; with the followingPHP code:

<?php$ipaddress = getenv(REMOTE_ADDR);$local= strpos($ipaddress, '192.168.');if ( $local=== false ) { $base_url = "http://www.example.com";} else { $base_url = "local network IP address";}?>

Here, replace www.example.com with the actual URL and local network IP address with theproper IP address (something like 192.168.xxx.xxx). It is possible that your local network IPaddresses do not begin with 192.168; in that case, you would need to change the code to look forthe local IP range accordingly.

With this setup, you can access the Drupal site using computer A by typing in Computer B's localIP address in your browser, while Internet users can continue to access it by typing inwww.example.com

More than one Drupal site on one machineThere are several possible configurations for running multiple Drupal servers on the samehardware. You can separate them by directories or by vhosts, they can share configurations or splitthem or, in some cases, have a mixture, but all of these methods have at their heart the./sites/domain_or_host_name/settings.php configuration file and the search-sequencewhere the Drupal program will search first for a configuration named for the current page and thento the current host before settling for the default.

General rules for multiple DrupaldeploymentsEach of the possible multi-drupal scenarios is discussed in more detail in the sections that follow,but the general form for the alternate configuration filename is:

./sites/vhost.uri/settings.php

Note how the path separator ('/') must be changed to a dot. As an example, the vhostdrupal.mysite.net may have one primary drupal server at the DOCUMENT_ROOT location, but asecond site may begin at DOCUMENT_ROOT/altserver. For this case, the configuration file wouldbe ./sites/drupal.mysite.net.altserver/settings.php

Note that in the case of having a separate site in a subdirectory such asDOCUMENT_ROOT/altserver in addition to the site configuration directory it is necessary to createa symlink from the subdirectory to the parent directory. In this case linking theDOCUMENT_ROOT directory to be called altserver. On IIS because symbolic links are notavailable it is necessary to create a virtual directory for /altserver in the IIS configuration.

Within that configuration file, the most common and minimal option is to set the $db_url thatspecifies the host, database and login for the Drupal tables, as well as the $base_url. But you canalso include assignments to override anything in the VARIABLES table. This allows you to redefine

Page 129: Drupal - Installation Guide

the theme, the site footer and contact email, blocks per-page limits, even the name you use foranonymous.

Drupal IDs: When using multiple drupal servers on the same hardware, each new configurationwill result in a new host component for the username@host Drupal login ID (used when logginginto a foreign Drupal server). For example, if you have a directory partitioned host atdrupal.mysite.net/altserver your usename to login to some other Drupal server would [email protected]/altserver.

Prefixing Database Tables to put them in One Database If you only have one database then itis necessary to use database table prefixing. See this handbook page for details on how to achievethat.

PCRE_UTF8 solution for VPS servers |FreeBSDinstallation PROBLEMS? - PCRE_UTF8 support on VPS server accounts? Look here!I receive the same error on every page with a basic install however everything seems to befunctioning otherwise fine.

warning: preg_match(): Compilation failed: this version of PCRE is not compiledwith PCRE_UTF8 support at offset 0 in/home/brandform/www/drupal.brandform.net/includes/unicode.inc on line 32.

The solution was much more difficult to find than i had hoped so maybe this post will beuseful to some others as well.I had to uninstall the pcre package and reinstall the proper one with utf-8.heres the procedure:

login to server via shell,on VPS2 accounts,# su rootthen type passwordbasically you want to be root user.then type:# pkg_infowhich will show you the installed packages.type:# pkg_delete pcre-6.4for me it was 6.4 but yours may be different. make sure to enter the proper version of pcredisplayed in pkg_info.then you want to change to the directory where your ports collection is.on FreeBSD it is:/ports/devel/pcre-utf8so type into your shell prompt:

# cd /# cd ports/devel/pcre-utf8# make# make install# make clean

then youll want to restart the apache server...something like this:# restart_apache

thats it...fixed everything for me.after over a day of pulling my hair out and almost abandoning the effort......

Known causes of PCRE server errorsIn the event that you see the following error:

warning: preg_match: internal pcre_fullinfo() error -3 in/SERVER_PATH/includes/common.inc on line 592.

Be aware that this issue exists at the server level, outside of Drupal code. Put plainly, the errormeans that the server's PCRE (Perl Compatible Regular Expression) library is not configuredcorrectly.

This error may be caused any time a Drupal module calls a PCRE function. Typically, the errorappears within common.inc, but this is not always the case.

Depending on the server environment, there are several different causes (including a reported bugin some versions of PHP 5).

This manual page is designed to capture known instances of this bug,

Known Causes

An upgrade of RedHat included a bad library and required a patch. (Details to follow)

Page 130: Drupal - Installation Guide

Recommendations

Send the content of the error to your system admin and have them debug your PHP's PCREmodule.

Redirecting specific pages to new URLs (301redirects in Drupal)If you are porting over an existing website to Drupal, one consideration is how you redirect the oldpage URLs to the appropriate pages on the Drupal version of the site. If you don't want to createcustom rewrite paths within Drupal for those nodes -- or perhaps cannot due to clean URLs orfilename suffixes -- then 301 redirects are considered the best way to handle redirected pages, forthey inform search engines to update their databases with the new paths. This way, you should notrisk your search engine pagerank or lose site visitors with 404 "not found" errors.

However, 301 redirects cannot be done using the common approach. Yet establishing 301 redirectsis quite easy, provided you have mod_rewrite enabled in your .htaccess file.

How to create 301 redirects in Drupal Apache mod_rewrite

Edit your .htaccess file in a text editor. [Note: Be sure to save the file in "UTF-8" format.]

In the file, you will find the commands:

# Various rewrite rules.<IfModule mod_rewrite.c> RewriteEngine on

# Modify the RewriteBase if you are using Drupal in a subdirectory and # the rewrite rules are not working properly. #RewriteBase /drupal

RewriteBase /

Immediately after that code -- and before the Drupal-provided "Rewrite old-style URLs"commands -- add your rewrite rules using the following format:

#custom redirects

RewriteRule ^old/URL/path$ http://example.com/new/path [R=301,L]

#end custom redirects

Note the convention: The old path is simply the path off the root. The new path is the full path,including the domain. The [R=301,L] code is the 301 redirect instruction. (axbom notes: "The 301tells browsers and spiders it is a permanent redirect, and the L ensures that no other rewrites areprocessed on the URL before it reaches Drupal; Hence place this code above Drupal 's own URLrewrite, but below the command RewriteEngine on.")

If you have more paths to add, insert the rewrite commands as their own line as above.

For more information, see the forum thread at http://drupal.org/node/16084 [from where I drewthis information]

Migrating the Drupal way...saving those oldURLsMapping a previously used ID to a NID

Let's say that the old URL looked like http://example.com/index.asp?id=123, but your new Drupalsite uses a URL like http://example.com/node/123. The following rules could be used to remap theold URL unbeknownst to the user. The following examples would be placed before the Drupalrewrite rules in your .htaccess file:

# Match a request for index.aspRewriteCond %{REQUEST_URI} ^/index.asp$# Match a query string like id=[some number] and capture that numberRewriteCond %{QUERY_STRING} ^id=([0-9]*)$# Rewrite a Drupal friendly URL using the captured number# Note that %1 is a backreference from a RewriteCond# where $1 is a backreference from a RewriteRuleRewriteRule ^.*$ index.php?q=node/%1 [L]

Mapping a previously used numeric file name to a NID

Perhaps your former CMS creates static HTML files, but uses an ID predictably in the file name.The following example will capture any numeric characters in parentheses and append them toindex.php?q=node/. e.g. requesting file5.html would return the same contents as node/5.

# Map a filename with a predictable number to a drupal nidRewriteRule ^file([0-9]*)\.html$ index.php?q=node/$1 [L]

Redirecting as a solution

Page 131: Drupal - Installation Guide

If you want to send your visitors to the correct page and use your new Drupal-style URLs, youcan use a permanent redirect. The 301 HTTP status code tells your visitors that the old URL has anew permanent home. Search engines should also respect a 301 and index appropriately. Using theRewriteRules above, you could accomplish this by using the flags [R=301,L], demonstratedbelow:

# Match a request for index.aspRewriteCond %{REQUEST_URI} ^/index.asp$# Match a query string like id=[some number] and capture that numberRewriteCond %{QUERY_STRING} ^id=([0-9]*)$# Permanently redirect - note the ? at the end of the address# which is necessary to not append the original query stringRewriteRule ^.*$ http://example.com/node/%1? [R=301,L]

The above example will redirect the user to a URL like /node/123. So, what if you want topermanently redirect to a more friendly URL alias? A great option is to use the Global Redirectmodule for Drupal.

Global Redirect can also be used in conjunction with mod_rewrite rules. (The first set ofmod_rewrite rules mentioned in this post are a good example) Assume that you have a URL aliaslike /your-aliased-url used for /node/123. Using mod_rewrite, you can map /index.asp?id=123 to/node/123 and Global Redirect will permanently redirect to your alias. This effectively sends allrequests for /index.asp?id=123 to /your-aliased-url.

sourcehttp://acquia.com/blog/migrating-drupal-way-part-ii-saving-those-old-urls

Running Drupal on Ubuntu ServerLearn how to set up Ubuntu with Apache, MySQL, SSH Server, PhpMyAdmin, and configure allwith some minor tweaks that will cause a major performance boost over a barebones install.

Setting up Ubuntu Server for hosting Drupal sites

Showing the public a holding page while youdevelop or troubleshoot your siteWhile you develop your Drupal site you may want to show the public either a simple holding pageor keep an older version of the site operational.

You can either develop Drupal in a subdirectory while keeping the site in place, or you candevelop Drupal in the webroot and put the holding page or old site in a subdirectory. This pageconsiders the latter approach.

This technique can also be used to display a more friendly message than the standard 'Can'tconnect to the database' message when your site goes down.

For a module-based approach, see http://drupal.org/project/holding.

Instructions

Create your static holding page(s) and place it in a subdirectory called, for example, 'holding'.

Then add the following lines to your Drupal installation's .htaccess file, below the 'RewriteEngineon' line:

##### rewriting for holding page RewriteCond %{HTTP_HOST} mysite\.com [NC] RewriteCond %{REQUEST_URI} !^/holding [NC] RewriteCond %{HTTP_HOST} !^drupal [NC] RewriteRule ^(.*)$ /holding/$1 [L] ##### end

Replace 'mysite\.com' with the domain name of your own site, escaping the full stops withbackslashes, as in the example.

This will redirect visitors of 'mysite.com' to 'mysite.com/holding', without them realising.

To access your Drupal site, you need an alternative domain name. There are two ways to do this.

The easiest method is if you have the original domain name for your hosting, such as'mysite.somehostingcompany.com'. Using this to reach your site will give you the Drupalsite rather than the holding site. You may also be able to access your site at your IP like this:http://1.1.1.1/~usernameAlternatively, create a subdomain called 'drupal' for your site, set to the same webroot as themain domain. The third line in the code snippet above means that visiting'drupal.mysite.com' won't be redirected to the holding page.

If you get a 403 for the holding site, you'll need to put an .htaccess file in the holding folder, asDrupal's .htaccess only allows index.php as a directory listing. This is all you need for theholding/.htaccess file:

# Set the default handler.DirectoryIndex index.php index.html

Page 132: Drupal - Installation Guide

Transforming a default table namesinstallation into a prefix table namesinstallationThis operation may be useful in many cases, expecially if you need to move your site from an hostproviding a dedicated drupal installation database to a shared database with all data in onedatabase.

1) Log off your Drupal site, back up the database, the risk breaking your data is definitely here.

2) Export the database to text file. You can use i.e. phpMyAdmin Export function with thefollowing options: "SQL" (as format to use). Be sure to check Structure (and "AddAUTO_INCREMENT value" in it) and Data (and "Use exadecimal for binary fields"). Don't usecompression settings, you want a plain file.

3) Decide the prefix for the tables. I.e. all tables name changed from "xxxxx" to "dpl_xxxxx".

4) Open the text dump created, search and replace every

CREATE TABLE '

withCREATE TABLE 'dpl_

andINSERT INTO '

withINSERT INTO 'dpl_

where dpl_ is any SQL valid prefix you want to use.

5) Save the dump

6) Drop the current database (if you are reinstalling on same machine, else skip)

7) Create the database in the destination machine. I give "utf8_unicode_ci" as default collation.From now on everything is done on the destination computer.

8) Import the saved dump there.

9) Open a SQL prompt / window / whatever (i.e. "SQL" option in phpMyAdmin).

10) At the SQL prompt enter:

update dpl_sequences set name = concat('dpl_', name)

Of course if you use something different than 'dpl_', you have to apply such prefix both in front of"sequences" and in the concat operator. Example, if you used "my_stuff_" it'd become:update my_stuff_sequences set name = concat('my_stuff_', name)

Beware, the prefix must be the same in the whole process or everything will break. I'd reallysuggest keeping case consistency too.

11) Open the settings.php, usually it'll reside in the /sites/default folder. If you have a multi-siteinstallation you have to find the relevant php settings file in the affected domain folder.

12) If you changed database name / server, search for:

$db_url = 'server://path/database_name';

and alter it as per the instructions reported above that line.

13) Search for:

$db_prefix = '';

(should be right next of the above $db_url statement) and put the new prefix inside the ' '.

Example:

$db_prefix = 'dpl_';

14) Launch the home page of the destination installation. If everything shows up, you are at agood point. Else you have to double check what step did you miss.

15) Log in as administrator and create a quick page and a story. If you see green and encouraging"page / story added" you are done. If you get "Warning: duplicate key / ID" whatever, you skippedsomething about prefixes and you have to drop the database and redo from point 6.

Note

Page 133: Drupal - Installation Guide

Amazing tutorial! it works for Drupal 6.x but in my case I also had to replace:

LOCK TABLES ' and ALTER TABLE ' with LOCK TABLES 'pre_ and ALTER TABLE 'pre_

Use Microsoft Access to query your drupaldatabaseHope this helps someone. I used ODBC to MySQL over SSH port fowarding on a Windows client.Here goes:

1) Download and install cygwin (www.cygwin.com) on your windows machine; make sure toinclude OpenSSH, tcp_wrappers, and zlib. There’s a nice set of instructions here:http://pigtail.net/LRP/printsrv/cygwin-sshd.html. NOTE: You can also use Plink.

2) Download and install MySQL Connector / ODBC 3.51 on your machine, located here:http://dev.mysql.com/downloads/connector/odbc/3.51.html. I downloaded the WindowsZip/Setup.EXE

3) I needed to comment out the line “skip networking” in /etc/my.cnf. I did this by 1) SSH into myserver, 2) type cd /etc and press enter, 3) type pico my.cnf and press enter, 4) put a “#” in front ofthe phrase “skip networking” 5) Save 6) Restart MySQL server.

4) Now you’re ready to set up an SSH tunnel from your local machine to the host. Open Cygwinand use the following command:ssh -N -f -L 3307:localhost:3306 [email protected].

5) Setup the ODBC connection. In Vista, goto Control Panel -> Administrative Tools -> Datasources and click Add. Select MySQL ODBC 3.51 Driver, click finish, and fill in the fields likesuch:Data source name: You pick!Description: You pickServer: localhostUser: the name that you use to login to your serverPassword: ******** Note: Your password needs to be 8 characters or less.Database: the name of the database to connect to.On the 2nd page of the dialog, enter port 3307Click Test and you should be able to connect!

6) To connect MS Access to your database(s), goto external data -> import from ODBC, and whenit says select data source goto machine data source. You should see your data source name. Clickon that and follow the prompts. You’re good to go!

Using Apache .htaccess files to stop proxiesfrom caching pagesThere are a number of situations that might result in visitors accessing a Drupal site via a cachingweb proxy. Even though such caches are typically a good thing for sites, sometimes these cachingschemes can have undesirable side effects and you may find that instructing proxy servers not tocache pages is the only solution to some problems. (You can learn more about web caches andhow they work.)

Some problems that caches may cause with Drupal sites include:

A change that a user made to a page may not be reflected immediately, forcing the user towait some time to see content they contributed (such as a comment) appear on the site.User identities become confused. A user may login under their username but when theyaccess another page, the proxy server sends the cached page from another user's session,effectively switching the identities of the user.

Proxy servers can be instructed to stop caching pages for a Drupal site using a variety oftechniques. The simplest involves modifying your theme to include certain <meta … /> tags inyour theme's <head> section. Although using these tags may be more convenient, many cachingproxies won't respond to their instructions. In these cases, you must embed cache controls in theHTTP headers sent by the web server itself.

Apache web servers typically use mod_expires to configure and send these cache-controllingHTTP headers. Assuming that mod_expires is enabled on your web server, try adding thefollowing lines to your .htaccess file to stop the proxy server from caching Drupal pages:

ExpiresActive onExpiresDefault "access plus 0 seconds"

Alternatively, if the web server has both mod_expires and mod_headers this snippet may be morerobust.

ExpiresDefault A0 Header set Cache-Control "no-store, no-cache, must-revalidate, max-age=0"Header set Pragma "no-cache"

Note that Drupal's internal cache is distinct from any caching that web servers may do. For moreinformation about Drupal's internal caching mechanism, see Cache support. For information

Page 134: Drupal - Installation Guide

regarding how to enable a web cache of your pages, see Squid Caching.

Increase PHP memory limit (4 methods)While Drupal core will run with 8 MB of memory configured for your server, you may need toincrease this depending on how may modules you use on your site.

In Drupal 4.7.x and earlier, when you go into ?q=admin/modules, you may experience a blankscreen. This is caused by Drupal loading all the modules of your site into memory, whether youhave them turned on or not. If you get a blank screen here, you have two choices; increase yourallocated memory for PHP or delete unused modules.

In Drupal 5.x and above, this problem has been fixed, and the modules page no longer loads allmodules. If you are still getting out of memory problems, you should either reduce the number ofmodules used or increase your allocated memory for PHP.

Depending on your host, this can be done in a number of places with the most likely beingphp.ini or .htaccess depending on your hosting situation.

Add for example:

memory_limit = 16M to your php.ini file (recommended, if you have access)

With root access, you can use the sed util in Linux/Unix based systems, in order to increasethe memory for 64M. Don't forget to properly locate your php.ini file!

sed -i 's/memory_limit = .*/memory_limit = 64M/' /etc/php5/apache2/php.ini

ini_set('memory_limit', '16M'); to your sites/default/settings.php filephp_value memory_limit 16M to your .htaccess file in the Drupal rootOr simply install: http://drupal.org/project/drupal_tweaks and increase your PHP memorylimit in settings.

You will need to experiment with the value that is right for you depending on which modules youare using. Some people find they need to set the memory to 24M or 32MB or higher (e.g.96MB is recommended for a site with built-in image processing using ImageAPI GD).

NOTE: Some hosts do not allow you to control how much PHP memory is available. In this caseyou will need to work with your host, be very conservative with your module selection and testingor look for a new host that allows more flexibility.

Installing modules and themesNow that you've installed Drupal, you will want to customize it to your tastes by adding modulesand themes. The basics of managing modules and themes are fairly similar. If you browse to thesites/all folder you will find a README.txt file.

This directory should be used to place downloaded and custom modules and themeswhich are common to all sites. This will allow you to more easily update Drupal corefiles. These modules and themes should be placed in subdirectories called modulesand themes as follows:

sites/all/modulessites/all/themes

Installing contributed modulesYou can add third-party contributed modules to extend or alter Drupal's behavior.

Basic instructionsObtain the module as an archive and extract the files to your Drupal installation (normally intosites/all/modules) , read the directions, and enable the module in Administer > Site building >Modules.

Note that experienced Drupal site builders generally use command-line techniques like the UNIXwget command or drush. There is also a Plug-in Manager module that allows you to install othermodules using your Drupal site's web interface..

Detailed Instructions

1. Download the module. The module version must be compatible with your version ofDrupal. Note that "Development snapshots" are modules that are in an active stage ofdevelopment. They may be written for a previous/current/future version of Drupal, and theyare considered unstable and should be handled with care.

2. Extract the files. When you first get the module, it will appear in a compressed file formatsuch as 'tar.gz'. On Windows, use a program like 7-zip to extract it. On the Mac, you canuse Stuffit Expander. For *nix systems, use the command line:

tar -zxvf modulename-drupalversionnumber.tar.gz

You should see a list of files extracted into a folder.

Page 135: Drupal - Installation Guide

3. Upload the folder. FTP your files to the desired modules folder in your Drupal installation.The modules folder at the top level of your Drupal installation is reserved for Drupal coremodules (the ones that come with the original download of Drupal). So, you shouldgenerally create a sites/all/modules/ directory and put uploaded modules there. If you arerunning a multi-site installation of Drupal, you can create a modules folder undersites/my.site.folder and put modules there that are specific to a particular site in yourinstallation. Modules that will be shared between all sites should be placed insites/all/modules.

4. Read the directions. If the module has an installation file (usually INSTALL.txt and/orREADME.txt), read it for specific instructions. There are modules that require specialtreatment, and even modules that depend on other downloaded files to function properly.Sometimes the README file has no .txt extension. When you try to double-click on it, yourcomputer doesn't know what program to use. In that case, open your favorite text editor first,and then open the file using the editor's 'file open' command.

5. Enable the module. Navigate to Administer > Site building > Modules. Check the 'Enabled'box next to the module and then click the 'Save Configuration' button at the bottom. NOTE:If you're upgrading an existing module you'll need to browse to your update page atwww.example.com/update.php and click on 'run the database upgrade script'.

6. Set up permissions. Some modules will require you change permissions to get themworking. Permissions information may be in the instructions that came with the module.Usually, go to Administer > User management > Permissions (for Drupal 5 it's Administer >User management > Access control). Scroll down to see if the module appears in the listand, if it does, give the appropriate permissions to desired roles.

7. Adjust settings. Most modules will have some type of settings page. It will vary frommodule to module but but if not described in the README.txt file it will usually be locatedunder Administer > Site building or Administer > Site configuration. If you have troublelocating a module's settings page try navigating to "admin/by-module" and see if the moduleappears in the list. If it does, it's settings page(s) will be listed also. If all else fails, check themodule's .module file for a 'modulename_menu' function-- even if you're not a coder thesettings path, if there is one, should be pretty easy to discern.

8. If you run into problems, search the module's issue queue and the forums. If your problemhasn't already been addressed, post a question or issue and someone will try to help you out.

Note: To keep up-to-date on any issues and fixes related to your newly installed module(s), youcan create a user account (if you haven't done so all ready) and then subscribe to each module youare using.

Note: You can only have one copy of a module with the same name in each Drupal site. Themodule's name is determined by the name of the .module file, not by the name of the directory.

Installing themes1. Download the theme. Make sure the version of the theme matches your version of Drupal.

Note that themes labeled "CVS" or "DEV" are in a development stage. They may be writtenfor a previous/current/future version of Drupal, and they are considered unstable and shouldbe handled with care.

2. Extract the files. When you first get the theme, it will appear in a compressed file formatsuch as 'tar.gz'. On Windows, use a program like 7-Zip to extract it. On the Mac, you canuse Stuffit Expander. To extract the file using the Unix command line:tar -zxvf themename-drupalversionnumber.tar.gz

You should see a list of files extracted into a folder.3. Upload the folder. FTP/Copy/SCP your files to the desired themes folder in your Drupal

installation. Since the themes folder at the top level of Drupal is typically reserved forDrupal core themes, you should create a sites/all/themes/ directory and put uploaded themesthere. If you are running a multi-site installation of Drupal, you can create a themes folderunder sites/my.site.folder and put themes there that are specific to a particular site in yourinstallation. Themes that will be shared between all sites should be placed in sites/all/themes.

4. Read the directions. If the theme has an installation file (usually INSTALL.txt and/orREADME.txt), read it for specific instructions. There are themes that require specialtreatment to function properly.

5. Enable the theme. Go to administer > site building > themes. Check the 'Enabled' box nextto the theme and then click the 'Save Configuration' button at the bottom.

If you run into problems, check the themes issue queue and search the forums. If your problemhasn't already been addressed, post a question and someone will try to help you out.

Moving modules and themesThe best practice is to keep all of your contributed modules and themes in thesites/all/modules or sites/all/themes directory, as appropriate. If you are upgrading from aprevious version or have already installed them in the main modules or themes directories andyou wish to move them, it is possible but you just need to make sure Drupal knows you movedthem.

1. Go to Administer > Site Building > Modules (or Themes) and disable the modules/themesyou wish to move.

2. Move the modules/themes to the new directory you wish them to live in.3. Now go back and enable the modules again. Drupal will locate them in the new directory

and update the system table as needed.

Page 136: Drupal - Installation Guide

The system table gets rebuilt when you visit: admin/build/modules. So if your module has movedand you've forgotten to disable it then just visit the modules page and you should be fine.Typically you'll see a PHP "Fatal error: Call to undefined function myfunction()" error whenDrupal doesn't know where your module is.

This is not necessarily true as of Drupal 6.

Some contributed modules will NOT come back online because of paths stored in their settingsand may cause various database errors. Always remember to make a complete backup first. Inthese cases, try uninstalling the module completely. Or just leave it where it was before you movedit. It's also possible to modify the database directly to change the path if necessary.

Uninstalling modulesUninstalling a module is easy! Remember to create a backup of your database first. Beforedeleting the files, it must be disabled.

Disabling a module

Go to example.com/admin/build/modules.

Scroll down until you find the modules that you'd like to remove.

In this case, you'll want to disable all of the “Views” set of modules. In order to disable amodule, click to uncheck the “enabled” checkbox that's next to it. If a module box is greyedout, that means you cannot yet disable it. This is because there is another module thatrequires that module to be active.

In this case, Views RSS and Views UI must be disabled first before the Views module canbe disabled. Uncheck those boxes first, then click on “Save configuration”

Page 137: Drupal - Installation Guide

Once the page refreshes, the checkbox next to the Views module will no longer be greyedout. Repeat the process with the Views module, and everything will be disabled.

Uninstalling a module

Not all modules have specific uninstall functions programmed in. A module will only show up onthe uninstall tab if it has this feature. If it doesn't, skip this step and simply delete its files.

Click on the “uninstall” tab at the top of the example.com/admin/build/modules page. It willlook like this:

Click on the checkbox next to the desired module (in this case Views) and click the uninstallbutton.

Next, you'll have a screen verifying your intention to uninstall this module.

Click on the uninstall button again, and you'll get a screen with green text verifying that themodule is uninstalled.

Remove/delete module files

Removal of module files is similar to the process of uploading module files.

1. Use the same FTP client software as used in the uploading process, and use the sameconnection information.

2. Navigate to the same directory3. Instead of uploading files from your own computer, delete the directory containing the

desired module.

Page 138: Drupal - Installation Guide

SSH

1. Use the same SSH client software as used in the uploading process, and use the sameconnection information.

2. Navigate to the same directory.3. Instead of using the wget command to upload files, use the command “rm -rf [module

folder name]”. In the Views example, you would type “rm -rf views”.

Note: a module without an uninstaller may leave tables or fields in your database. A module likethis must be dealt with manually in order to completely remove it from your database, which isbest practice to keep your site clean if you definitely do not want to use this module again. Theremay be an obviously named table or set of tables in your database which can be easily deleted,but the only way to know for sure is to examine the module installation file to see what was addedin the first place. Always create a backup snapshot of your database before attempting this!

From TopNotchThemes.com

Upgrading modulesUpgrading modules is a more involved process than installing or removing modules. The stepsshould be followed closely, as all these steps are necessary to ensure the stability of your website.

Backup your Files and Database

Your website's database contains all of its content, as well as all of its settings and configuration.As such, any operation which modifies it could, although unlikely, be potentially damaging.Backing up your website's files will ensure that you can revert back to the point when things wereworking. We highly recommend you take steps to back it up before performing this procedure.More information about taking backups may be found at http://drupal.org/node/250790.

Update Module

Update capabilities are not automatically available in Drupal. To keep track of updates to yourinstalled modules, you may want to install the Update module, which is located here:http://drupal.org/project/update_status

Check Module status

The Update module can check your modules for updated status automatically to assist youwith updates. It will provide you with download links and available versions. Once theUpgrade module is installed and enabled, you can reach a list of modules for update byeither clicking on the “available updates” link on the main administration page or by goingdirectly to example.com/admin/logs/update. This page checks the current and theinstalled versions of modules, and will give a report on their status. This will allow easyupdates without having to manually check each module installed in your website.

In this example, the Views module is out of date. Any out-of-date module will be labeled inred, as shown above. We can upgrade this now.

Disable Module

You must first disable the module. Here is a tutorial that covers how to disable a module Followonly part of the instructions listed there. Stop at the section labeled “Uninstalling a module” andonly perform the first section of steps for disabling a module.

Reinstall Module

Next is reinstalling the module. The Update module also provides a download link which may beused to download the updated version instead of going to Drupal.org. Delete the outdated module'sfiles and upload the new ones as if you were installing the module for the first time.

Run update.php

Page 139: Drupal - Installation Guide

Update.php is a script that is used to maintain websites after upgrades. A new version of a modulemay change the structure of the database. This script adjusts the database to fit the updatedmodule. As the database contains all of the content and the settings of your website, this is anessential step to ensure its continued operation.

The update.php script can be called two different ways. You may go to the mainadministration page and click on the “update.php” link on the front page, or you may godirectly to example.com/update.php in your browser.

You will require admin privileges to perform this upgrade. The first account created on yoursite will have the required privileges.

If you do not have the proper privileges, you will receive this screen. Either log in or followthe instructions on the page to perform the upgrade.

Once you have the proper privileges, you will see this screen. Click on the “Select versions”link to expand the section.

These dropdown boxes contain database updates specified by modules you have installed. Ifyou are not developing your own module or troubleshooting, you should leave them aloneand just click the “Update” button. The correct items should already be selected by default -- either “No updates available” if there have not been any database changes, or a number,which is simply an ID number of the database upgrade being applied.

This next page may take a small amount of time to load, as the server is modifying yourdatabase. This page will display any errors that may have occurred during the process. Ifnone have occurred, your module upgrade is complete!

From TopNotchThemes.com

Directory precedence and multi-site

Page 140: Drupal - Installation Guide

considerationsDirectory Precedence

Contributed modules and themes can also be placed in the directories /sites/sitename/modules/ and/sites/sitename/themes/. Often, the sitename will be 'default'.

Contributions placed there will only be available to the named site, whereas those under /all/* areavailable globally. For a single site setup, this probably won't make much difference to you, but ifyou ever start modifying downloaded code for your own use, it's a good idea to isolate yourchanges from the clean versions.

It's possible to have two versions of any module (even core ones) available on the site. Yourinstallation will choose from the most specific one available (first /sites/sitename/modules, then/sites/all/modules, then /modules). You can take advantage of this to test patches without damagingyour existing files.

Also, you can place modules anywhere within subfolders underneath any of these /modules/folders. They will be searched recursively when you visit your admin/build/modules page. You canuse this to further organise your available items.

Multi-site Considerations

The steps for installing in a multi-site configuration are much the same. The difference is wherethe modules and themes directory is located. If you use the /sites/all directory, then any module ortheme installed under it will be available to all sites using the same code base.

If you wish to limit the access to a module or theme to a specific site, then create a modulesand/or themes directory under that sites folder.

sites/example.com.site3/modulessites/example.com.site3/themes

Anything in a site specific directory will not be accessible to other sites sharing the code base.

Migrating to DrupalThis page contains hints and scripts from members of the Drupal community for migrating toDrupal from other content management systems (CMS) weblog, and bulletin board applications.Migrating from other platforms often requires knowledge of PHP and SQL.

Migration involves mapping data fields from the original application's database into Drupal'sdatabase. For some applications this can a simple task, with tools or scripts available to do themigration. Other applications may have complex database schemas, lack documentation, and areuncommon enough that there are no tools available.

The best way to find out if tools or scripts exist for your application is to search on Google. Forexample a search such as "migrate WordPress Drupal" returns dozens of useful links.

If there are no tools available for migrating from your application to Drupal, you will want tofamiliarize yourself with Drupal's database schema, as well as the schema of the application youare migrating.

You will need to map all your current users into Drupal's users table. If you have different roles(for example, read-only, author, editor/reviewer, admin), you will need to assign your users toproperly set up and configured roles in Drupal. This can mostly be done through Drupal's admininterface, although if you have a large number of users, you may want to find a way to automatethe assignment. Editing each user by hand could be time consuming.

If the content being migrated is text, it would likely map into the node and node_revisions tables,with comments in the comments table.

It is usually possible to import databases (MySQL, etc.) containing content and users from yourprevious CMS into Drupal.

This can be done by exporting the databases first to CSV (comma-separated values) or similarfiles. Tools such as phpMyAdmin for MySQL can make this task easier. You can then importthese files with import/export modules such as Node Import, User Import, CSV Parser, Migrate, orTransformations (see a module comparison).

Note that content is often imported as Content Construction Kit (CCK) custom content types. Ifyour tables are available in your Drupal database, you can use the Table Wizard to expose them toViews, and then use the Migrate module to copy the data from the old columns to the CCKcontent types. Also, the Node Convert module can convert imported node types to other nodetypes; it supports, at least, CCK fields, book and forum nodes, and probably others like blog, etc.

In the case that your chosen import module is not yet ready for the Drupal version you wish to use,then there is the workaround of installing a site running on a previous Drupal version just for theimport, and then upgrading it.

On the other hand, if you prefer to migrate data into Drupal developing a custom PHP script, seefor example Migration tips for some techniques.

Page 141: Drupal - Installation Guide

Support for migrating can be found on the Drupal.org forum, Converting to Drupal. See also theDrupal group Content migration, import, and export, for discussion of best practices in contentmigration. Drupal Groups also has a comparison of modules for importing and exporting data.

Finally, look in the Drupal CVS contributions repository for a subdirectories named mt2drupal(code for migrating from Movable Type to Drupal), phpbb2drupal (SQL code for migrating fromphpBB to Drupal) and slash2drupal (Slash 2.2 to Drupal) for SOME IDEAS. None of these is upto date with the latest releases of Drupal and the respective source systems, so they will NOT workwith latest versions of any of the foregoing. However, they will get you close.

The following pages describe methods people have used to migrate to Drupal in the past. As otherCMS software and Drupal evolve, you can use these as a guide to help with your own.

Database import broken down to small piecesIn order to import content to drupal's core or contrib modules, you need to understand how eachcomponent works, and how data is stored.

The main items listed in http://drupal.org/node/307799 to import include; content, comments, files& images, users and roles, external services.

In this section, we will delve into more detail as to how to import different items.

Inserting a simple nodeThe following is the framework for code to create a very simple node, only populating the titlefield, not even the body. This label content type does not have any cck fields.

// Create a mapping table if it does not exist db_query("CREATE TABLE IF NOT EXISTS {map_label} ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY , nid INT NOT NULL , label_id INT NOT NULL ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");

// Populate an array with drupal nids already imported $sql = "SELECT label_id FROM map_label WHERE nid != %d"; $result = db_query($sql, 0); while ($obj = db_fetch_object($result)) { $current[$obj->label_id] = $obj->label_id; }

// Loop through all the old data in the postgres database $sql = "SELECT label_id, company_name, active FROM label"; $result = pg_query($sql); if (!$result) { print "Unable to retrieve data"; exit; }

while ($obj = pg_fetch_object($result)) { // Only insert new data to drupal if (! array_key_exists($obj->label_id, $current)) { $n = new stdClass(); $n->uid = 36; $n->name = 'archive'; $n->type = 'ppl_label'; if ($obj->active == 'Y') { $n->status = 1; } $n->validated = 1; $n->title = trim($obj->company_name); node_save($n); // echo "$n->nid: $obj->label_id: $obj->company_name <br/>"; $ins_sql = "INSERT INTO map_label (label_id, nid) VALUES (%d, %d)"; db_query($ins_sql, $obj->label_id, $n->nid); } }

Inserting termsdb_query("CREATE TABLE IF NOT EXISTS {map_terms} ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY , class_id INT NOT NULL , tid INT NOT NULL , vid INT NOT NULL ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */ ;");

function _taxonomy_get_tid($name, $vid) { $sql = "SELECT t.tid FROM {term_data} t WHERE t.name LIKE '%s' AND t.vid =%d"; $tid = db_result(db_query("SELECT t.tid FROM {term_data} t WHERE t.name LIKE'%s' AND t.vid = %d",trim($name), $vid)); return $tid;}

// Connect to postgres$conn = pg_connect("dbname=db_123 user='db_user' password='db_pass'");

Page 142: Drupal - Installation Guide

if (!$conn) { print "Unable to Connect to DB"; exit;}

function insert_music_genre() { echo "========== Music Genre ==========<br/>"; $vid = 6;

$sql0 = "SELECT class_id FROM map_terms WHERE tid != 0 AND vid = %d"; $result0 = db_query($sql, $vid); while ($obj = db_fetch_object($result0)) { $current[$obj->class_id] = $obj->class_id; }

$sql = 'SELECT * FROM classification c '; $sql .= 'JOIN media_type_classification mc ON mc.class_id = c.class_id '; $sql .= "WHERE mc.media_type_id = 3 AND c.active = 'Y' ORDER BY class_name"; $result = pg_query($sql); if (!$result) { print "Unable to retrieve data"; exit; }

$terms = array(); while ($obj = pg_fetch_object($result)) { if (! array_key_exists($obj->class_id, $current)) { $values = array('name' => $obj->class_name, 'vid' => $vid,); taxonomy_save_term($values); $tid = taxonomy_get_tid($obj->class_name, $vid); db_query("INSERT INTO map_terms (table_name, class_id, tid, vid) VALUES('%s', %d, %d, %d)", 'classification', $obj->class_id, $tid, $vid); echo "$tid <br/>"; } }}

URL RedirectionSteps

Confirm with client the urls to be redirectedInstall path_redirect moduleIdentify which urls can be generated from node/{nid}Identify which urls are views to be createdAny remainder on the list not covered by node/{nid} or views, discuss with client possiblesolutions, and come to an agreementAnalyze pattern of old url generation, find a logical pattern, usually can be obtained fromtables in the old databasecreate a script that uses the mapping of drupal's node table to old database (created earlier)to populate path_redirect table

Details

With path redirect module, all their old links would work and redirect properly 301 to the newitems.

To test path redirect, they can go to the admin page /admin/build/path-redirect, or to really test,they could alter their hosts file to point to the beta server, and see what happens when they look upan old url.

$rid = db_next_id('{path_redirect}_rid'); $old_url = 'music-reviews'; $new_url = 'reviews/music'; db_query("INSERT INTO {path_redirect} (rid, path, redirect, type) VALUES (%d,'%s', '%s', '%s')", $rid, trim($old_url, '/'), trim($new_url, '/'), '301');

Regeneration of url aliases

If the customer changes their mind about the url structure, no need to regenerate most of theredirect links. The path redirect module works together with the url alias table to provide thecorrect url.

delete the url aliases from url_aliases table using the menu option to delete aliases for all nodes, orwith sql to delete certain aliases

DELETE FROM url_alias WHERE src LIKE 'node%' AND dst LIKE 'movies/%';

note if the new pathauto pattern is similar or identical to the old url's populated in path_redirect,then please patch pathauto with http://drupal.org/node/261615 so that if the url auto-generated isidentical, delete the row from path_redirect instead of creating the url in url_alias with -0 added.

Using geonames and importing locationenabled nodes

Page 143: Drupal - Installation Guide

function xmlfromplace($name, $country, $type) { $str = 'http://ws.geonames.org/search?q='; $str .= $name; if ($type == 'city') { $str .= '&featureClass=P&country='; } elseif ($type == 'province') { $str .= '&featureCode=ADM1&country='; } elseif ($type == 'country') { $str .= '&featureClass=A&country='; } else { $str .= '&country='; } $str .= $country; $str .= '&maxRows=1'; $xml = simplexml_load_file($str); return $xml;}

function insertlocation($node, $city, $postal_code, $province, $country, $xml) { $lat = $xml->geoname->lat; $lon = $xml->geoname->lng; $l = array(); $l['city'] = $city; $l['province'] = $province; $l['country'] = $country; $l['lat'] = $lat; $l['lon'] = $lon; $l['source'] = 3; _location_save($l, $node, 'node');}

Parameters for insertlocation

node: full node objectprovince: 2 letter abbreviationcountry: 2 letter abbreviationxml: result from xmlfromplace()

Location table

For each location enabled node that is saved, a row is saved into the location table, wherelocation.eid = node.vid

mysql> describe location;+-------------+------------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------------+------------------+------+-----+---------+-------+| eid | int(10) unsigned | NO | | 0 | | | lid | int(10) unsigned | NO | PRI | 0 | | | type | varchar(6) | NO | | | | | name | varchar(255) | YES | | NULL | | | street | varchar(255) | YES | | NULL | | | additional | varchar(255) | YES | | NULL | | | city | varchar(255) | YES | | NULL | | | province | varchar(16) | YES | | NULL | | | postal_code | varchar(16) | YES | | NULL | | | country | varchar(2) | YES | | NULL | | | latitude | decimal(10,6) | YES | | NULL | | | longitude | decimal(10,6) | YES | | NULL | | | source | tinyint(4) | YES | | 0 | | | is_primary | tinyint(4) | NO | | 0 | | +-------------+------------------+------+-----+---------+-------+

+-----+-----+------+------+--------+------------+-----------+----------+-------------+---------+-----------+-------------+--------+------------+| eid | lid | type | name | street | additional | city | province |postal_code | country | latitude | longitude | source | is_primary |+-----+-----+------+------+--------+------------+-----------+----------+-------------+---------+-----------+-------------+--------+------------+| 9 | 1 | node | | | | Vancouver | BC | | ca | 49.263588 | -123.138565 | 3 | 0 | +-----+-----+------+------+--------+------------+-----------+----------+-------------+---------+-----------+-------------+--------+------------+

Get started by creating a list* Content* Comments* Files & Images* Users and Roles* External services, either relying or providing

ContentCould be delivered in html/xml format or as a database dump.Need to determine how to organize content so that the drupal cck content types, taxonomies orother can be created.

Comments

Page 144: Drupal - Installation Guide

Is there a commenting system and are the comments to be migrated.

Files & ImagesHow are files stored, can the path be referenced directly, or do they need to be stored as nodes.For images, use the image module or imagefield?

Users and RolesWhat users if any to migrate over, how does the access system in the old site translate into drupal'suser access system?

External ServicesDoes the site provide feeds or other services? Or does the site depend on other external servicessuch as Amazon, Youtube, etc. How will the interaction be translated?

Deciding when to use cck and taxonomyWhen importing to cck content types, a very good understanding is needed of the clients olddatabase, what their business use cases are, how they interact with the data, and what are the newrequirements.

The content types have to be created and have approval from the client that, they work in the waythe client is expecting, before the bulk of database migration is started.

Creating content types

The customer may identify different grouping of pages that they are likely to create, e.g. newsreleases, products, companies. Depending on how each grouping of data interacts with each other,it could be either:

content type

content types can be as simple as all the data in the body field, or depending on how theclient may want to sort and filter data, each piece of information segregated into fieldsmake use of node reference fields to describe relationship between content types, e.g. a filmhas many actors, where both film and actor are both content types, since the client describesdetails about both films and actorsif the client does not store, and will likely not store more details about a piece of data, e.g.festival, then festival would be a taxonomy instead.

vocabulary/taxonomy/category

used for a simple list of items. Very powerful tool. Not used when there are more detailsdescribing that vocabulary term. For example: book awards could be a vocabulary for onesite, for another site, that is mainly concerned with awards, it would be a content type. As acontent type, more details about each book award can be stored, sorted, filtered andsearched.if in the first phase a type of content is stored as taxonomy, and then later the customerdecides to expand the use of that content, no need to stress, it is not too difficult to converttaxonomy terms into nodes.

custom field

node/view reference field

drop down cck fields

be very wary and hesitant of using drop down cck fieldsmainly useful for static grouping of items, e.g. yes/no or monday/tuesday ... /sundayuse taxonomy or node/view reference instead if listing is likely to be altered.

If approaching content type bloat

consider to combine content types together; for example instead of having ppl_actor,ppl_director content types, an alternative is to have people content type with a vocabulary ofperson type (actor, director, etc.).The benefit is that there would not be 2 or more nodes describing a single person.With 2 or more nodes of the same entity, it becomes difficult to accurately show all moviesParis Hilton acted in as well as all songs Paris Hilton sung in with a simple view.

The proper data architecture, as in proper for that client, not proper for all clients, will determinehow easy or difficult it is to accommodate likely future feature requests. This will impact themaintainability of the website as well.

Use mapping tables to control data import

Page 145: Drupal - Installation Guide

Create a mapping table to record the drupal nid to the unique id found on the old database. Thepurpose is to have a way of tracking the work done, and to have a way of double checking.

Also, it is used to know what data has already been inserted, and what new data has not yet beeninserted.

* the minimum columns in a mapping table would be** id : just the usual unique id for a table** nid: node nid created in drupal** label_id: unique id on the old database** other columns can be created as needed, for quick reference and checking.

How to migrate from many different forumsystemsWhen there is not yet a Drupal module for direct conversion from your current forum software,migration can often be done in two steps, via popular forums with many converters available.Possible procedures are for example:

Old forum -> phpBB -> DrupalOld forum -> vBulletin -> Drupal

Migration to Drupal via phpBB

For the Old forum -> phpBB step, see phpBB 3.0.x Convertors and phpBB 2.0.x Convertors. Ifyou need to install the old phpBB2 version, see Download legacy release (phpBB, like Drupal, isopen source).

For the phpBB -> Drupal step, see Drupal's phpBB2Drupal module, and the handbook sectionMigrating from phpBB.

Migration to Drupal via vBulletin

For the Old forum -> vBulletin step, there are modules in vBulletin's ImpEx Import System toimport from a large number of forum systems.

For the vBulletin -> Drupal step, see the vBulletin to Drupal module, and the handbook pageMigrating from vBulletin.

Features and performance

For a Drupal forum with features similar to those of well-known forum systems such as phpBBand vBulletin, see the Advanced Forum module.

For good speed and performance similar to those of server-friendly static html files used by someforum systems, see Drupal's Boost static cache for anonymous users, and other performancemodules.

See also

The Migrating to Drupal handbook section includes general methods, and also sub-sections onmigrating from specific software systems, such as forums and CMS.

How to preserve old URLs during Drupal toDrupal migration by preserving nids andusing mod_rewriteThe problem: When migrating content into a Drupal site, no contributed modules provide a way topreserve old NID's during content import when consolidating several Drupal sites into a singleinstallation. Please post counterexamples to this thread, if you know any.

Therefore, it is impossible to preserve old URLs with those modules. Without a way of mappingthe old NIDs to their new NIDs, it is impossible to ensure that inbound links from other sites willbe preserved.

My particular challenge: This is a write up of how to merge three sites into one while preservingNIDs. When a request comes from oldsite2.com/node/23 it forwards to that nodes new location onthe new site, newsite.com/node/2023, likewise from oldsite1.com/node/23 tonewsite.com/node/4023. See the problem this solves? I imagine that most people won't find thisentire post particularly useful, but you can take parts of it as you might need.

This was a requirement for our client, and so I underwent a somewhat lengthy process to do this.There are probably several steps of this process that can be handled in a different way (forinstance, the awk script could have been an SQL or PHP script). Feel free to post those to thisthread.

I post this as a conceptual overview and some of my code so that others might benefit. I owe

Page 146: Drupal - Installation Guide

much to the Aquia migration blog post on this subject.

The solution overview: Migrate your old NIDs in a programmatic fashion. For instance, if an oldsite's node had a NID of 215, make it 2215, or , if it had a NID of 3, make it 2003. Add 2000 tothe NIDs in the old database, then export them, and import them into the new database (usingPHPmyAdmin or Drush or something). We also added 2000 to all comments and terms and thingsand imported them. We also mapped old input formats to new ones. The scripts below are justSAMPLES, and cannot be run verbatim.

Also export the url_alias table, and iterate through it with the language of your choice, adding2000 to the NIDs in that file. I used awk.

Next, any URL that comes from the old site's address, check it for paths /node/nid, and rewrite itwith mod_rewrite in the .htaccess file.

At the end of this process, any URL coming from oldsite.org/node/1 will be redirected andrewritten to newsite.org/node/2001. You can migrate in two sites, modifying these scripts to add6000 to the url of the second site, so that oldsite2.org/node/1 will be redirected tooldsite.org/node/6001.

As you may have guessed, this tutorial is not for the faint of heart.

First, upgrade all your sites to the current version of Drupal, in my case Drupal 6. If you're doingthis in Drupal 7, you'll have to modify this tutorial accordingly. You want to migrate from onetable to another preserving structure. I ran into this issue when upgrading from 4.7 with Spanishcharacters and solved it like this

NEXT: CREATE A COPY OF YOUR OLD DATABASE. RUN THESE SCRIPTS ON A COPY,NOT ON YOUR ORIGINAL.

2. Run your SQL scripts. Here are mine:

# add 2000 to nids, vids, and uids in node and node_revisionsUPDATE node SET nid = nid+2000;UPDATE node SET vid = vid+2000;UPDATE node SET uid = uid+2000;UPDATE node_revisions SET nid = nid+2000;UPDATE node_revisions SET vid = vid+2000;UPDATE node_revisions SET uid = uid+2000;

# map input formats/filters to new formats/filtersUPDATE node_revisions SET format = replace( format, 2, 6 ) ;UPDATE node_revisions SET format = replace( format, 3, 2 ) ;UPDATE node_revisions SET format = replace( format, 5, 3 ) ;UPDATE node_revisions SET format = replace( format, 4, 5 ) ;UPDATE node_revisions SET format = replace( format, 6, 3 ) ;

## correct a mistake I made!!! (in case you make a mistake)UPDATE node_revisions SET format = replace( format, 1, 1 ) WHERE nid > 1999;

##these are so that attachments work. UPDATE files SET fid = fid+2000;

UPDATE upload SET fid = fid+2000;UPDATE upload SET nid = nid+2000;UPDATE upload SET vid = vid+2000;

##make the user ids that created the files match. Otherwise you'll probably getan access denied errorUPDATE files SET uid = uid+2000;

## or, on another note, the following code can be used alternately to changeUID's from one to another. This has been useful to me in other projects.

UPDATE files SET uid = replace( uid, 8, 2 ) ;UPDATE files SET uid = replace( uid, 4, 55 ) ;

##this is to update the new location of the files, if it's changed. Maybeyou'll need it, maybe not.UPDATE files SET filepath = replace( filepath, 'sites/default/files','sites/newsite/files' ) ;

This next part was written by my co-worker, Josue.

## term_data UPDATE term_data SET tid = tid+2000;UPDATE term_data SET vid = replace( vid, 3, 15 );UPDATE term_data SET vid = replace( vid, 4, 16 );UPDATE term_data SET vid = replace( vid, 5, 2 );

##vocabularyUPDATE vocabulary SET vid = replace( vid, 3, 15 );UPDATE vocabulary SET vid = replace( vid, 4, 16 );UPDATE vocabulary SET vid = replace( vid, 5, 2 );

##vocabulary_node_typesUPDATE vocabulary_node_types SET vid = replace( vid, 3, 15 );UPDATE vocabulary_node_types SET vid = replace( vid, 4, 16 );UPDATE vocabulary_node_types SET vid = replace( vid, 5, 2 );

## term_hierarchyUPDATE term_hierarchy SET tid = tid+2000;

## term_node

Page 147: Drupal - Installation Guide

UPDATE term_node SET nid = nid+2000;UPDATE term_node SET tid = tid+2000;UPDATE term_node SET vid = vid+2000;

#usersUPDATE users SET uid = uid + 2000;

#users_rolesUPDATE users_roles SET uid = uid + 2000;

#commentsUPDATE comments SET cid = cid + 2000;UPDATE comments SET nid = nid + 2000;UPDATE comments SET uid = uid + 2000;

After running your (MODIFIED) scripts, export each of the modified tables, and then import themusing phpmyadmin or mysql commands or drush or whatever.

Now of the url_alias table. This was tricky because the path looks something like /node/23. Youcan add 2000 to a string. You have to pull out the number, add 2000, then rebuild it. Nice, huh?

So, export your old url_alias table, as is. With a good text editor, chop the first part off the file sothat it's just the data, and not the table definitions.

Then, modify this awk shell script and run it. I used gawk in linux, that is, gnu awk. Manual here.Yes, PHP could be used, too, to modify the tables in the database. Awk, however, is designed toregard text files as databases and provide complex string manipulation. While this script workedfor me, it should be tested and tweaked.

This script must be executed on a csv export of a database (I exported from phpmyadmin) fieldsterminated by |. The quotation marks enclosing a field must be searched for and deleted. The datashould look like this:

4407|taxonomy/term/855/0/feed|tag/vegetarianism/feed|4408|taxonomy/term/856|tag/soul-force|4409|taxonomy/term/856/0/feed|tag/soul-force/feed|

You can modify it afterwards to make it into an SQL file with inserts by combining it with anSQL export done the normal way.

Execute it like #script.sh url_aliases_export.sql > your_output_file.sql

#!/bin/bash

# this requires a csv file with a fields terminated by | and the fields enclosedwith ' Export using phpmyadimin

TEMPFILE=/tmp/pd.key.tempfile.$$TEMPFILE2=/tmp/pd.key.tempfile2.$$NID=/tmp/pd.key.nid.$$NID2=/tmp/pd.key.nid2.$$

trap "exit 1" HUP INT PIPE QUIT TERMtrap "rm -f $NID" EXIT#sed -e 's/\|\|/\|\'\'\|/g' sed -e '/^$/d' < $1 > $TEMPFILEa=(blank blank2)awk -v Q="'" -v NID2=0 'BEGIN { FS = "|"; OFS = "," } { gsub(Q, "", $1) ;gsub(Q, "", $2) ; $1 = $1 + 200000; match($2, /[0-9][0-9]?[0-9]?[0-9]?[0-9]?/,a) ; NID2 = a[0] + 2000 ; gsub(a[0], NID2, $2) } { print "(" Q $1 Q , Q $2 Q,Q $3 Q , Q "en" Q "),"}' $TEMPFILE

Check over this file. You may need to add a semicolon on the end, and clean it up a bit. Make sureit's right. Compare it to your other file. Paste the old table definitions stuff back in. Import it intoyour new database. It may catch on some URLS that have already been defined. Just delete thefirst half of the file (the part already imported) minus the field definitions, and delete the offendingline in your import sql.

See if your nodes and url aliases work as they are. You'll have to rebuild site permissions now oryou'll get "access denied" errors over at Content -> Post Settings: admin/content/node-settings.

Now for the mod_rewrite magic. For more info, check out the migration blog and the mod_rewriteonline documentation, a nice introduction, tons of examples, or this cheat sheet.

Finally, the most important thing to remember is that the RewriteCond is checking internal servervariables. the RewriteRule is just checking and rewriting the URL. This doesn't change the internalserver variables.

Paste the following into your .htaccess file.

# check each url and see if it is from the old sites. If oldsite1.org, add 6000to the node. If oldsite2.net, add 2000.

RewriteCond %{HTTP_HOST} ^oldsite1\.org$ [NC]RewriteCond %{QUERY_STRING} ^q=node/([0-9]{3})$ [NC]RewriteRule ^.*$ http://newsite.org/index.php?q=node/6%1 [R=301,L]

RewriteCond %{HTTP_HOST} ^oldsite1\.org$ [NC]RewriteCond %{QUERY_STRING} ^q=node/([0-9]{2})$ [NC]RewriteRule ^.*$ http://newsite.org/index.php?q=node/60%1 [R=301,L]

Page 148: Drupal - Installation Guide

RewriteCond %{HTTP_HOST} ^oldsite1\.org$ [NC]RewriteCond %{QUERY_STRING} ^q=node/([0-9]{1})$ [NC]RewriteRule ^.*$ http://newsite.org/index.php?q=node/600%1 [R=301,L]

RewriteCond %{HTTP_HOST} ^oldsite2\.net$ [NC]RewriteCond %{QUERY_STRING} ^q=node/([0-9]{3})$ [NC]RewriteRule ^.*$ http://newsite.org/index.php?q=node/2%1 [R=301,L]

RewriteCond %{HTTP_HOST} ^oldsite2\.net$ [NC]RewriteCond %{QUERY_STRING} ^q=node/([0-9]{2})$ [NC]RewriteRule ^.*$ http://newsite.org/index.php?q=node/20%1 [R=301,L]

RewriteCond %{HTTP_HOST} ^oldsite2\.net$ [NC]RewriteCond %{QUERY_STRING} ^q=node/([0-9]{1})$ [NC]RewriteRule ^.*$ http://newsite.org/index.php?q=node/200%1 [R=301,L]

RewriteRule !^http://newsite.org$ '-' [C]RewriteRule ^http://[.*]/([.*])$ '-' [C]RewriteRule ^(.*)$ http://newsite.org/$1 [R=301,L]

# rewrite all www's to the base name. Necessary to not write exceptions to theabove rules and make things nice and clean

RewriteCond %{HTTP_HOST} ^www\.oldsite1\.org$ [NC] RewriteRule ^(.*)$ http://oldsite1.org/$1 [L,R=301]

RewriteCond %{HTTP_HOST} ^www\.oldsite2\.net$ [NC] RewriteRule ^(.*)$ http://oldsite2.net/$1 [L,R=301]

RewriteCond %{HTTP_HOST} ^www\.newsite\.org$ [NC] RewriteRule ^(.*)$ http://newsite.org/$1 [L,R=301]

#rewrites anything from the old sites that that don't have node in them (all oldurls) to newsite.org/whatever_the_old_one_was

RewriteCond %{HTTP_HOST} ^(oldsite2\.net)$ [NC]RewriteRule !^.*node.*$ '-' [C]RewriteRule ^(.*)$ http://newsite.org/$1 [R=301,L]

RewriteCond %{HTTP_HOST} ^(oldsite1\.org)$ [NC]RewriteRule !^.*node.*$ '-' [C]RewriteRule ^(.*)$ http://newsite.org/$1 [R=301,L]

[C] means execute the following if and only if the current rule succeeds.[NC] means capitalization is irrelevant.[R=301] means permanent redirect.[L] Means last rule, quit processing() captures the enclosed and creates a variable that can be accessed later using $1 or %1

To troubleshoot this (surely it will all work perfectly!), enable devel module's execute php blockand execute print_r($GLOBALS); This will spit out all the internal apache server variables, whichyou can use to check to see if the RewriteCond can see the right stuff. Make sure you do thistemporarily, don't print your variables anywhere in your theme or anything. That would be reallybad, as the code contains your main database password and username.

Other than that, it's all probably working without a hitch now, and I suggest a cold beer. Youdeserve it.

Migrating from ACT!When I imported 3000 or so nodes from my ACT! database into a local Drupal site it all workedwell but because all the dates were in dd/mm/yy format they would not import using Node import .

I opened the .csv file in Excel and added two columns:'(unix) Create Date' for Create Dateand'(unix) Edit Date' for Edit DateI then used this formula to make the Unix timestamp=IF(A1, (A1-25569-(-5/24))*86400,"")Note:A1 is the cell that contains the dd/mm/yy or mm/dd/yy (your computer knows about the way youformat dates in your country) and the 5 is to set the time to 5am.

Migrating from BricolageIf a customer has a Bricolage site, and wants to use some of the features of drupal, they can tryout the Bricolage Integration module: http://drupal.org/project/bricolage

Otherwise, it is also possible to migrate from a Bricolage project entirely to drupal. To migratedata, I analyzed the database, to get unique ids (story__id) and the directory structure of thegenerated html files. Taxonomy and/or content type was determined from the directory structure,and main content was parsed from the html files.

* determine the bricolage story__id associated with types of content to be migrated fromBricolage, e.g. 1041 for article, 1054 for blog, 1063 for review, 1065 for artist.

* Identify all the story__id's that need to be imported, and store them in a mapping table to trackor trace what stories have already been imported.

Page 149: Drupal - Installation Guide

SELECT id, primary_uri, publish_date FROM story WHERE element__id IN (1041, 1054, 1063, 1065) AND active != 0

* Some data was obtained from the database by joining the story table (~ drupal's node table) tostory_instance table (~ drupal's node_revisions), for example short_val equated to the storiessubtitle when story_data_tile.element_data__id = 1070. In bricolage each paragraph or other itemhas its own row in the story_data_tile table.

SELECT s.id, s.primary_uri, s.publish_date, d.short_val FROM story s JOIN story_instance i ON s.id = i.story__id AND s.current_version = i.version JOIN story_container_tile t ON t.object_instance_id = i.id JOIN story_data_tile d ON t.id = d.parent_id WHERE t.element__id = 1041 AND d.element_data__id = 1070 AND d.active != 0 AND s.element__id IN (1041, 1054, 1063, 1065) AND s.active !=0

* other data was obtained by parsing the html files using fopen() and preg_match()

* image paths were replaced by using preg_replace() and the old and new path stored in amapping table for images, which were converted into imagefields for the story.$img['path'] = trim(preg_replace("/(.*?)[\\\"|'](.*?)[\\\"|'](.*)/", "$2",$buffer));

Migrating from CPG Dragonfly CMSNote: heavy editing in progress

Migrating from CMS Dragonfly CMS consists of two parts: first, migrating the forums using thephpBB2Drupal module (which migrates the users, profiles, forums, forum posts and replies,private messages, and polls) and second, migrating everything else (the articles, categories,roles...).

Migrating the forums1. Install Drupal and the following modules:

phpBB2DrupalBBCodeComment UploadPrivateMsg

2. Enable all of the above modules, plus:ForumPollProfile

3. Create a BBCode input format, and set as the default:1. Go to administer >> input formats (4.7.x) or Administer >> Site Configuration >>

Input Formats (5.x).2. Click Add input format, and enter the following options:

Name: BBCodeRoles: anonymous user, authenticated userFilters: BBCode

3. Click Save.4. Back at the main input formats screen, click the radio next to BBCode and press Set

default format.4. Apply the DragonflyCMS patch to phpBB2Drupal module.5. Configure the php2Drupal migration:

1. Click administer >> phpBB to Drupal (4.7.x) or Administer >> X >> phpBB toDrupal (5.x)

2. Click Configure the migration3. Enter the following settings:

Test on copy first > checkedInput format settings > Input format: BBCodeLocation of phpBB2 data > phpBB2 table prefix: cms_bbMisc settings > Convert Registration Date: checkedPolls import: Import polls? checkedPrivate Messages > Import private messages? checked

4. Click Save configuration6. Make sure you have a backup of your database, and then click Execute the migration

from the main phpBB2Drupal screen.7. Execute each step of the migration by clicking the Import button. Each step will import

separate data from phpBB.

Migrating everything elseBelow is the beginning of a script to handle migration from CPG Dragonfly CMS 9.0.6.1 toDrupal 4.7. I'll post updates as I get more completed in the coming weeks.

IGNORE the rest of this page for now!!

<?php// $Id$

/*** @file

Page 150: Drupal - Installation Guide

* Handles data import from CPG Dragonfly CMS 9.0.6.1 to Drupal 4.7. Or willsomeday,* when I get it finished. :P For now it only handles user and profile fields.** To use:* 1. Save this script as "dragonfly2drupal.php" in the root of your Drupalinstallation.* 2. Change the DRAGONFLY_PREFIX variable if needed -- defaults to 'cms_'* 3. In your settings.php file, change the $db_url as follows:** BEFORE:* $db_url = 'mysql://user:pass@host/drupal_db';** AFTER:* $db_url['default'] = 'mysql://user:pass@host/drupal_db';* $db_url['dragonfly'] = 'mysql://user:pass@host/dragonfly_db';**/

include_once "includes/bootstrap.inc";drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

/** Dragonfly CMS table prefix **/define('DRAGONFLY_PREFIX', 'cms_');

echo '<h2>Importing users...</h2>';dragonfly_user_import();echo '<h2>Done.</h2>';

echo '<h2>Adding profile fields...</h2>';dragonfly_add_profile_fields();echo '<h2>Done.</h2>';

echo '<h2>Importing profile fields...</h2>';dragonfly_user_profile_import();echo '<h2>Done.</h2>';

echo '<h2>Importing topics...</h2>';dragonfly_import_topics();echo '<h2>Done.</h2>';

echo '<h2>Importing blogs...</h2>';dragonfly_import_blogs();echo '<h2>Done.</h2>';

/* FUNCTION DECLARATIONS */

function dragonfly_user_import() {

// Drupal => Dragonfly field mappings $user_fields = array( 'uid' => 'user_id', 'name' => 'username', 'pass' => 'user_password', 'mail' => 'user_email', 'created' => 'user_regdate', 'access' => 'user_lastvisit', 'login' => 'user_session_time', 'status' => 'user_level', 'init' => 'user_email', );

// Retrieve all user records from Dragonfly except anonymous user (#1) db_set_active('dragonfly'); $dragonfly_users = db_query('SELECT * FROM %susers WHERE user_id != 1 ORDER BYuser_id', DRAGONFLY_PREFIX);

// Back to Drupal; handle any data conversion and then import the user info db_set_active('default'); while ($user = db_fetch_object($dragonfly_users)) { // Convert registered time $user->user_regdate = strtotime($user->user_regdate);

// Set all users but blocked users to active if ($user->user_level != 0) { $user->user_level = 1; }

// TODO: user avatar handling // Dragonfly lets you choose from a pre-existing avatar in the gallery, // upload a picture to the site, or link to an external image -- these // all need to go under files/pictures/picture-XX.png|jpg|gif, where XX // is the user's uid.

// TODO: signature handling // The tricky part here is that Dragonfly's signatures are in BBCode, // which Drupal can't parse natively.

// TODO: Handle blocked users

// Generate SQL string $sql = drupal_generate_sql_string('users', $user, $user_fields); db_query($sql);

}

// Increase sequence in sequences table $uid = db_result(db_query("SELECT MAX(uid) FROM {users}")); $sql = "UPDATE {sequences} SET id = $uid WHERE name = 'users_uid'"; db_query($sql);

Page 151: Drupal - Installation Guide

}

function dragonfly_add_profile_fields() { // Real name $profile_values = array( 'title' => t('Real Name'), 'name' => 'profile_real_name', 'category' => t('Profile Information'), 'type' => 'textfield', 'visibility' => 1, 'weight' => -4, ); profile_field_form_submit(NULL, $profile_values);

// Home Page $profile_values = array( 'title' => t('Website'), 'name' => 'profile_website', 'category' => t('Profile Information'), 'type' => 'textfield', 'visibility' => 2, 'weight' => -2, ); profile_field_form_submit(NULL, $profile_values);

// TODO: My Location - use Location/Gmap module for this?

// My Occupation $profile_values = array( 'title' => t('My Occupation'), 'name' => 'profile_occupation', 'category' => t('Profile Information'), 'type' => 'textfield', 'visibility' => 2, 'weight' => 0, ); profile_field_form_submit(NULL, $profile_values);

// My Interests $profile_values = array( 'title' => t('My Interests'), 'name' => 'profile_interests', 'category' => t('Profile Information'), 'type' => 'textfield', 'visibility' => 2, 'weight' => 2, ); profile_field_form_submit(NULL, $profile_values);

// Bio $profile_values = array( 'title' => t('Bio'), 'name' => 'profile_bio', 'category' => t('Profile Information'), 'type' => 'textarea', 'visibility' => 2, 'weight' => 4, ); profile_field_form_submit(NULL, $profile_values);}

function dragonfly_user_profile_import() { $profile_fields = array( 'name' => 'profile_real_name', 'user_website' => 'profile_website', 'user_occ' => 'profile_occupation', 'user_interests' => 'profile_interests', 'bio' => 'profile_bio', );

// Get field IDs for the various profile fields $fids = array(); foreach ($profile_fields as $key => $value) { $fids[$key] = db_result(db_query("SELECT fid FROM {profile_fields} WHEREname = '$value'")); }

// Retrieve profile fields from Dragonfly $fields = implode(', ', array_keys($profile_fields)); db_set_active('dragonfly'); $result = db_query("SELECT user_id, $fields FROM %susers ORDER BY user_id",DRAGONFLY_PREFIX);

// Import data db_set_active('default'); while ($user = db_fetch_array($result)) { $uid = $user['user_id']; foreach ($user as $key => $value) { if (!empty($value) && $key != 'user_id') { db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d,'%s')", $fids[$key], $uid, $value); } } }}

// Taxonomyfunction dragonfly_import_topics() { $vocabulary = array( 'name' => t('Topic'),

Page 152: Drupal - Installation Guide

'nodes' => array('story'), ); //taxonomy_save_vocabulary($topic); // Get vocabulary ID //$vocabulary['vid'] = db_result(db_query("SELECT id FROM {sequences} WHEREname = '%s'", db_prefix_tables('{vocabulary}_vid')));

// Grab all topics db_set_active('dragonfly'); $result = db_query("SELECT * FROM %stopics ORDER BY topicid",DRAGONFLY_PREFIX); $terms = array(); while ($topic = db_fetch_array($result)) { $terms[] = array( 'tid' => $topic['topicid'], //'vid' => $vocabulary['vid'], 'name' => $topic['topictext'], ); } db_set_active();

// Write XML file // Note: This line messes up codefilter -- change to ? > without a space. $xml = '<?xml version="1.0" standalone="no"? >' . "\n"; $xml .= '<!DOCTYPE taxonomy SYSTEM "taxonomy.dtd">' . "\n"; $xml .= "<vocabulary>\n"; foreach ($vocabulary as $key => $value) { if (is_array($value)) { $xml .= " <$key>" . check_plain(implode(',', $value)) . "</$key>\n"; } else { $xml .= " <$key>" . check_plain($value) . "</$key>\n"; } } foreach ($terms as $term) { $xml .= " <term>\n"; foreach ($term as $key => $value) { $xml .= " <$key>" . check_plain($value) . "</$key>\n"; } $xml .= " </term>\n"; } $xml .= "</vocabulary>\n";

taxonomy_xml_parse($xml); // TODO: images}

function dragonfly_import_blogs() { db_set_active('dragonfly'); $result = db_query("SELECT * FROM %sblogs", DRAGONFLY_PREFIX); db_set_active();

while ($post = db_fetch_object($result)) { $blog = new stdClass(); $blog->type = 'blog'; $blog->title = $post->title; $blog->body = $post->text; $blog->teaser = node_teaser($post->text); $blog->uid = drupal_get_user_id($post->aid); $blog->status = 1; $blog->created = $post->timestamp; $blog->changed = $post->timestamp; $blog->comment = 2; node_save($blog); }}

function drupal_get_user_id($username) { return db_result(db_query("SELECT uid FROM {users} WHERE name = '%s'",$username));}

function drupal_generate_sql_string($table, $object, $mapping) { $fields = array(); $values = array(); foreach ($mapping as $key => $value) { $fields[] = $key; $values[] = $object->$value; } $fields = implode(', ', $fields); $values = implode("', '", $values);

return "INSERT INTO {$table} ($fields) VALUES ('$values')";}?>

Migrating from DCForum+This work is not cleaned up, but then again I've been meaning to clean it up since November!Trying to start 2006 on a fresh slate so here goes.

However, basic thing is that it works. It is not recommended for those who are not comfortablewith php/mysql. And then again, if you're doing/thinking about doing this in the first place thenyou've either got a lot of chutzpah or you know what you are doing.

Functionality:

Page 153: Drupal - Installation Guide

There are two scripts to be run in order which together allows you to migrate dcforum+ (the mysqldatabase backed version) user accounts (usernames and profiles + password recognition), andforum posts.

Live example: http://research.yale.edu/swahili/learn just migrated to Drupal from dcforum+ and ahomecooked CMS.

1. dcforumintegration.module(Depends on forum.module, and flatforum.module)Enable it and run as the first admin user so that it won't be available to any other user.Enabling the module will generate a menu link called "migrate dcf". On clicking, there will belinks toa. Migrate usernames and emails [Click the "Undo" link to reverse this process]b. Migrate forum containers [Click the "Undo" link to reverse this process]c. Migrate forum posts + responses (as Drupal comments) [Click the "Undo" link to reverse thisprocess]

The "Undo" links were put there for my own sanity.

2. dcprofilesmigration.modulea. Create the profile fields you want to migrate using the profile.moduleb. Enabling this module generates a menu item called "mdata". On clicking, there will be a pagethat lists all the profile columns in dcforum (from the dcuser table). Each column has a drop-downlist with all the Drupal profile fields.c. Match the Drupal profile fields to the dcuser profile field of your choice and select thecheckboxes of the matched fields.d. Click the Submit button at the bottom of the page to run the profile migration SQL queries. Thegenerated queries will also be displayed in the textarea at the bottom of the page for manualinspection.

Hope this helps someone.

dcforumintegration.module<?php/** dcforumintegration.module* From: DCForum+ User Accounts and Forum * To Drupal forum and flatforum module.* Passwords are migrated by modifying user.module* Remember to search and replace "$my_dcf_dbase" with the name of the dcforum+mysql database. */

function dcforumintegration_menu($may_cache){ global $user; $items = array(); $admin_access = user_access('administer site configuration'); $items[] = array('path' => 'dcf', 'title' => t('migrate dcf'), 'callback' => 'actions', 'access' => $admin_access); $items[] = array('path' => 'dcf/users', 'title' => t('migrate dcf users'), 'callback' => 'actions', 'access' => $admin_access); $items[] = array('path' => 'dcf/forums', 'title' => t('migrate dcfforums'), 'callback' => 'actions', 'access' => $admin_access, weight=> '1'); return $items;}

//------------HELPER FUNCTIONS------------------//

function actions(){ switch(arg(1)) { case 'users': $output = migrate_users(); break; case 'forums': { if(arg(2) == "toplevel") { $output = migrate_containers(); $output.= migrate_forums(); } else if(arg(2) == "undotoplevel") { $output = unmigrate_containers(); $output.= unmigrate_forums(); } else if(arg(2) == "topposts") $output = migrate_topposts(); else if(arg(2) == "undotopposts") $output = unmigrate_topposts(); } break;

Page 154: Drupal - Installation Guide

default: $output = "<li>".l('Migrate Users', 'dcf/users')."</li><br/><b>Note thatall users except the root user will be deleted from the database</b>"; $output .= "<li>".l('Migrate Forums','dcf/forums')."</li><br/><b>Perform the following in order <br/>Remember to augment the node, comment tables with the two fieldsfrom $my_dcf_dbase</b>"; $output .= "<ul><li>".l('Migrate Top Level Forums','dcf/forums/toplevel')." [".l('Undo', 'dcf/forums/undotoplevel')."]</li>"; $output .= "<ul><li>".l('Migrate Top Level Posts + comments/responses)','dcf/forums/topposts')." [".l('Undo', 'dcf/forums/undotopposts')."]</li>"; break; } print theme('page',$output);}

function migrate_users(){ # Step 1: Migrate Users

db_query("DELETE FROM {users} WHERE uid!=1"); db_query("INSERT INTO {users} (uid) VALUES(0);"); db_query('INSERT INTO {users} (uid, name, pass, mail, signature, mode,status, init, data, created, changed) SELECT id, username, password, email, pk,0, 1, email, "N;", reg_date, last_date FROM $my_dcf_dbase.dcuser WHERE id!=1;'); db_query("DELETE FROM {users_roles};"); db_query("INSERT INTO {users_roles}(uid, rid) VALUES(0, 1);"); db_query("INSERT INTO {users_roles}(uid, rid) VALUES(1, 2);"); db_query("INSERT INTO {users_roles} (uid, rid) SELECT uid, 2 FROM {users}WHERE uid != 1 AND uid !=0;"); # Set the user sequence! db_next_id("user"); watchdog('dcfmigration', "All users deleted, populated with dcuser entries",1); return "All users deleted, populated with dcuser entries".l('View ImportedUsers', 'admin/user');}

function migrate_containers(){ # number of vocabulary groups I already have $numvocgroups = db_fetch_object(db_query("SELECT id FROM {sequences} WHEREname = 'vocabulary_vid'")); $numvocgroups = $numvocgroups->id; # Step 3: Migrate toplevel containers # Remember to clear forum* variables from the variables table db_query("DELETE FROM {variable} WHERE name LIKE 'forum%'"); db_query("INSERT INTO {term_data} (tid, vid, name, description, weight) SELECT id, %d, name, description, forum_order FROM$my_dcf_dbase.dcforum WHERE parent_id='0';",$numvocgroups ); $res = db_query("SELECT id FROM $my_dcf_dbase.dcforum WHERE parent_id='0'"); #Make them containers $containers = variable_get('forum_containers', array()); while($tid = db_fetch_object($res)) { $containers[] = $tid->id; } variable_set('forum_containers', $containers);

db_query("INSERT INTO {term_hierarchy} (tid, parent) SELECT tid, 0 FROM {term_data;}");db_query("REPLACE INTO {sequences} (id, name) SELECT max(tid), 'term_data_tid'FROM {term_data}"); # Set the term_data_id sequence! return "Top level containers ".l('View forums', 'forum'); }

function unmigrate_containers(){ $tids = db_query("SELECT id, name FROM $my_dcf_dbase.dcforum WHEREparent_id='0'"); while($tid = db_fetch_array($tids)) { db_query("DELETE FROM {term_data} WHERE tid = %d ", $tid); db_query("DELETE FROM {term_hierarchy} WHERE tid = %d ",$tid); $output.= "<li>".$tid['name']; } variable_set('forum_containers', array()); db_query("REPLACE INTO {sequences} (id, name) SELECT max(tid),'term_data_tid' FROM {term_data}"); # Set the term_data_id sequence!

return $output."<br><b>Top Level Containers Deleted</b>"; }

function migrate_forums(){ # number of vocabulary groups I already have $numvocgroups = db_fetch_object(db_query("SELECT id FROM {sequences} WHEREname = 'vocabulary_vid'"));

Page 155: Drupal - Installation Guide

$numvocgroups = $numvocgroups->id; # Step 3: Migrate forums (these have parent_id's > 0) db_query("INSERT INTO {term_data} (tid, vid, name, description, weight) SELECT id, %d, name, description, forum_order FROM$my_dcf_dbase.dcforum WHERE parent_id >0 ;",$numvocgroups );

db_queryd("INSERT INTO {term_hierarchy} (tid, parent) SELECT id, parent_id FROM $my_dcf_dbase.dcforum WHERE parent_id >0"); db_query("REPLACE INTO {sequences} (id, name) SELECT max(tid),'term_data_tid' FROM {term_data}"); # Set the term_data_id sequence! return "Migrated Forums "; }

function unmigrate_forums(){ $tids = db_query("SELECT id, name FROM $my_dcf_dbase.dcforum WHERE parent_id> 0"); while($tid = db_fetch_array($tids)) { db_query("DELETE FROM {term_data} WHERE tid = %d ", $tid); db_query("DELETE FROM {term_hierarchy} WHERE tid = %d ",$tid); $output.= "<li>".$tid['name']; } db_query("REPLACE INTO {sequences} (id, name) SELECT max(tid),'term_data_tid' FROM {term_data}"); # Set the term_data_id sequence!

return $output."<br><b>Forums Deleted</b>"; }

function migrate_topposts(){

//Need to update 5 main tables: forum, node, node_comment_statistics,term_node, flat_forum db_query("INSERT INTO {flatforum} (posts, uid) SELECT num_topics, uid FROM$my_dcf_dbase.dcforum, {users} WHERE {users}.name = last_author;"); # number of toplevel posts I have $initnodeoffset = db_fetch_object(db_query("SELECT id FROM {sequences} WHEREname = 'node_nid';")); $initnodeoffset = $initnodeoffset->id; # add all the forum topics (posts become comments to these topics) $allforums = db_query("SELECT id FROM $my_dcf_dbase.dcforum WHERE parent_id> 0"); //$allforums = db_query("SELECT id FROM $my_dcf_dbase.dcforum WHERE id =5");

while($eachforum = db_fetch_object($allforums)) { db_query('INSERT INTO {node} (forum_id, topic_id, type, title, uid,status, created, comment, promote, moderate, teaser, body, changed, revisions) SELECT %d, t.id, "forum", t.subject, t.author_id, 1, unix_timestamp(t.mesg_date), 2, 0, 0, t.subject, t.message , unix_timestamp(t.last_date) , "" FROM $my_dcf_dbase.%d_mesg t WHERE parent_id = 0', $eachforum->id, $eachforum->id); #Update the forum table db_query("INSERT INTO {forum} (nid, tid) SELECT nid, %d FROM $my_dcf_dbase.%d_mesg t, {node} n WHEREn.topic_id = t.id", $eachforum->id, $eachforum->id, $initnodeoffset, $eachforum->id); #Update the term_node table db_query("INSERT INTO {term_node} (nid, tid) SELECT nid, %d FROM $my_dcf_dbase.%d_mesg t, {node} n WHEREn.topic_id = t.id", $eachforum->id, $eachforum->id, $initnodeoffset, $eachforum->id);

#insert responses to posts as comments db_query("INSERT INTO {comments} (forum_id, topic_id, pid, nid, uid, subject, comment, hostname,timestamp) SELECT %d, t.id, n.topic_id, n.nid, t.author_id, t.subject, t.message, 'unknown', unix_timestamp(t.mesg_date)

Page 156: Drupal - Installation Guide

FROM {node} n, $my_dcf_dbase.%d_mesg t WHERE t.parent_id > 0 AND t.top_id =(n.topic_id)", $eachforum->id, $eachforum->id); #update node_comment_statistics db_query("REPLACE INTO {node_comment_statistics} (nid,last_comment_timestamp, last_comment_uid) SELECT nid, changed, uid FROM {node}"); /* db_query("INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid) SELECT DISTINCT(nid), unix_timestamp(t.last_date), last_author,n.uid FROM $my_dcf_dbase.%d_mesg t, {node} n WHERE n.topic_id = t.id",$eachforum->id, $initnodeoffset, $eachforum->id); */ }

#Update node_comment_statistics comment_count $allnodes = db_query("SELECT DISTINCT(nid) FROM {comments}");// WHEREnid=c.nid"); while($eachnode = db_fetch_object($allnodes)) { $no = db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE nid =$eachnode->nid")); db_query("UPDATE {node_comment_statistics} SET comment_count = $no WHEREnid = %d", $eachnode->nid); } $node_seq = (array) db_fetch_object(db_query("SELECT max(nid) FROM{node}")); db_query("UPDATE {sequences} SET id = %d WHERE name = 'node_nid'",$node_seq['max(nid)']); # Set the node sequence! $comments_seq = db_result(db_query("SELECT max(cid) FROM {comments}")); db_query("UPDATE {sequences} SET id = %d WHERE name = 'comments_cid'",$comments_seq); # Set the comments sequence! //update flatforums with users who have made posts $all_users = db_query("SELECT uid FROM {users}"); while($uid = db_fetch_object($all_users)) { $uid = $uid_>uid; $posts = db_result(db_query("SELECT COUNT(nid) FROM {node} n WHERE uid =%d", $uid)); $posts += db_result(db_query("SELECT COUNT(cid) FROM {comments} c WHEREuid = %d", $uid)); db_query('REPLACE INTO {flatforum} (uid, posts) VALUES (%d, %d) ', $uid,$posts); }}

function unmigrate_topposts(){ $res = db_query("SELECT uid FROM {users} INNER JOIN $my_dcf_dbase.dcforumWHERE {users}.name = last_author"); while($uid = db_fetch_object($res)) { db_query("DELETE FROM {flatforum} WHERE uid = %d", $uid->uid); } # number of toplevel posts I have $initnodeoffset = db_fetch_object(db_query("SELECT id FROM {sequences} WHEREname = 'node_nid';")); $initnodeoffset = $initnodeoffset->id; # remove the forum topics (posts become comments to these topics) db_query('DELETE FROM {node} WHERE type="forum"');

#Update the forum table db_query("DELETE FROM {forum}"); #Update the term_node table db_query("DELETE FROM {term_node}"); #update comments db_query("DELETE FROM {comments} WHERE forum_id!=0");

#update the node_comment_statistics db_query("DELETE FROM {node_comment_statistics}"); //update flatforums with users who have made posts $all_users = db_query("SELECT uid FROM {users}"); while($uid = db_fetch_object($all_users)) { $uid = $uid->uid; $posts = db_result(db_query("SELECT COUNT(nid) FROM {node} n WHERE uid =%d", $uid)); $posts += db_result(db_query("SELECT COUNT(cid) FROM {comments} c WHEREuid = %d", $uid)); db_query('REPLACE INTO {flatforum} (uid, posts) VALUES (%d, %d) ', $uid,$posts); }

Page 157: Drupal - Installation Guide

$comments_seq = db_result(db_query("SELECT max(cid) FROM {comments}")); db_query("UPDATE {sequences} SET id = %d WHERE name = 'comments_cid'",$comments_seq); # Set the comments sequence! $node_seq = (array) db_fetch_object(db_query("SELECT max(nid) FROM{node}")); db_query("UPDATE {sequences} SET id = %d WHERE name = 'node_nid'",$node_seq['max(nid)']); # Set the node sequence!

}?>

dcprofilesmigration.module<?php

/** dcprofilesmigration.module* From: DCForum+ User Profiles* To Drupal profile module.* Remember to search and replace "$my_dcf_dbase" with the name of the dcforum+mysql database. */function dcprofilesmigration_menu($may_cache){ global $user; $items = array(); $admin_access = user_access('administer site configuration'); $items[] = array('path' => 'mdata', 'title' => t('migrate profiles'), 'callback' => '_migrate_data', 'access' => $admin_access); return $items;}

function _migrate_data(){ $old = db_query("SELECT fid, name FROM {profile_fields}"); $output_old = array(); while($_old = db_fetch_object($old)) { $output_old[$_old->fid].= $_old->name; } $new = db_query("SELECT * FROM $my_dcf_dbase.dcuser LIMIT 1"); $output_new= array(); while($_new = db_fetch_array($new)) { $output_new = array_keys($_new); } $output.="<table>";

foreach($output_new as $key=>$new) { $output.= "<tr><td><input type='checkbox' name='select[$new]'value='$key'> </td><td>".form_select($new, $key, $key,$output_old)."</td></tr>"; } $output.="</table>"; $output.= form_button('SQL_QUERY'); $output = form($output);

$jcc_usernames = db_query("SELECT username FROM $my_dcf_dbase.dcuser"); $userids = array(); while($suser = db_fetch_object($jcc_usernames)) { $userids[].= db_result(db_query("SELECT uid FROM {users} WHERE name='%s'", $suser->username)); } $br = "<br/>"; foreach($userids as $uid) { if(sizeof($_POST)) { $edit = $_POST['edit']; $select = $_POST['select']; //print_r($edit); //print_r($select); foreach($select as $key=>$value) { $map[$key] = $edit[$value]; } //$map = (array_intersect(($select), ($edit) ));// print_r($map); foreach($map as $key =>$fid) { if(($key != "id") && ($key != "userlevel") && ($key !="username") && ($key != "password")) { $_userq= sprintf("REPLACE INTO {profile_values} (fid, uid,value) SELECT %d, %d, %s FROM $my_dcf_dbase.dcuser WHERE id=%d \n", $fid, $uid,$key, $uid);

Page 158: Drupal - Installation Guide

db_query($_userq); $userquery.= $_userq; } } $query = $userquery; } $textarea = $query; //$query = $textarea; } $output.= form_textarea("SQL", 'sql', $textarea, 70, 15);

print theme('page', $output);}

function get_key($select, $edit){ return $edit;}

?>

user.module - hacked for password migrationThis hack has two pieces and is meant to be temporary. It makes the fact of the migrationtransparent to regular users. Revert to the default user.module after you notice that most of yourregular users have visited your site. Everyone else can use the "request password reminder" featureto reset their passwords.

First is this file: dcuser.inc which just defines some basic functions required to encrypt dcuserpasswords.

<?php

function my_crypt($str,$salt) {

return crypt($str,substr($salt,0,2));

}

function check($username){

$q = "SELECT * FROM $my_dcf_dbase.dcuser WHERE username = '$username' ";

$result = mysql_query($q) or die(mysql_error());

if (! mysql_num_rows($result)) { $error = $in['lang']['no_such_user']; } else { $row = mysql_fetch_array($result); $in['last_date'] = $row['last_date']; if ($row['status'] != 'on') { $error = "Deactivated account"; } } return $row['password'];} ?>

And then in user.module replace user_load with the following(remember to replace$my_dcf_dbase with the actual name of your dcf mysql database):

<?phpfunction user_load($array = array()) {

// dcforum+ migration user.module hack: startinclude_once("dcforum/dcuser.inc"); //assuming that dcuser.inc is inmodules/dcforum

if(($array['name'] != "")){ $dcpass = my_crypt($array['pass'], check($array['name'])); $dcuser = db_fetch_array(db_query("SELECT id, username, password, g_id FROM$my_dcf_dbase.dcuser WHERE username='%s' AND password='%s'", $array['name'],$dcpass));

if((sizeof($dcuser) > 0) && ($dcuser['g_id'] > 0)) //valid dcuser! { //copy password into drupal database if not changed. $drpass = db_result(db_query("SELECT pass FROM {users} WHERE name='%s'",$array['name']));

Page 159: Drupal - Installation Guide

$array['name'])); if($drpass != md5($array['pass'])) { db_query("UPDATE {users} SET pass='%s' WHERE name='%s'",md5($array['pass']), $array['name']); } }}

// dcforum+ migration user.module hack: end

// Dynamically compose a SQL query: $query = '';

$params = array(); foreach ($array as $key => $value) { if ($key == 'pass') { $query .= "u.pass = '%s' AND "; $params[] = md5($value); } else if ($key == 'uid') { $query .= "u.uid = %d AND "; $params[] = $value; } else { $query .= "LOWER(u.$key) = '%s' AND "; $params[] = strtolower($value); } } $result = db_query_range("SELECT u.* FROM {users} u WHERE $query u.status <3", $params, 0, 1);

if (db_num_rows($result)) { $user = db_fetch_object($result); $user = drupal_unpack($user);

$user->roles = array(); $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN{users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid); while ($role = db_fetch_object($result)) { $user->roles[$role->rid] = $role->name; } user_module_invoke('load', $array, $user); } else { $user = new StdClass(); }

return $user;}?>

W32/TrojanDownloader.Ani.Gen

Migrating from DiscusDiscus is a message board software by DiscusWare. Migration from Discus boards to Drupalforums can be done in two or three steps. Some possible procedures are for example:

Discus -> phpBB 2 -> DrupalDiscus -> phpBB 2 -> phpBB 3 -> DrupalDiscus -> vBulletin -> Drupal

Migration to Drupal via phpBB 2 or 3

For the Discus -> phpBB 2 step, see markus_freerela's converter on the phpBB discussion Discus4 --> phpBB2 convertor, which also includes other converters. Markus' script has several versionsthat you can try, in order to find the most suitable for your board. Download links are: 2.0, 2.0.1,2.0.2, 2.1.0, 2.1.1, 2.2.0, 2.2.1, 2.2.3, 2.2.4. To install the needed old phpBB2 version, seeDownload legacy release (phpBB, like Drupal, is open source).

For the phpBB 2 or 3 -> Drupal steps, see Drupal's phpBB2Drupal module, and the handbooksection Migrating from phpBB.

Migration to Drupal via vBulletin

For the Discus -> vBulletin step, there are two modules for DiscusWare in vBulletin's ImpExImport System: the older discus_file, and the more recent and probably more completeDiscusWare4Pro_tabfile. If Discus was using the optional database, you should export its data(users, etc.) to files with Discus Administration (Database Manager) before the conversion. Also,to export the posts to a tabfile (tab-delimited messages), see the Backup Manager. Two relatedthreads are: 1, 2. If the Discus auto-archiving of messages was enabled, see this post for aworkaround.

For the vBulletin -> Drupal step, see the vBulletin to Drupal module, and the handbook pageMigrating from vBulletin.

Features and performance

Page 160: Drupal - Installation Guide

For a Drupal forum with features similar to those of well-known forum systems such as phpBBand vBulletin, see the Advanced Forum module.

For good speed and performance similar to those of Discus' static html files, see Drupal's Booststatic cache for anonymous users, and other performance modules.

Migrating from Dotclear 2This is a copy-and-paste from Dotclear 2 to Drupal 5 on my personal weblog.

As far as I know, this is the very first article on how to move from Dotclear 2 to Drupal. I wrotethe first Dotclear vs Wordpress article some months ago, now this is time for the first Dotclear 2to Drupal one (there is already a Dotclear 1 to Drupal converter).

I’ll try to stay concise. For this reason, I won’t explain everything—just tell me if you’d likesomething to be explained.

Good to know before

First, this is a two-step migration:

1. Dotclear ! WordPress2. WordPress ! Drupal

Second, you must install WordPress on the same server as Drupal. There is no such limitationwith Dotclear, since we will work with a flat export file. This is because the WordPress to Drupalconverter only allows direct access.

Third, the whole operation may take more than three hours. Oh, and at least for me, tags have notsurvived the migration from Dotclear to WordPress (I’m not sure they would survive fromWordPress to Drupal neither)

What you need to download

Dotclear 2 beta7 | WordPress 2.2 | Drupal 5.1dc2wp | wp2drupal5Simple Tagging plugin

Dotclear to WordPress

1. [Dotclear] Start with Dotclear 2 beta6. That may work with other versions, but better safethan sorry.

2. [WordPress] Install WordPress 2.2. That may work with other versions, but better safe thansorry.

3. [WordPress] Extract dc2wp. Inside it, pick up flatimport.php, that you will put at /wp-admin/import and throw the rest away.

4. [WordPress] If you used tags with Dotclear:1. install the Simple Tagging plugin at /wp-content/plugins. Don’t forget to activate it

(in the WordPress administrative panel, at Plugins).2. put all the files in the wordpress 2.1 template files for default theme (kubrick) sub-

directory in wp-content/themes/default. Three files have to be overwritten. If youdon’t want to lose them, just rename there before replacement.

WordPress 2.3 won’t require these steps, since tags will come bundled with it.

5. [Dotclear] Close comments and trackbacks. This is in order to ensure than no new data willenter your blog while you’re moving it.

6. [Dotclear] Export the whole blog or whole content (I suggest the latter, but you may havereasons—like being hosted on Gandiblog—to choose the former. I never tried exportingonly one blog, notify me of any problem with this). I will henceforth consider you exportedthe whole content. You will get a blog-backup.txt file.

7. [WordPress] Upload (FTP) this file to /wp-content/uploads. This folder must havepermission 777 (all permissions)

8. [WordPress] /Manage/Import. Choose Dotclear flat import. Press the Import button.Depending on the size of your blog, it may take a lot of time. If it timeouts, press the Updatebutton once you’re back at the import plugin’s homepage.

That shall be done. Shall be.

Just in case it doesn’t work for you: more information in English and even more in French.

WordPress to Drupal

1. [Drupal] Install Drupal 5.1. At the time of writing, Drupal 6 is not code-freezed yet. Tellme how it behaves.

2. [Drupal] Install wp2drupal. Give permissions 777 on the folder. Remove the extra linesafter the final ?&gt; in wp2drupal/migrate.php

3. [Drupal] Copy wp-config.php from your WordPress install to /modules/wp2drupal. This isa convenience: That will save you entering the configuration data for WordPress.

4. [Drupal] Now, this is really experimental. It seems one file needs to be patched. Here is thepatch (and the discussion. I patched the file manually, but if you have some diff tools, youcould do it automatically. Follow the instructions on the /admin/wp2drupal/. You might

Page 161: Drupal - Installation Guide

experience a timeout. Just reload, it should restart from where it stopped. Continue followingthe instructions.

Wouah! This is done! You migrated from Dotclear to Drupal! !estitam!

Check it out! (temporary location, I’m pretty sure a lot of thing are not there, starting with tags)

Feedbacks greatly appreciated.

What doesn’t work

tags (well, not sure: they’re are in the topics. They have been merged with the categories,which is not that great)thin unbreakable space (required for French typography)permalinks of course (mine are based on ID)a lot of function have disappeared (number of posts and comments, programmingpublication…)certainly much more

Migrating from GeeklogThe partial migration of stories from Geeklog into story-nodes Drupal is a mapping of the*_stories table into the nodes table; a quick way to do the transform is to dump the stories outinto a format suitable for load data infile:

select 'story' as type, title, unix_timestamp(date) as created, '' as users, introtext as teaser, bodytext as body, unix_timestamp(date) as changed, '' as revisions from tc_stories into outfile '/tmp/stories.dump';

this creates the load file; after you've loaded the database script from the Drupal distribution, thisdata can be inserted into the database with load data infile '/tmp/stories.dump' into table node (type,title,created,users,teaser,body,changed,revisions);

This is not a perfect transformation, but it's a start. Geeklog subjects are lost: To preservecategories, you would need to pre-load the topics in Drupal, then create a script that would insertitems from *_stories as mapped in the above example, but then to fetch the nid node id numberfrom the newly inserted record and do a search on the term_data to get the tid number, theninsert the pair into the term_node table.

Since the terms of our new site were only superficially similar to the categories we'd used inGeeklog, we chose instead to fix up the categories later by doing keyword searches on stories toget a list of nid and then pairing those to the new topics by hand using SQL via mysql

Bug: After inserting stories using the above method, the stories will be in the archives, but will notappear on the main page (use update node set promot = 1 to fix this for all or selected items).A more serious bug is that the nodes do not appear in search results -- I don't know that muchabout the inner workings of Drupal, but I expect someone will post a comment explaining how tofix this.

Migrating from Geeklog 1.4.1 to Durpal 5.xHow to migrate stories:

1. Backup Geeklog and Drupal databases.2. Run the following query in the "node" table of your Drupal db:SELECT * FROM `node` WHERE 13. Look at the resulting table to find the next available "nid"/"vid" number. If you want, you cansave the resulting data for later reference.4. Run this query in the Geeklog db:

SELECT'' as nid,'' as vid,'story' as type,title,'1' as uid,'1' as status,unix_timestamp(date),unix_timestamp(date),'0' as comment,frontpage,'0' as moderate,featuredfrom gl_stories

This query assigns all of the user IDs to your primary Drupal account. To get the correct user ID,run the query with uid instead of '1' as uid. You will need to ensure the users map correctly

Page 162: Drupal - Installation Guide

from Geeklog to Drupal, otherwise this will cause problems in your Drupal install.This also disables comments on the stories. To pull the actual comment code information, usecommentcode instead of '0' as comment. You will need to change all instances of -1 for thisfield to 0.This query assumes all stories in your db have been approved.5. Export as SQL and save it as a text file (suggested name: node.txt or node.sql).6. Delete everything up to the first INSERT INTO...7. ReplaceINSERT INTO `gl_stories`

withINSERT INTO `node`

8. Run this query in the Geeklog db:SELECT'' as nid,'' as vid,'1' as uid,title,bodytext,introtext,'' as log,unix_timestamp(date),'1' as formatfrom gl_stories

This query assigns all of the user IDs to your primary Drupal account. To get the correct user ID,run the query with uid instead of '1' as uid. You will need to ensure the users map correctlyfrom Geeklog to Drupal, otherwise this will cause problems in your Drupal install.Note that this query will be mapping the intro text as the trimmed version of your articles andbody text as the full version. For my own migration, I had to move the text in the body into theintro text and map it to both the trimmed and full version.9. Export as SQL and save it as a text file (suggested name: node_revisions.txt ornode_revisions.sql).10. Delete everything up to the first INSERT INTO...11. ReplaceINSERT INTO `gl_stories`

withINSERT INTO `node_revisions`

12. Run this query in the Geeklog db:SELECT'' as nid,tidfrom gl_stories

13. Export as SQL and save it as a text file (suggested name: term_node.txt or term_node.sql).14. Delete everything up to the first INSERT INTO...15. ReplaceINSERT INTO `gl_stories`

withINSERT INTO `term_node`

16. For each of the three files, you will need to manually insert the "nid" and "vid" values, startingwith the next available number you determined from step 3. The "nid" and "vid" values should bethe same for each line, but different between the lines. For example, if the next available "nid"value is 10, the "nid" and "vid" for the first line in all three files should be "10"; the second line inall three files should have "11" as the "nid" and "vid".Those of you with hundreds of stories will want to find some way to convert the data to aspreadsheet and assign the numbers through it. Be careful to not take a shortcut and export thetables as a spreadsheet---the data will not be converted into the proper SQL syntax to be importedlater.17. In your term_node data, replace the Geeklog "tid" values with the numerical equivalent fromyour Drupal db. If you're not sure what those values are, run the following query in your Drupaldb and match the numbers with what you got in step 3:SELECT * FROM `term_node` WHERE 118. Go to phpMyAdmin for your Drupal database and import your three files.19. Check your site to ensure everything worked.20. If there are links in your stories, you will need to update these manually after importing them.

Migrating from Invision Power BoardThis is a 'How To' guide on importing users from an existing Invision Power Board database toyour Drupal database. The following steps presume you are doing this through phpMyAdmin,though it may work with other methods.

Currently, the members will have to request new passwords, as the Invision passwords are hashedwith a salt (more info here). Boris Mann and myself will be working on carrying the correctpasswords over too, and I will update this once the work is finished.

Step One: Export Invision TablesLog in to your phpMyAdmin where your Invision database resides.

Page 163: Drupal - Installation Guide

In most cases just visit "example.com/cpanel", click 'MySQL' databases, and then the'phpMyAdmin' link.

Export 'ibf_members' and 'ibf_members_converge' tables (one at a time).To export, select your Invision database, then click the name of the table on the left. Up top,click the 'Export' tab, check the 'save as file' checkbox, and click "Go."

Step Two: Import Invision Tables into Drupal DatabaseSelect your Invision Database, and Import each table seperately.

Once you are in the Drupal database, click the 'SQL' tab up top, click 'Browse', and thenclick the bottom-most "Go" button. Do this for each Invision table that you previouslyexported (two total).

Step Three: Moving the Data You Need To DrupalRun SQL statements to import the data.

While in your Drupal database, click on the 'SQL' tab once again. Enter the following code,and click "Go" after each one:

INSERT INTO users (uid, name, mail, created) SELECT id, name, email, joined FROMibf_members;

UPDATE `users` SET `status` = 1 WHERE `status` = 0;

UPDATE `users_roles` SET `rid` = 1 WHERE `rid` = 0;

Now you need to update your sequences table so that new users' UID will be higherthan the last UID of the new users you just imported. To do this, follow these steps:1)Select your 'users' table by click it in the left sidebar.

2)Click the 'Browse' tab up top.3)Click the 'UID' link in your database twice to sort that columb by decending order. Writedown the highest number.4)Select your 'sequences' table.5)Click 'Browse'.6)Click the little pencil icon next to 'users_uid' to edit it.7)Update the number (bottom right text box in the "ID" row) to the number you wrote down.Click 'Go'.

FinishedYour users, their email, and joined date have been successfully imported, and your Drupaldatabase has been updated. The users will now have to request a new password. Drupal will askthem for their username and email (the ones they entered in Invision), and it will send them a newpassword that they can use to login. They can then change that password.

As I stated earlier, we are working on converting the passwords as well so that will not benecessary, and once that is done, this will be updated.

Take care and have fun!

Migrating from Joomla/MamboThis guideline focuses on migration from Joomla! 1.0.x to Drupal 4.7.x/5.x. Before you domigration you must understand some differences between both to make sure your migration to besuccessful:

Joomla! vs Drupal1. Joomla only supports one Section and one Category for each content, while you can assign

Drupal contents to several Sections/Categories.2. Joomla does not support multi-site setups, so the migration must be put into a certain site if

you already setup a multi-site with Drupal.3. In this guide I assume you have a forum in your Joomla site. Drupal has built-in forum

discussion, so you don't need to install additional modules.4. The term "Blog" in Joomla is not same as blog in Internet dictionary. 'Blog' term in Joomla

is actually a teaser view of contents containing: Title, Introduction and a Read More link.So, in short, 'Blog' in Joomla terminology is not 'Weblog'! If one is asking if Joomlasupports a 'Blog' by default, then the answer is yes, but with a different meaning.

5. Comments on contents are not available in Joomla by default, but Drupal supportscomments for all content-types by default.

Joomla vs. Drupal TerminologyThere are some different terms between Joomla and Drupal. Here is a list to give you a quickunderstanding:

1. Joomla "Template" is called "Theme" in Drupal.2. Component = Module.

Page 164: Drupal - Installation Guide

3. Module = Block.4. Mambot/Plugin = Input filter.5. Menu-Horizontal = Primary Links6. Menu-Vertical = Navigation7. Dynamic Content Item = Story8. Static Content = Page9. Back-end = there is no back-end in Drupal, but modules like Administration Menu that

provide a similar interface.10. SEF = Clean URLs (but some docs refer to SEF, too).11. Section = Taxonomy Vocabulary/Term12. Section Title = Taxonomy Term (master)13. Category = Taxonomy Term (child)14. Introtext = Teaser15. Maintext = Body (see explanation below)16. Pathway = Breadcrumb

Other terms are the same, such as: forum discussion, editor, search, region, comment, subject/title,preview, html tag, view, edit, advertising/banner, log in/log out, profile, avatar, access control,logs, cache, site maintenance, RSS feed, parent-child and snippets.

Migrating Joomla Content/ItemsFirst, you must transfer all Joomla-Sections to Drupal-Categories and transfer Joomla-Categoriesto Drupal-Term according to their parent. After that, you can transfer Joomla content/item fromjos_content table. Drupal tables for saving article are drupal.node and drupal.node_revisions!

Migrating Joomla IntrotextIntrotext vs Teaser, this is very important, you must know that Drupal can automatic turn thebeginning of an article into an introtext. The introtext is called a teaser in Drupal. Now, how toconvert Joomla introtext to Drupal?

1. copy the Joomla Introtext to drupal.node_revisions:teaser2. copy the Joomla Introtext+Maintext to drupal.node_revisions:body

You may confuse why step #2 including the Introtext again? Because in Drupal, there is apossibility to set Teaser different from the First Paragraph of a body. In other words, the FirstParagraph of Drupal is not always become a Teaser!

If you want to edit migrated contents later on in Drupal, you should actually copy

Introtext + "<!--break-->" + Maintext

in step #2.

Migrating Joomla ForumI assume you use Joomlaboard forum for Joomla. In Drupal, forum is built-in, then you only needenable it on administer-module then show it on certain front page section using administer-blocks. You must transfer Parent-Forum Category of Joomlaboard to Drupal-Forum Container andChild-Forum Category to Drupal-Forum Category. Again, I am using SQLyog to transfer theentire forum contents, SQLyog is very easy because its GUI.

EditorDrupal by default has no WYSIWYG Editor, meaning you must type in HTML tags manually toformat your article. Joomla has built-in TinyMCE editor. In Drupal, you can use users contributedmodules such as TinyMCE Editor or FCKeditor.

TipsUsually better to install Drupal in a folder such as domainname.com/drupal, so you can still accessboth website during this migrating. You better not convert the Joomla templates to Drupal Theme,but edit any existing Drupal theme to meet your requirement because Drupal supports themeengine (PHPtemplate) and separate templates such as comment.tpl.php, mean you can apply anyformat to the comment.

Helpful ModulesYou may also want to check out the following modules:User Import - for usersNode Import - for content

Database Queries and Procedure forMigrating to DrupalHere is a database based procedure for porting Joomla to Drupal. It's got plusses (you can do

Page 165: Drupal - Installation Guide

tricks like concatenate fields, or change the case, do joins, or use other database functions) andminuses (perhaps not as simple as using a module, export and import).

I used Access, and created a new database, and an ODBC connection to my Drupal (test)database.Then Import-Link Tables, and select all the tables. Answer some questions about which are thekey fields of certain tables, and you will be able to browse your Drupal database.

First, create a vocabulary, i.e. vid=1

Here are some of the queries I used:

The bizarre where clauses are just because the Joomla data isperverted...some of the categories reference sections (which should benumeric section IDs) like "com_weblinks", so ignore those....

Import Taxonomies-Insert the Sections into Term_data:

INSERT INTO term_data ( vid, name, description )SELECT 1 AS Expr1, mos_sections.name, mos_sections.descriptionFROM mos_sections;

(the vid is a constant, 1)

Then insert the Sections into the Hierarchy, with Parent 0:Sorry, overwrote it by accident....

Insert the Categories into the Term_data table:

INSERT INTO term_data ( vid, name, description )SELECT 1 AS Expr1, mos_categories.name, mos_categories.descriptionFROM mos_categoriesWHERE (((mos_categories.section)<"a" And(mos_categories.section)<>"12" And (mos_categories.section)<>"7"));

For terms without parent, we must linked with themself

INSERT INTO term_hierarchy( tid, parent )SELECT td.tid,0FROM term_data tdWHERE td.tid NOT IN (SELECT th.tid FROM term_hierarchy th)

If you use pathauto module remember run Bulk generate aliases for terms that are not aliased

Again, vid is a constant, 1

-Insert the Categories into the Hierarchy

INSERT INTO term_hierarchy ( tid, parent )SELECT term_data.tid, mos_categories.sectionFROM term_data INNER JOIN mos_categories ON term_data.name =mos_categories.nameWHERE (((term_data.tid)>7) AND ((mos_categories.section)<"a" And(mos_categories.section)<>"12" And (mos_categories.section)<>"7"));

This gets the termid and the parent termid, which is what goes into the hierarchy.

If your Sections have moved around, you may have some Categoriesassociated with the wrong section. It may be easier to just re-number(update the ID of the Section) rather than update all of thecategories, which will likely be more numerous. Since the IDs are ina unique key, say you are swapping 1 and 3, make 1 like 999 orsomehthing, then switch the other one 3, to 1, then put 999 to 3, andwhen you refresh your Categories, things should line up better.

Import NodesAppending the Content to nodes_revisions per the node 80195, is really easy, once you realize thatvid in this case is not the vocabularyid, but is a revisionid that must be unique across the entiredatabase.

That query looks like this:

INSERT INTO node_revisions ( vid, uid, title, teaser, body ,log)SELECT jos_content.id, 2 AS Expr2, jos_content.title, jos_content.introtext,concat(jos_content.introtext,"<br>",jos_content.fulltext) AS Expr3, "Importedfrom joomla"FROM joomla.jos_content;

Userid will be 2 to which you want to assign the content.

But nid in nodes_revisions is not autoincrement, which seems odd.

You can do essentially the same insert on nodes:

INSERT INTO node ( vid, type, title, uid )

Page 166: Drupal - Installation Guide

SELECT mos_content.id, "story" AS Expr4, mos_content.title, 2 AS Expr2FROM mos_content;

This importation don't handle i18n support, if you need set the language field with 'en' i.e:

INSERT INTO node ( vid, type, title, uid,language )SELECT mos_content.id, "story" AS Expr4, mos_content.title, 2 AS Expr2, 'en'FROM mos_content;

Then you just have to get the nodeid (nid) updated in node_revisions, which is easier, because weused the same id field from mos_content as the vid in both tables, so we use that to join the tables,and updated the node_revisions.nid with the node.nid:

UPDATE node INNER JOIN node_revisions ON node.vid = node_revisions.vid SETnode_revisions.nid = [node].[nid];

There may be an issue with the vids being the same...Pro Drupal Development, p. 84, says vid hasto be unique across nodes AND node revisions, so we may have to add 1000 or something tomake them unique....haven't gotten there yet.

Import Joomla/Mambo Modules as Nodes

Sometimes Joomla used modules to represent content, for this reason depends of Joomla/Mamboimplementation could be a good idea import modules with content and published.

INSERT INTO drupal.node_revisions(vid,uid,title,body,log)SELECT id+57,2,title,content,'Imported from joomla' FROM joomla.jos_moduleswhere jos_modules.published = 1 and jos_modules.content != ''

INSERT INTO drupal.node ( vid, type, title, uid )SELECT id+57,"story",title,2 FROM joomla.jos_moduleswhere jos_modules.published = 1 and jos_modules.content != ''

Import UsersINSERT INTO users(name,pass,mail,status)SELECT ju.name,ju.email,ju.password,1FROM joomla.jos_users ju

All users well be active, change the constant 1 to 0 if you want import as disabled users

Migrating from LiveJournalIn some respects, there is no need to migrate from Livejournal, as such. It's great.. one thing I can'toffer here is the 'friends' feature, and all the othe great stuff the LJ offers.

This posting is for people who wish to either include their LJ data in a Drupal site or to leave LJbehind and import their data wholesale into a Drupal Blog.

When I started playing with Drupal I tried to import my LiveJournal in several ways... You maybe happy with one of these. These are listed in order of best integration with Drupal.

If anyone see a mechanism for making their export system any better 1) email me. 2) emaillivejournal..!!

Import your LJ through an IFRAME held in abook page or similarNot ideal to be honest, although I did use this approach for a week or two. You will rely upon theLJ commenting feature, and you will have to create a suitable LJ style to make it work.

Interestingly, you may not be aware that you can, in fact, have as many styles are you wish. 'They'will not tell you this anywhere... but you can.

You could have one style for people who view your journal directly at livejournal.com, andanother for your importing IFRAME.

You simply reference them (in an IFRAME) like this:

<!-- Setup journal --><iframe src="http://www.livejournal.com/customview.cgi?user=rowanboy&styleid=186838" width="100%" height="300" frameborder="0"scrolling="auto" allowtransparency="false"><!-- Alternate content for non-supporting browsers --> Your browser won't work here. You'll need IE5.5+</iframe>

When you define your custom style at LJ, you'll be told the style id to use. Note that this will onlywork for paid users of LJ.

Page 167: Drupal - Installation Guide

Using provided Import ModuleYou *could* use the 'import' module to connect to the RSS feed provided by LiveJournal for everyPAID user. It's pretty good that LJ even bother with this, so I guess we have to be grateful..

A standard RSS feed is provided at a url similar to:http://www.livejournal.com/users/rowanboy/rss.xml

This will work if imported into the newsfeeds section of your Drupal site....but the actual contentwill still live at LiveJournal. I guess the advantage here is that you can still use LJ and yet (fairly)dynamically pull content into Drupal.

Migrating from Movable TypeThe Import TypePad module should be able to handle the Movable Type export format.

Here's a few scripts for updating Movable Type to a 4.7.x or 5.x Drupal install. These scripts willlet you migrate your Movable Type blog to Drupal with comments and all settings intact. Feel freeto tweak the code as you like.

NOTE: To use this you will need to be running PHP 5. The simplexml commands are notsupported on PHP 4.

Overview of the steps involved:

1. Install and "rebuild" MT Theme2. Create a drupal page (ie: hit the path 'node/add/page') with supplied PHP snippet3. Patch comment.module to allow comments to get proper dates (you can remove this patch

after you finish migrating)4. Done!

First, follow the section of this guide titled "Extract Movable Type content as xml" except use theMT template below:

<?xml version="1.0" encoding="UTF-8"?><items> <MTEntries lastn="1000" sort_order="ascend"> <item about="<$MTEntryLink$>"> <title><$MTEntryTitle encode_xml="1"$></title> <description><$MTEntryBody encode_xml="1"$></description> <link><$MTEntryLink$></link> <subject><$MTEntryCategory encode_xml="1"$></subject> <creator><$MTEntryAuthor encode_xml="1"$></creator> <date><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></date>

<comments> <MTComments lastn="1000" sort_order="ascend"> <comment> <author><$MTCommentAuthor default="Anonymous" encode_xml="1"$></author> <email><$MTCommentEmail encode_xml="1"$></email> <homepage><$MTCommentURL encode_xml="1"$></homepage> <date><$MTCommentDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></date> <body><$MTCommentBody convert_breaks="0" remove_html="1"encode_xml="1"$></body> <title><$MTCommentTitle encode_xml="1"$></title> </comment> </MTComments> </comments>

</item> </MTEntries></items>

Once your finished with that, rebuild the template, and download it (ie: enter something likehttp://yourblog.com/drupal.rdf in your web-browser and do a "Save As").

Put the drupal.rdf file somewhere sensible. My code assumes you're putting it in the scripts folderof your Drupal install. If you put it somewhere else then be sure to edit the PHP code.

Now, we're ready to import it into Drupal. To do this, create a new node of type 'page' on your siteand give it the input format type of PHP (you might want to unpublish it as well so people don'tstumble upon it).

The content of this new page should be the following code:

<?php /** * This snippet will scrape the 'drupal.rdf' MT XML export file and create * nodes and comments from the content. * * @author James Andres * @version 2007-03-17 */ if ($_GET['start'] == 1) { // ****** Change the 'scripts/drupal.rdf' line to the location of your MTXML export ****** $xml = simplexml_load_file('scripts/drupal.rdf'); global $user;

Page 168: Drupal - Installation Guide

foreach ($xml->item as $item) { $comment_count = count($item->comments->comment);

echo "Saving <strong>$item->title</strong> with $comment_countcomments.<br />\n";

// Create a node $node = (object) array(); node_object_prepare($node); $node->type = 'blog'; $node->status = 1; $node->promote = 1; $node->uid = $user->uid; $node->format = 3; // Full HTML $node->created = strtotime($item->date); $node->updated = $node->created; $node->path = str_replace('http://www.davidrdgratton.com/', '', $item->link); if ($item->subject) { // Save the tags $term = taxonomy_get_term_by_name($item->subject); $term = current($term); $node->taxonomy[] = $term->tid; $node->taxonomy_term = (string) $item->subject; }

$node->title = $item->title; $node->body = $item->description; $node->description = $item->description;

node_save($node);

foreach ($item->comments->comment as $comment) { $edit = array(); $edit['pid'] = 0; $edit['nid'] = $node->nid; $edit['uid'] = ( strtolower($comment->author) == strtolower($user->name) ? $user->uid : 0 ); $edit['timestamp'] = strtotime($comment->date); $edit['name'] = $comment->author; $edit['subject'] = $comment->title; $edit['comment'] = $comment->body; $edit['format'] = 2; $edit['mail'] = $comment->email; $edit['homepage'] = $comment->homepage; comment_save($edit); } } } else { echo l('start', $_GET['q'], array(), 'start=1'); }?>

Hit save. BUT before you hit the 'start' link you might want to patch the comment.module.

How to patch the comment module:

If you're on Drupal 4.7 or 5.0, find your comment.module and look for the line$edit['timestamp'] = time();. Replace that line with the following code ...

if (!$edit['timestamp']) { $edit['timestamp'] = time(); }

Last but not least, log in as the user you want to be the "author" of all the blog posts you migrate(ie: In my case that user was 'James'). If that author matches the author of your MT blog the scriptwill detect that and act accordingly.

Finally, you should be able to hit the 'start' link on the page you created with all that PHP code init and the migration will run.

mt2drupal

[jseng: mt2drupal is another trick you can use to migrate MT to Drupal. It is written in perl as anMT plugin utilizing MT libraries to extract from the database and then feed it into the MySQLdatabase directly. It will import:

all your bloggersall your defined categoriesall your entries including body, excerpt, extended (in 4.4.1 & CVS, it is stored asbodyextended and in D4B formatting rules are also preserved)all your comments (with anonymous support, in CVS and D4B)all incoming trackbacks (stored as comments)all your outgoing trackbacks (D4B only)all your trackbacks trackers (D4B only)keep all your old archives as url_alias, including your RSS feeds so permalink is preserved

Extract Movable Type content as xml

Page 169: Drupal - Installation Guide

1. Install the following as a new Movable Type template called Drupal Convert, with drupal.rdfspecified as the Output File.

<?xml version="1.0" encoding="iso-8859-1"?><items><MTEntries lastn="1000" sort_order="ascend"><item about="<$MTEntryLink$>"><title><$MTEntryTitle encode_xml="1"$></title><description><$MTEntryBody encode_xml="1"$></description><link><$MTEntryLink$></link><subject><$MTEntryCategory encode_xml="1"$></subject><creator><$MTEntryAuthor encode_xml="1"$></creator><date><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></date></item></MTEntries></items>

2. Save the template, and rebuild. Movable Type will offer to rebuild drupal.rdf for you. The filewill contain the last 1000 Movable Type entries, encoded as XML, sorted in ascending date order.This will be helpful if you are turning them into drupal blog entries, because drupal displays blogentries in reverse node id (database insert) order.

Moving your MT styles and templatesOf course you want to make your new Drupal site look and feel as much as possible like your oldMT site. This article might help on the way in doing so. Luckily this is not too hard, so non-PHPprogrammers can re -create the old styles, so that they can be used on the new drupal site. To dothis, you do not need to know PHP, but you do need to know at least basic CSS coding.

Since I do not know the way MT templates are built and created, I will stick only to the Drupalpart of the story. That's not a too big problem, because, as long as you understand the way drupaluses its themes, you will be able to modify little things so that they /look/ like the MT styles, butdo not have to be the same. After all, this is not an article about stealing, its about how to portyour own MT creations to drupal. So bear in mind: do not steal!

Drupal knows many methods for theming. It depends on your own preferences what themingmethod you choose. This, however is far out of the scope of this article, and I stick to the easiestmethod, in my opinion, PHP template.

The PHP template can be installed as any other theme, read the shipped install text on how to dothis. There are numerous articles on drupal.org that explain in detail how to configure PHPtemplate, go look for them yourself and use them to configure the template. This document is nota tutorial on how to use PHP template, after all.

Creating a new template under PHPtemplate is as easy as copy-pasting one of the folders. Renameit to something you like: MyTemplate for example. The best is to copy the MoveableToDrupalfolder and paste it as MyTemplate.

Now some technical blabla on the way PHPtemplate works. Drupal knows themes, just the waymost CMS'es do. The file phptemplate.theme is the actual theme. The big difference is thatPHPtemplate is not just a theme, like chameleon, or blue robot, but acts more like a layer. It allowsyou to create templates in the theme. Get it? No?

Alright: Drupal has themes. You can install a theme and the look and feel of your site haschanged. But PHPtemplate is not really one of them. It uses some fancy coding to create anothertemplating system. So it is a template in a theme. All the folders inside the PHPtemplate folder aretemplates.

Got it now?

So inside those sub-folders (for example the folder MyTemplate) there are some files. Some ofthem are styles, some images and a few are .php files. They are the actual templates. If you knowenough PHP just open them and move some of the code around.

But now over to the real stuff: using the style sheet(s) to re-create your MT design.

As said above: you will need CSS skills to do this, if you don't have those, well, post a message ondrupal.org or on the support list and tell you've got some money or something else (stories,tutorials, modules, clients with loads of money) lying around you wish to get rid of. And ask ifanybody is interested in receiving that money (or that something else) for the simple task ofrewriting the MT CSS.

Back to business: drupal can have virtually any HTML DOM, but in general it is kind of similar tothat of MT. In PHP template , we have sidebars and a main content. Drupal uses the id .nodeinstead of .blog and it has some more differences, of course.

Some basic changes you should make are:

MT selector Drupal PHP template selector#banner .header

.side .sidebar-left or .sidebar-right

#content .main-content

Page 170: Drupal - Installation Guide

H3.title .node H2 (A)

.blog .node

.blogbody (P) .node .content

These are some basic changes , that should get you on the road. For all other stiles and selectors,you should heave a look at the style sheet in MoveableToDrupal

Parse xml into sql insert statementsThis code was originally published by Senor Dude. But because he didn't publish it in the DrupalHandbook, and because I added code to improve the generation of the teaser (the original codejust put the whole body into the teaser), I'm posting it here.

You'll need to have perl of a high enough version to handle the iso-8859-1 encoding (I used 5.8;5.6 is too old). You'll need to install XML::SAX (easy enough with cpan). This may takes quite awhile to run, depending upon what parser it locates.

use XML::SAX::Base;use XML::SAX::ParserFactory;

package Node;

my $teaser_length = 600;

package ConversionFilter;

@ISA = qw(XML::SAX::Base);

my $type = 'blog';

sub characters { my ($self,$data) = @_; $self->{_characters} .= $data->{Data};}

sub start_element { my ($self, $element) = @_; my $tagname = $element->{LocalName}; my $handle = "start_$tagname"; if ($self->can($handle)) { $self->$handle($element); } $self->SUPER::start_element($element);}

sub end_element { my ($self, $element) = @_; my $tagname = $element->{LocalName}; my $handle = "end_$tagname"; if ($self->can($handle)) { $self->$handle($element); } $self->SUPER::end_element();}

sub start_item { my $self = shift; $self->{_current_item} = new Node(); }

sub end_item { my $self = shift; print $self->{_current_item}->insert_statement();}

sub start_description { my $self = shift; $self->clear_characters();}

sub end_description { my $self = shift; $self->{_current_item}->{description} = $self->get_characters();}

sub start_title { my $self = shift; $self->clear_characters();}

sub end_title { my $self = shift; $self->{_current_item}->{title} = $self->get_characters();}

sub start_date { my $self = shift; $self->clear_characters();}

sub end_date { my $self = shift;

Page 171: Drupal - Installation Guide

$self->{_current_item}->{created} = $self->get_characters();}

sub clear_characters { my $self = shift; $self->{_characters} = "";}

sub get_characters { my $self = shift; return $self->{_characters};}

package Node;

sub new { my $class = shift; return bless {}, $class;}

# Borrowed from node.module

sub node_teaser { my $body = shift; my $size = $teaser_length;

if ($size == 0) { return $body; }

if (length($body) < $size) { return $body; }

if (my $length = rindex($body, "<br/>", $size)) { return substr($body, 0, $length); }

if (my $length = rindex($body, "<br>", $size)) { return substr($body, 0, $length); }

if (my $length = rindex($body, "</p>", $size)) { return substr($body, 0, $length); }

if (my $length = rindex($body, "\n", $size)) { return substr($body, 0, $length); }

if (my $length = rindex($body, ". ", $size)) { return substr($body, 0, $length + 1); }

if (my $length = rindex($body, "! ", $size)) { return substr($body, 0, $length + 1); }

if (my $length = rindex($body, "? ", $size)) { return substr($body, 0, $length + 1); }

return substr($body, 0, $size);}

sub insert_statement { my $self = shift; my $body = mysql_escape($self->{description}); my $teaser = mysql_escape( node_teaser( $self->{description} ) ); return "INSERT INTO node ". "(type,title,uid,status,comment, promote, users, attributes,revisions, created,teaser,body)". " VALUES ('$type','". mysql_escape($self->{title})."',1,1,2,1,'','','',". "UNIX_TIMESTAMP('".to_mysql_date($self->{created})."'),'$teaser','$body');\n";}

sub mysql_escape { my $string = shift; $string =~ s/\n/\\n/mg; $string =~ s/(\'|\")/\\$1/g; #" quote to help syntax coloring return $string;}

sub to_mysql_date { my $string = shift; $string =~ s/T/ /; $string =~ s/\+00:00$//; return $string;}

package main;

my $filename = $ARGV[0];

my $handler = new ConversionFilter();

Page 172: Drupal - Installation Guide

my $parser = new XML::SAX::ParserFactory->parser(Handler => $handler);

$parser->parse_uri($filename);

Template for MT entry and comment exportand Drupal importNote: this script was originally written to migrate to Drupal 4.4. It is left for reference.

To do:

Automatically create accountsExport MT categories and import to Drupal taxonomy

Limitations:

All comments are from the Anonymous userAll comments are unthreadedThe comment subject is made from the first five words of the commentThe import defaults to using "uid" 1, i.e. the site admin (change the $uid variable toimport to another user)All posts are promoted to the front pageAll comments have a published statusMT categories (Drupal taxonomy terms) are not exported

Instructions:

1. Create a new Movable Type Index template called "Drupal Import" with "import.php"specified as the Output File

2. Cut and paste the following into the "Template body" textarea3. Set the variables below the "//set variable defaults" comment to the correct values4. Save and rebuild the template5. Load "import.php" in your web browser

If the import is successful, the output will be a single sentence listing the number of entriesand comments imported.

<html><head><title>Export</title></head><body>

<?php//set variable defaults$hostname = "";$username = "";$password = "";$db = "";$uid = 1;

// get next node number from sequences table$link = mysql_connect($hostname,$username,$password) or die("Could notconnect to server");mysql_select_db($db) or die("Could not select database ".$db);$result = mysql_query("SELECT nid FROM node");$node_rows = mysql_num_rows($result)+1;

<MTEntries lastn="1000" sort_order="ascend">

$node_title = <<<NT<$MTEntryTitle$>NT;$node_title = mysql_escape_string($node_title);

$node_teaser = <<<NE<$MTEntryBody$>NE;$node_teaser = mysql_escape_string($node_teaser);

$node_body = <<<NB<$MTEntryBody$><$MTEntryMore$>NB;$node_body = mysql_escape_string($node_body);

//get post status$status = strtolower("<$MTEntryStatus$>");

if ($status == "publish"){ $node_status = 1; }else{ $node_status = 0;}

$node_insert_query = "INSERT INTO node (type, title, uid, status, comment,promote, users, revisions, created, changed, teaser, body) VALUES ('blog','$node_title', $uid, $node_status, 2, 1, '', '',

Page 173: Drupal - Installation Guide

UNIX_TIMESTAMP('<$MTEntryDate format="%Y-%m-%d%H:%M:%S"$><$MTBlogTimezone$>'), UNIX_TIMESTAMP('<$MTEntryDate format="%Y-%m-%d %H:%M:%S"$><$MTBlogTimezone$>'), '$node_teaser', '$node_body');";

<MTComments sort_order="ascend">$comment_text = <<<CT<$MTCommentBody$>CT;$comment_text = mysql_escape_string($comment_text); // grab the first five words of the comment as the comment subject$subject = "";$arr = explode(" ",$comment_text); for($i=0; $i<5; $i++) { $subject .= $arr[$i]." "; }

$comments_insert_query = "INSERT INTO comments (cid, pid, nid, uid,subject, comment, hostname, timestamp, score, status, thread, users) VALUES(NULL, 0, $node_rows, 0, '$subject', '$comment_text', '<$MTCommentIP$>',UNIX_TIMESTAMP('<$MTCommentDate format="%Y-%m-%d%H:%M:%S"$><$MTBlogTimezone$>'), 0, 0, '1/', 'a:1:{i:0;i:0;}');";

mysql_query($comments_insert_query);

if (mysql_errno($link)){ echo mysql_errno($link) . ": " . mysql_error($link) . "\n";}

$comments_rows++;</MTComments>

// increment node_rows counter, so we have the correct nid for the commentinsert next time$node_rows++;

mysql_query($node_insert_query);

if (mysql_errno($link)){ echo mysql_errno($link) . ": " . mysql_error($link) . "\n";}

</MTEntries>

// echo the number of rows added to the nodes tableecho($node_rows." blog entries and ");mysql_query("INSERT into sequences (name,id) VALUES('node_nid',$node_rows+1)");if (mysql_errno($link)){ echo mysql_errno($link) . ": " . mysql_error($link) . "\n";}

// echo the number of rows added to the comments tableecho($comments_rows." comments inserted.");mysql_query("INSERT into sequences (name,id) VALUES('comments_cid',$comments_rows+1)");if (mysql_errno($link)){ echo mysql_errno($link) . ": " . mysql_error($link) . "\n";}

mysql_close($link);?>

</body></html>

Insert content into Drupal nodesThe final trick is that the insert statements count on mysql's auto_increment feature, but drupalactually sets node ids explicitly. So after you run the generated mysql, you'll need to find themaximum node id that mysql generated for you, and bump the next node id that drupal intends toassign to be larger than that.

% /bin/perl ./convert.pl drupal.rdf >mt.sql% mysql -ppassword drupal <mt.sql% mysql -ppassword drupalmysql> select max(nid) from node;+----------+| max(nid) |+----------+| 83 |+----------+1 row in set (0.25 sec)

mysql> select * from sequences;+----------------+----+| name | id |+----------------+----+| users_uid | 8 || vocabulary_vid | 2 || term_data_tid | 8 || node_nid | 6 || comments_cid | 3 |+----------------+----+

Page 174: Drupal - Installation Guide

+----------------+----+5 rows in set (0.00 sec)

mysql> update sequences set node_nid = 84;

Setting terms for inserted nodesyou probably want to assign terms to the inserted nodes. You can do this by hand in mysql. Thefollowing attaches the term with term id 1 to all the nodes (whose node ids I determined by somecharacteristic of the nodes themselves, using a select statement).

%mysql -ppassword drupalmysql> insert into term_node select nid, 1 from node where nid >= 6 and nid <=83;

Migrating from PHPNukeThere's a module to migrate from phpnuke to drupal 6 at http://drupal.org/project/phpnuke2drupal

There are also some migration scripts for drupal 5 available here:http://www.quillem.com/nuke2drupal

Related to those scripts there is some extra code with explanation for migrating web links fromphpnuke to drupal in a forum post.

Migrating themesJust like PHPNuke themes, Drupal uses PHP-based themes mixed with HTML markup.Both have similar functions for header, footer, box and story (node).

Migrating usersMigrating users:To migrate users from PHP Nuke to Drupal takes two simple MySQL commands. The followingexamples are for going from PHP Nuke 5 to Drupal 3.

First, you need to be sure that the 'name' column in the PHP Nuke user table isn't blank. Forexample, from within MySQL type:update phpnuke.nuke_users set name=uname where name='';Second, copy the valid data from the PHP Nuke user table to the Drupal user table:insert into drupal.users(name,userid,real_email,fake_email,url,bio) selectname,uname,email,femail,url,bio from phpnuke.nuke_users;If you find this intimidating, you can try this script which includes more instructions.

Migrating from PHPweblogWe recently successfully imported thousands of nodes from a phpweblog cms into drupal. Also,the stories were in portugese, encoded in iso-8859-1, so in order to preserve the accents, the dbalso had to be run through 'iconv', a converter utility, in order to switch it to utf-8 (drupal'sstandard encoding.)

Here were our basic steps in case this will help you...

make the backup:

mysqldump -u {db_username} -ppassword {db_name} > weblog.sql

copy the file over to your test site location, and run iconv:

iconv -f iso-8859-1 -t utf8 weblog.sql > weblog_utf8.sql

I added all the old tables right into the drupal tables (although that might not have been the bestmove speed wise, and all the old tables will have to be dropped when you're done). But it lookedlike this:

mysql -u {db_username} -ppassword {db_name} < weblog_utf8.sql

The phpweblog stories are all in the table T_Stories.

drupal phpweblognode story------- ---------nid CAST(REPLACE(Rid,'/','') AS UNSIGNED)type 'story'title Headinguid '2'status '1'created unix_timestamp(Birthstamp)changed unix_timestamp(Birthstamp)comment '2'promote '0'moderate '0'teaser Summary

Page 175: Drupal - Installation Guide

body Contentrevisions ''sticky '0'format '1'

this mapping converts the phpweblog story id (Rid) into an id compatiblewith drupal (nid). For example 05/03/08/179851 --> 50308179851. thisonly works if you make "nid" a bigint and increase the length to atleast 15. the only purpose of doing this instead of letting drupalassign new node ids is that this way we can make it so that the old URLs(which might have tons of links to them) can still be used with a littlemod_rewrite alchemy:

RewriteCond %{QUERY_STRING} ^story=(.*)/(.*)/(.*)/(.*)$RewriteRule ^.*$ /index.php?q=node/%1%2%3%4 [L]

So, in mysql, the copy over looked like this:

INSERT INTO node(nid,type,title,uid,status,created,changed,comment,promote,moderate,teaser,body,revisions,sticky,format)SELECT CAST(REPLACE(Rid,'/','') ASUNSIGNED),'story',Heading,'2','1',unix_timestamp(Birthstamp),unix_timestamp(Birthstamp),'2','0','0',Summary,Content,'','0','1'FROM T_Stories;

Also, in the above code, the stories will all appear as authored by 'uid 2', I created a user named"archiver" (who happened to have a uid of 2.) So, to make all the old posts appear from a differentuser, here is the mysql:

UPDATE node SET uid={whatever number} WHERE uid=2;

And there they all were! If you run cron.php, your site will be re-indexed, and they're allsearchable!

NodeVarchar vs. Int

Looking at the tables, Rid is a varchar, nid is an int. By changing nid over to a varchar, you'll beable to import the table into the node table and then switch the nid back over to a bigint.

Migrating from PhorumIf you are using the Phorum message board system there is now a Phorum Converter module to ahelp migrate to a Drupal based forum site.

For more details see the project page and the README.txt

Migrating from PostNukeI've written a MySQL script to migrate from a PostNuke database to a Drupal one.

Currently it migrates Themes, Users, Stories, Comments, Polls and Poll comments. These were theonly tables which I was interested in. I wrote it to migrate Puntbarra.COM (the Catalan version ofSlashdot) in early September.

It has been a bit complicated given the fact PostNuke database structure is horrible.

Take it from my sandbox.

Configuring mod_rewrite in .htaccess for PNlegacy URLs inI'll be migrating Kairosnews from PostNuke to Drupal CVS this weekend. Since the site hasalmost 2000 stories, I'm concerned about the fact tha any links to them from around the web willgo dead. Some consolation is that the .htaccess rules will take those dead links and refer them tothe home page instead of 404ing them.

Can .htaccess be configured to rewrite the urls? The node ids will be taken from the current storyid's, so that part will not be a problem.

The current PN default story url looks like this:modules.php?op=modload&name=News&file=article&sid=1972&mode=nested&order=0&thold=0

so it seems like it could be rewritten to

node/view/1972

Is this possible? Admittedly, I know very little about mod_rewrite. Any suggestions would behelpful.

Page 176: Drupal - Installation Guide

To Drupal 4.7Here was my move from Postnuke to Drupal 4.7.5:

Actions performed:

1- User Migration - Complete

INSERT INTO awnewso_drupal4.users (uid, name, pass, mail, signature, timezone,mode, sort, threshold, status, init, created, access, data) SELECT pn_uid,pn_uname, pn_pass, pn_email, pn_user_sig, 0, 0, 0, 0, 1, pn_email,pn_user_regdate, UNIX_TIMESTAMP('2007-01-01 01:01:01'), "N;" FROMawnewso_awnewsorg.nuke_users WHERE pn_uid!=1;

________

Created Anonymous user in Post Nuke nuke_users. uid=663ran:

INSERT INTO awnewso_drupal4.users (uid, name, pass, mail, signature, timezone,mode, sort, threshold, status, init, created, access, data) SELECT pn_uid,pn_uname, pn_pass, pn_email, pn_user_sig, 0, 0, 0, 0, 1, pn_email,pn_user_regdate, UNIX_TIMESTAMP('2007-01-01 01:01:01'), "N;" FROMawnewso_awnewsorg.nuke_users WHERE pn_uid=663;

--------

2 - Story Migration - Complete

INSERT INTO awnewso_drupal4.node (nid, vid, type, title, uid, status, created,comment, promote, moderate, changed)SELECT pn_sid,pn_sid,"story",CASE WHEN NOT strcmp(LEFT(pn_title,3),"_TP") THEN substring(pn_title,4) ELSEpn_title END,pn_uid,1,unix_timestamp(pn_time),2,1,0,now()FROM awnewso_awnewsorg.nuke_stories s, awnewso_awnewsorg.nuke_users uWHERE s.pn_informant=u.pn_uname

---

INSERT INTO awnewso_drupal4.node_revisions (nid, vid, uid, title, teaser, body,log)SELECT pn_sid,pn_sid,pn_uid,pn_title,pn_hometext,pn_bodytext,""FROM awnewso_awnewsorg.nuke_stories s, awnewso_awnewsorg.nuke_users uWHERE s.pn_informant=u.pn_uname

___________

3 - Comment Migration - Complete

INSERT INTO awnewso_drupal4.comments ( cid, pid, nid, uid, subject, comment,hostname, timestamp, homepage)SELECT c.pn_tid,c.pn_pid,c.pn_sid,IF(strcmp(c.pn_name,""),u.pn_uid, 0) ,c.pn_subject,c.pn_comment,c.pn_host_name,unix_timestamp(c.pn_date),""FROM awnewso_awnewsorg.nuke_comments c, awnewso_awnewsorg.nuke_users uWHERE c.pn_name=u.pn_uname

___________

4 - Final testing.

SELECT @term_data_tid:=MAX(tid) FROM term_data;SELECT @comments_cid:=MAX(cid) FROM comments;SELECT @node_nid:=MAX(nid) FROM node;SELECT @users_uid:=MAX(uid) FROM users;SELECT @vocabulary_vid:=MAX(vid) FROM node;

DELETE FROM sequences WHERE name="term_data_tid";DELETE FROM sequences WHERE name="comments_cid";DELETE FROM sequences WHERE name="node_nid";DELETE FROM sequences WHERE name="users_uid";DELETE FROM sequences WHERE name="vocabulary_vid";

INSERT INTO sequences (name,id) SELECT "term_data_tid", @term_data_tid;INSERT INTO sequences (name,id) SELECT "comments_cid",@comments_cid;

Page 177: Drupal - Installation Guide

INSERT INTO sequences (name,id) SELECT "node_nid",@node_nid;INSERT INTO sequences (name,id) SELECT "users_uid",@users_uid; INSERT INTO sequences (name,id) SELECT "vocabulary_vid",@vocabulary_vid;

Comment fix:

INSERT INTO awnewso_drupal4.node_comment_statistics(nid,last_comment_timestamp,last_comment_name,last_comment_uid,comment_count)SELECT c.pn_sid,unix_timestamp(c.pn_date),NULL,IF(u.pn_uid=-1,0,u.pn_uid),s.pn_commentsFROM awnewso_awnewsorg.nuke_comments cLEFT JOIN awnewso_awnewsorg.nuke_users u ON c.pn_name=u.pn_unameLEFT JOIN awnewso_awnewsorg.nuke_stories s ON c.pn_sid=s.pn_sidLEFT JOIN awnewso_awnewsorg.nuke_comments d ON c.pn_sid=d.pn_sid ANDunix_timestamp(c.pn_date)<unix_timestamp(d.pn_date)WHERE d.pn_date IS NULL;

ONLY if your user is already in the post-nuke database.Replace references to user who is to become admin with admin. (move referencesof uid to 1)

update node set uid = replace(uid,242,1);update node_revisions set uid = replace(uid,242,1);update comments set uid = replace(uid,242,1);

To Drupal 5I can confirm that the SQL query for 4.7 worked OK for migrating at least the news/story itemsfrom a Postnuke .762 install to Drupal 5.1.

Only one modification was required, and that was the 'changed' column wasn't accepting now() asa value, so I just used unix_timestamp(pn_time) instead.

Note that I mapped all stories to uid 1, as my uid mapping was different from PN to Drupal, and Iset comment to 0. YMMV.

INSERT INTO node (nid, vid, type, title, uid, status, created, comment, promote,moderate, changed)SELECT pn_sid,pn_sid,"story",CASE WHEN NOT strcmp(LEFT(pn_title,3),"_TP") THEN substring(pn_title,4) ELSEpn_title END,1,1,unix_timestamp(pn_time),0,1,0,unix_timestamp(pn_time)FROM nuke_stories;

There's also an additional sequence required, node_revision_vid. If you don't update yoursequences, you won't be able to create new nodes.

SELECT @node_revisions_vid:=MAX(vid) FROM node;DELETE FROM sequences WHERE name="node_revisions_vid";INSERT INTO sequences (name,id) SELECT "node_revisions_vid",@node_revisions_vid;

Postnuke conversion

This can be used to migrate the bodies of stories from a PostNuke 0.764 install to Drupal 5.2.

INSERT INTO node_revisions (nid, vid,uid,title,body,teaser,log,timestamp,format)SELECT (pn_sid + NUMBER), // NUMBER equals equals highest existing nid in tablenode_revisions(pn_sid + NUMBER), // Same."UID", // UID: number of existing drupal userpn_title,pn_bodytext,pn_hometext,"",unix_timestamp(pn_time),1FROM _stories;

Set the categorie to all imported posts to a drupal taxonomy named 'archive':

INSERT INTO term_node (nid, tid)SELECT (pn_sid + 133),12FROM _stories;

To Drupal 6Use phpMyAdmin to perform the following SQL. This requires both the PostNuke site and the

Page 178: Drupal - Installation Guide

new Drupal site to exist in the same MySQL server instance.

Note that the Drupal site must be a fresh one with no existing content or users. If you do havesuch then you will need to add an increment to the ID's to avoid conflicting index numbers.

You will want to adjust or remove the database names drupal and postnuke. You may need tochange the table prefix in these statements from "nuke_" to "pn_", depending on your version ofPostNuke.

UsersAssuming anon and admin are already present from the installation . . .

INSERT INTO drupal.users (uid, name, pass, mail, signature, timezone, mode,sort, threshold, status, init, created, access, data, login) SELECT pn_uid,pn_uname, pn_pass, pn_email, pn_user_sig, IF( pn_timezone_offset = 0, NULL, (pn_timezone_offset - 12) * 3600), 0, 0, 0, 1, pn_email, pn_user_regdate,UNIX_TIMESTAMP('2007-01-01 01:01:01'), "N;", 0 FROM postnuke.nuke_users WHEREpn_uid!=1;

Note: This also assumes your system timezone has not changed between the migration. If it has,you may wish to change the NULL to an appropriate value for the prior timezone (such as -18000for UTC-5) so that users experience the same zone.

Optional unoptimized query to import creation timestamps which may include the "Nov 1, 2001"style:

UPDATE users,nuke_users SET users.created = ( SELECT CASE WHEN ISNULL( UNIX_TIMESTAMP(STR_TO_DATE( nuke_users.pn_user_regdate, '%b %d, %Y' ) ) )THEN nuke_users.pn_user_regdateELSE UNIX_TIMESTAMP( STR_TO_DATE( nuke_users.pn_user_regdate, '%b %d, %Y' ) )ENDFROM nuke_usersWHERE users.uid = nuke_users.pn_uid )

or change the field using UNIX_TIMESTAMP('2007-01-01 01:01:01') in the first query to:

WHEN ISNULL( UNIX_TIMESTAMP( STR_TO_DATE( nuke_users.pn_user_regdate, '%b %d,%Y' ) ) )THEN nuke_users.pn_user_regdateELSE UNIX_TIMESTAMP( STR_TO_DATE( nuke_users.pn_user_regdate, '%b %d, %Y' ) )

User profiles

PostNuke stores its user profile data in additional columns in its nuke_users table, while Drupaluses a separate many-to-many table to match users, profile items and profile values.

First, examine your nuke_users table for fields to transfer, then create the fields in the profileeditor. Identify the fid values in profile_fields that match the columns in nuke_users, and run avariation of the following query for each, replacing 1 with the fid and both instances of pn_namewith the column to be copied:

INSERT INTO drupal.profile_values (fid, uid, value)SELECT 1, pn_uid, pn_nameFROM postnuke.nuke_usersWHERE pn_name != ''

News ItemsINSERT INTO drupal.node (nid, vid, type, title, uid, status, created, comment,promote, moderate, changed)SELECT pn_sid,pn_sid,"story",CASE WHEN NOT strcmp(LEFT(pn_title,3),"_TP") THEN substring(pn_title,4) ELSEpn_title END,pn_uid,1,unix_timestamp(pn_time),2,1,0,now()FROM postnuke.nuke_stories s, postnuke.nuke_users uWHERE s.pn_informant=u.pn_uname

INSERT INTO drupal.node_revisions (nid, vid, uid, title, teaser, body, log,timestamp, format)SELECT pn_sid,pn_sid,pn_uid,pn_title,pn_hometext,CONCAT( IF( pn_notes != '', CONCAT(pn_hometext,'<div class="node-note">',pn_notes,'</div>') ,pn_hometext), IF( pn_bodytext != '', CONCAT('',pn_bodytext), '')),"",UNIX_TIMESTAMP( STR_TO_DATE( pn_time, '%Y-%m-%d %T') ),2FROM postnuke.nuke_stories s, postnuke.nuke_users uWHERE s.pn_informant=u.pn_uname

Note: To allow only filtered HTML, change the 2 above to 1.

Polls

Page 179: Drupal - Installation Guide

Because stories and polls both reside in the nodes table, you will have to set an appropriate offsetwhen importing. Consider using SELECT MAX( nid ) FROM node to determine this.

SET @POLL_NID_OFFSET=2600;INSERT INTO drupal.node(nid, vid, type, title, uid, status, created, changed, comment, promote)SELECTpn_pollid+@POLL_NID_OFFSET,pn_pollid+@POLL_NID_OFFSET,'poll',pn_title,2,1,pn_timestamp,pn_timestamp,2,0FROM postnuke.nuke_poll_desc

You also have to insert a revision. It will have a title, but no body or teaser text.

SET @POLL_NID_OFFSET=2600;INSERT INTO drupal.node_revisions(nid, vid, uid, title, timestamp, format)SELECTpn_pollid+@POLL_NID_OFFSET,pn_pollid+@POLL_NID_OFFSET,2,pn_title,pn_timestamp,2FROM postnuke.nuke_poll_desc

Now we can add the poll itself:

SET @POLL_NID_OFFSET=2600;

INSERT INTO drupal.poll(nid, active)SELECT pn_pollid+@POLL_NID_OFFSET,0FROM postnuke.nuke_poll_desc

Lastly, you add the poll choices. Unfortunately you won't know who voted for what, as thisinformation is not recorded by PostNuke.

SET @POLL_NID_OFFSET=2600;INSERT INTO drupal.poll_choices(nid, chtext, chvotes, chorder)SELECT pn_pollid + @POLL_NID_OFFSET, pn_optiontext, pn_optioncount, pn_voteid -1FROM postnuke.nuke_poll_dataWHERE pn_optiontext != ''ORDER BY pn_pollid, pn_voteid

Poll comments are handled below.

CommentsINSERT INTO drupal.comments ( cid, pid, nid, uid, subject, comment, hostname,timestamp, status, format, thread, name, mail, homepage)SELECT c.pn_tid, c.pn_pid, c.pn_sid, IF(STRCMP(c.pn_name,""),u.pn_uid, 0), c.pn_subject, c.pn_comment, c.pn_host_name, UNIX_TIMESTAMP(c.pn_date), 0, 2, "01/", IF(STRCMP(c.pn_name,""), c.pn_name, NULL), IF(STRCMP(c.pn_email,""), c.pn_email, NULL), IF(STRCMP(c.pn_url,""), c.pn_url, NULL)FROM postnuke.nuke_comments cLEFT JOIN postnuke.nuke_users u ON c.pn_name = u.pn_uname

Note: To allow only filtered HTML, change the 2 above to 1. If you prefer not to importanonymous comments, replace the last two lines with:

FROM postnuke.nuke_stories s, postnuke.nuke_users uWHERE s.pn_informant=u.pn_uname

Poll comments

As with nodes, an increment must be applied to poll comments, as they use the same table as storycomments. You must also use the same node increment that you used before.

SET @POLL_NID_OFFSET=2600;SET @POLL_CID_OFFSET=39000;

INSERT INTO drupal.comments

Page 180: Drupal - Installation Guide

( cid, pid, nid, uid, subject, comment, hostname, timestamp, format, thread,name, mail, homepage )SELECTpn_tid+@POLL_CID_OFFSET,IF(pn_pid != 0, pn_pid+@POLL_CID_OFFSET, 0),pn_pollid+@POLL_NID_OFFSET,IF(STRCMP(c.pn_name,''), u.pn_uid, 0),pn_subject,pn_comment,pn_host_name,UNIX_TIMESTAMP(pn_date),1,'01/',IF(c.pn_name != '', c.pn_name, NULL),IF(c.pn_email != '', c.pn_email, NULL),IF(c.pn_url != '', c.pn_url, NULL)FROM postnuke.nuke_pollcomments cLEFT JOIN postnuke.nuke_users u ON c.pn_name = u.pn_uname;

If you find you have doubled quotemarks in your poll comments, try the following fix:

SET @POLL_CID_OFFSET=39000;UPDATE comments SET comment = REPLACE(comment, '\'\'', '\'') WHERE cid =>POLL_CID_OFFSET

Comment statistics

INSERT INTO drupal.node_comment_statistics ( nid, last_comment_timestamp,last_comment_name, last_comment_uid, comment_count)SELECT pn_sid,UNIX_TIMESTAMP('2008-01-01 01:01:01'),"",0,pn_commentsFROM postnuke.nuke_storiesWHERE pn_sid > 1

Rather than perform this query, consider running this script with the devel php code block. Thiswill also fix comment threading.

TrackerNote: This assumes you are using the Tracker 2 module, rather than the Drupal 6 default.

INSERT INTO drupal.tracker2_node (nid, published, changed)SELECT nid, status, changedFROM postnuke.node

INSERT INTO drupal.tracker2_user (nid, uid, published, changed)SELECT nid, uid, status, changedFROM postnuke.node

REPLACE INTO drupal.tracker2_user (nid, uid, published, changed)SELECT DISTINCT nid, uid, 1, timestampFROM postnuke.comments WHERE status = 0 ORDER BY timestamp DESC

TaxonomySet up a taxonomy and insert a single term into it. Look at your drupal.term_data table to identifythe vid (here, it is 1). Use this in the following SQL statement:

INSERT INTO drupal.term_data (tid, vid, name, description) SELECT pn_topicid, 1,pn_topicname, pn_topictext FROM postnuke.nuke_topics

Then, insert the instances of this term - PostNuke has a simple category hierarchy, so you onlyhave one term to import per story:

INSERT INTO drupal.term_node (nid, vid, tid) SELECT pn_sid, pn_sid, pn_topicFROM postnuke.nuke_stories

Beware: Community Tags relies on having its own table filled with details of existing tags. If youperform this query with a tag vocabulary after installing it, you may find these tags removed whenother modifications are made by that module.

Migrating from SPIPThere is a module that migrates from SPIP to drupal 6.x. It is currently (April 2010) in activedevelopment.

It provides a plugin for spip so it depends on versions above 1.8 (I think) that introduced ainterface for plugins.

http://drupal.org/project/spip2drupal

Migrating from SlashcodeThis is how I moved over my data from a Slashcode site to Drupal. It worked for me, might workfor you, might not.

Slash tables needed, dumpm'!

Page 181: Drupal - Installation Guide

mysqldump --add-drop-table --opt -c story_topics_rendered journals journals_textusers users_info comments comment_text stories story_text topics >SlashTables.sql

need to change the name of the users and comments tablessince they are the same in Drupal and Slash.mysqldump -u -p db > db.sqlcp SlashTables.sql Good_Slash_Tables.sqlperl change.pl (this just changes the name of the users and comments tables)mysql -u -p db_name < SlashTables.sql

now, go to mysql and make the magic happenMove over topics,Needs to go into term_data, term_hierarchy

delete from term_data;insert into term_data (tid,vid,name,description,weight) selecttid,2,keyword,textname,0 from topics;delete from term_hierarchy;insert into term_hierarchy (tid,parent) select tid,0 from topics;

Move over the Slash users into the Drupal users table.Move over all users who have, left a comment, written in their journal, logged into the site in thepast 18 months (or so). maybe this needs to be done into 3 identical tables, then do a select out ofthem?

Make Sure we get all the Journals Users (Slash users tables was renamed)

delete from users where uid > 2;insert into users (uid,name,mail,signature,pass,created,status)select distinct slash_users.uid, slash_users.nickname, slash_users.realemail,slash_users.sig, slash_users.passwd, UNIX_TIMESTAMP(users_info.created_at),1from slash_users, journals, users_info where slash_users.uid > 2 andslash_users.uid = users_info.uid and slash_users.uid = journals.uid;

Make sure we get all the users who have ever left acomment(Slash users tables needs renamed)insert ignore into users (uid,name,mail,signature,pass,created,status)select distinct slash_users.uid, slash_users.nickname, slash_users.realemail,slash_users.sig, slash_users.passwd, UNIX_TIMESTAMP(users_info.created_at),1from slash_users, users_info, slash_comments where slash_users.uid =slash_comments.uid and slash_users.uid=users_info.uid;

Make sure we get all the users who have logged into the site inthe last 18 months(Slash users tables needs renamed)insert ignore into users (uid,name,mail,signature,pass,created,status)select distinct slash_users.uid, slash_users.nickname, slash_users.realemail,slash_users.sig, slash_users.passwd, UNIX_TIMESTAMP(users_info.created_at),1from slash_users, users_info where users_info.lastaccess > '2007' andslash_users.uid = users_info.uid;

OK That's the useres, now content.Move over Journals.

The journals.discussion=comments.sidcombine the damn stupid seperate journals tablesthis also messes up the sequences things

select max(stoid) from story_text;select max(stoid) from stories;

ALTER TABLE stories CHANGE stoid stoid int(20) unsigned DEFAULT '0' NOT NULL;update journals set id = id+22376;update journals_text set id = id+22376;update journals set discussion=5 where discussion IS NULL;

insert into stories(stoid,uid,time,discussion,tid,sid)selectid,uid,date,discussion,tid,idfrom journals;

insert into story_text(title,introtext,stoid)select journals.description,journals_text.article, journals.idfrom journals,journals_text where journals_text.id = journals.id;

Move over stories

Page 182: Drupal - Installation Guide

The DISCUSSION field in the slash_stories table == the SID field in the slash_comments table

delete from node;delete from node_revisions;

insert into node(nid,vid,type,title,uid,status,created,changed,comment,promote,moderate,sticky)selectstories.stoid,stories.stoid,'story',story_text.title,stories.uid,1,UNIX_TIMESTAMP(stories.time),UNIX_TIMESTAMP(stories.time),2,1,0,0from stories, story_textwhere stories.stoid = story_text.stoid;

insert into node_revisions (nid,vid, uid, title, body,teaser,log,timestamp,format)select stories.stoid,stories.stoid,stories.uid, story_text.title,concat(story_text.introtext,story_text.bodytext), story_text.introtext,'Imported From Slashcode', UNIX_TIMESTAMP(stories.time),1from stories, story_text where stories.stoid = story_text.stoid;

make sure to change this number to whatever that id+ was from journals

update node set type = 'blog' where nid > 22376;update node set promote = 0 where type = 'blog';

fix the Annonymous patron thingupdate node set uid = 0 where uid = 1;update node_revisions set uid = 0 where uid = 1;

update node set uid = 1 where uid = 2;update node_revisions set uid = 1 where uid = 2;

update node_revisions set body = teaser where body = '';

Now, the commentsdelete from comments;

insert into comments(nid,cid,pid,uid,subject,comment,timestamp,score,status,format,thread,name,mail,homepage)selectstories.stoid,slash_comments.cid,0,slash_comments.uid,slash_comments.subject,comment_text.comment,UNIX_TIMESTAMP(slash_comments.date),0,0,1,'01/',slash_users.nickname,'[email protected]','http://example.org'from stories,comment_text,slash_users, slash_commentswhere comment_text.cid = slash_comments.cidand slash_users.uid = slash_comments.uidand stories.discussion = slash_comments.sidON DUPLICATE KEY UPDATE nid= nid+2;

update comments set uid = 0 where uid = 1;update comments set uid = 1 where uid = 2;

fix the comment count for each nodedelete from node_comment_statistics;

insert into node_comment_statistics (nid,comment_count)select node.nid,count(*) as comment_countfrom node,commentswhere node.nid = comments.nidgroup by comments.nidorder by comment_count desc;

select nid from node order by nid desc limit 1;select nid from node_revisions order by nid desc limit 1;select cid from comments order by cid desc limit 1;select * from sequences;update sequences set id = 28105 where name = 'node_nid';update sequences set id = 28105 where name = 'node_revisions_vid';update sequences set id = 31521 where name = 'comments_cid';update sequences set id = 110 where name = 'term_data_tid';

delete from term_node;insert into term_node (tid,nid)select story_topics_rendered.tid, stories.stoid from story_topics_rendered,stories where story_topics_rendered.stoid=stories.stoid order by stories.stoid;

delete from node_access;insert into node_access (nid,gid,realm,grant_view,grant_update,grant_delete)select nid,0,'all',1,0,0 from node;

clear the cachestruncate cache;truncate cache_content;truncate cache_filter;truncate cache_menu;truncate cache_page;truncate cache_views;

Page 183: Drupal - Installation Guide

Migrating from WordpressMigrating to Drupal from Wordpress should be a fairly straight forwards process for a solid basictransition (complex custom additions to wordpress may need to be re-engineered into Drupal, butyour content, comments taxonomies etc should come across just fine)

Essentially, the wordpress import takes a feed of your existing wordpress site and generates nodesand vocabularies from that data in your Drupal site

Suggested steps are;

- Setup a base Drupal site (see our beginning with drupal articles)

- Configure it to your new site as much as you can ( you could install an existing theme or modifyan existing theme to your preference )

- Install the Wordpress Import module and enable it in your module configuration

- Follow the instructions in the Wordpress Import module (read the project page and any text filesthat come with the tarball) and execute the import

Some things to consider ;

- The visual layout/structure may not be the same, you need to think about if you need customcontent types (see the CCK module) or you want to migrate using the default 'page' content type

- You may need to theme the created nodes from your wordpress import that are generated fromyour wordpress import.

- Wordpress uses the concept of "categories" but in Drupal they are called "Vocabularies", termsform a taxonomy which belong to a vocabulary, but in the end, they are all the same thing, just beaware of the difference in terminogoly however there are many plugins for Drupal that can do verycool things depending on the Vocabulary/Taxonomy (or category) of a post.

Hope this all helps!

There are also some external contrib modules located here http://superjacent.net/cms/?q=node/509that provide an alternative to the wordpress_import module

Using XML-RPC to combine Drupal andWordpress on a siteThis is really a set of notes for myself, so I can document what I'm trying to do and hopefully beable to reproduce it in the future.

The Idea

I have two sites right now - a Wordpress blog at /, and in /more, a Drupal site. I'm working on anew theme for both that includes content from each on the other, with some interesting ways toswitch between them.

Starting Out

I have some ideas on grabbing Wordpress content from a Drupal page/template, so I'mconcentrating on solving the other issues right now: starting Drupal and getting some content outof it. So far, I started a test.php file and have the folowing bits:

1. *Start Drupal:* Not too bad, Morbus helped me here.

require_once (./includes/bootstrap.inc); drupal_bootstrap (DRUPAL_BOOTSTRAP_FULL);

2. *Grab some content to render:* I want to do as much config as possible in Drupal as to thecontent that appears on the Wordpress side, so I created new region in my theme, 'shared', andassigned a couple blocks to it. I then followed up the previous code with this:

print theme('blocks', 'shared');

At this point I'm a bit stumped... I'm getting simply a blank page as the output. I suspect is hassomething to do with not having a template file to use, but I'm not at all certain, and I'd be open toany suggestions.

Cautious Success

Well, I figured out the problem I was experiencing in [Part I](/tech/franken-site-i) - I hadmisconfigured the blocks for the region I was attempting to use, so that's fixed. Using a chdir, mycode now looked like this:

$_DIR = 'more'; chdir ($_DIR); require_once './includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

Page 184: Drupal - Installation Guide

return theme('blocks', $region);

And it worked! At least, from a plain php page in my Wordpress directory it did. As soon as Ibuilt it into a quick-and-dirty Drupal plugin for Wordpress, it went all to heck.

Fatal error: Cannot redeclare timer_start() (previously declared in /server/path/to/redmonk.net/wp-settings.php:57) in /server/path/to/redmonk.net/more/includes/bootstrap.inc on line 37

D'oh! Drupal and Wordpress were defining the same functions! To be expected, I suppose. Icommented out the first few I found but kept running into more. Time to look for another solution.

Regroup and RPC

After my simple attempts at just including Drupal's bootstrap and using theme() to get what Iwanted failed, I turned to a new pipe to get content from: Drupal's XML-RPC interface.

I have experience writing Drupal modules, so I did the required reading on hook_xmlrpc, and thengot to work.

I added a custom module, redmonk.module. Then, I added a simple method to return the content Iwanted (hard coded for now, later I'd make it a little more generic).

function redmonk_shared () { return theme('blocks', 'shared'); }

Then I implemented hook_xmlrpc:

function redmonk_xmlrpc () { return array ("redmonk.shared"=>"redmonk_shared"); }

Lastly, I built a quick Wordpress plugin, the expansively named drupal.php:

include_once(ABSPATH . WPINC . '/class-IXR.php');

function drupal_get_blocks ($region) { $ixrcli = new \ IXR_Client('http://redmonk.net/more/xmlrpc.php', \ false,80,15); $ret = "no response";if ($ixrcli->query('redmonk.shared')) { $ret = $ixrcli->getResponse(); } return $ret; }

So now, I have an xml-rpc call that returns the chunk of HTML that I need for the Wordpress halfof my franken-site. Next, I need to confirm that I can do something similar from Wordpress.

It's Alive!

After managing to fetch the content I wanted from Drupal into a Wordpress page via a customXML-RPC call, I needed to figure out how to get recent posts out of Wordpress and onto aDrupal page.

Naturally RSS is a pretty decent way to accomplish this sort of thing, but I did not really want tomess with creating a custom feed just for this information. So I fell back to Wordpress's XML-RPC api. Wordpress supports the MetaWeblog api, which has an api which fitted my needsexactly:

metaWeblog.getRecentposts (n)

So, I added a couple methods to my redmonk.module for Drupal:

function redmonk_monkinetic_posts_call ($num) { $rpc_result = xmlrpc ("http://redmonk.net/xmlrpc.php", "metaWeblog.getRecentPosts", "myblog","myusername","mypwd", $num); return $rpc_result; }

function redmonk_monkinetic_posts ($num) { $posts = redmonk_monkinetic_posts_call ($num); $retstr = "<dl class='nodes'>\n"; foreach ($posts as $post) { $retstr .= "<dt><a href='" . $post['link'] . "'>" . $post['title'] . "</a></dt>\n"; $retstr .= "<dd>" . $post['description'] . "</dd>\n"; } $retstr .= "</dl>\n"; return $retstr; }

The call goes into a Drupal template in the normal manner:

print redmonk_monkinetic_posts (1);

Bingo!

Page 185: Drupal - Installation Guide

So now all that remains is to clean up the plugin/module code on each side, and implement thenew template. I *had* initially hoped for a more "integrated" way to work between the two, butthe XML-RPC approach was remarkably simple, will be quite flexible, and will survive upgradesto both platforms.

Migrating from XoopsHere are some queries that I used in a recent migration from Xoops 2.0.13 to Drupal 4.7.0. Thiswas my first real life experience using SQL so be warned. You might consider adapting the XoopsMigration Module for use with 4.7 instead.

Make database backups at every stage using mysqldump or phpmyadmin.

mysqlump --opt -u user -p database > backup.sql

You will need to have your xoops and drupal tables in the same database for these to work. Thewhole transfer took me about 10 hours but I was learning as I went. This is not a completemigration solution but hopefully these will save you some time.

In each case change the drupal_users and xoops_users to reflect your table prefixes.

Users

Change the '-28800' to reflect the timzone of your users.

INSERT INTO drupal_users (uid, name, pass, mail, signature, status, init, created, timezone, access, timezone_name, language) SELECT uid, uname, pass, email, user_sig, '1', email, user_regdate, '-28800', last_login,'America/Argentina/Buenos_Aires', 'en'FROM xoops_users WHERE uid > 1;

If you want to transfer Occupation and User From then you'll need to setup fields in theprofile.module and transfer these separately. Drupal supports user avatars but I didn't transferthese.

Stories from News 1.4

I deleted all nodes from my drupal account before transferring stories so that node ids matchedxoops story ids. Drupal 4.7 uses node and node_revision tables so you need to to this in twostages. Here the revision id is the same as the node id. You'll need to add the bbcode input filter tothe Filtered HTML filter.

INSERT INTO drupal_node (nid, vid, type, title, uid, status, created, changed,comment, promote, moderate, sticky)SELECT storyid, storyid, 'story', title, uid, '1', created, published, '2', '1','0', '0' FROM xoops_stories WHERE published<>0;

INSERT into drupal_node_revisions (nid, vid, uid, title, body, teaser, log,timestamp, format) SELECT storyid, storyid, uid, title, concat(hometext, bodytext),concat(hometext, bodytext), '', published, '1' FROM xoops_stories WHEREpublished<>0;

Forum posts from NewBB | CBB 2.x

Enable the drupal forum module and setup some categories to hold your xoops forum topics.Drupal's forum uses nodes for topics and comments for topic replies. At this point you will need tofind the number of nodes you have from your story import - change #NODE below for thisnumber.

INSERT into node (nid, vid, type, title, uid, status, created, changed, comment, promote, moderate, sticky) SELECT (topic_id + #NODE), (topic_id + #NODE), 'forum', topic_title,topic_poster, '1', topic_time, topic_time, '2', '0', '0', '0' FROMxoops_bb_topics;

INSERT into drupal_node_revisions (nid, vid, uid, title, body, teaser, log,timestamp, format) SELECT (t.topic_id + #NODE), (t.topic_id + #NODE), t.uid, t.subject, p.post_text, p.post_text, '', t.post_time, '1' FROM xoops_bb_posts AS t INNER JOIN xoops_bb_posts_text AS p ON t.post_id =p.post_id AND pid = '0';

To set the topics from xoops to a category, setup your drupal categories and note down thenumbers. Here I didn't have many categories so I did it by hand - replace 15 below with yourdrupal category number and 1 with your xoops topic id. You can repeat this for each topic.

INSERT into drupal_forum (nid, vid, tid) SELECT (topic_id + #NODE), (topic_id + #NODE), '15' FROM xoops_bb_topics WHERE forum_id='1';

INSERT into drupal_term_node (nid, vid, tid) SELECT (topic_id + #NODE), (topic_id + #NODE), '15' FROM xoops_bb_topics WHERE forum_id='1';

Page 186: Drupal - Installation Guide

If your forum posts have attachments these will be lost in the above process.

To transfer forum replies (this assumes tables of both are in the same database):

Replace the #NODE below with the number of nodes previous to forum nodes (same as above).Then run this query.

INSERT INTO comments( pid, uid, nid, subject, timestamp, comment ) SELECTxoops_bb_posts.post_id, xoops_bb_posts.uid, (xoops_bb_posts.topic_id + #NODE),xoops_bb_posts.subject, xoops_bb_posts.post_time, xoops_bb_posts_text.post_textFROM xoops_bb_posts, xoops_bb_posts_text WHERE xoops_bb_posts.post_id =xoops_bb_posts_text.post_id AND xoops_bb_posts.pid > 0;

It would appear that topic starting posts have pid of 0 in XOOPS which is why the condition ofimporting only posts with pid bigger than 0 results in importing only actual replies.

Cleaning up

Statistics

In order to get the forum topics to show up I needed to add some information to other tables. Iidentified what needed to be added using a diff between mysqldumps. There may be an easier wasto do this.

INSERT into drupal_history (uid, nid, timestamp) SELECT uid, nid, created FROMnode; INSERT into drupal_node_comment_statistics (nid, last_comment_timestamp, last_comment_name, last_comment_uid,comment_count)SELECT nid, created, '', '1', '0' FROM node;

To get the Nodes to show the correct poster comments, You can try this Mysql Stored procedure. Iencountered issues with the forums after populating the history, and comment_stats table. Youneed to modify the CREATE line, and set the Definer. (Note this is using the mysql QueryBrowser) Once this SP is created, you can do aCALL fixforums();to execute it

DELIMITER $$

DROP PROCEDURE IF EXISTS `fixforums` $$CREATE DEFINER=`user`@`ip.add.res.s` PROCEDURE `fixforums`()BEGIN DECLARE done INT DEFAULT 0; DECLARE id,replies,postid INT; DECLARE cur1 CURSOR FOR select topic_id, topic_replies, topic_last_post_idfrom xoops_bb_topics; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN cur1;

REPEAT FETCH cur1 INTO id,replies,postid; IF NOT done THEN select uid from xoops_bb_posts where post_id=postid into @lastpostid; update node_comment_statistics set last_comment_uid=@lastpostid wherenid=@nodeid; update node_comment_statistics set comment_count=replies wherenid=@nodeid; END IF; UNTIL done END REPEAT;

CLOSE cur1;

END $$

DELIMITER ;

Avatars & Signatures

Drupal 6.xInstall/Enable the Author Pane Module for Drupal.Enable User Pictures in admin/user/settingsCopy the avatars from wherever they are stored in your xoops system, into the drupal'sites/default/files/pictures'Run this stored procedure to associate the xoops avatars with pictures on the drupal system.Again, You need to modify the CREATE line, and set the Definer.CALL fixavatars();

DELIMITER $$

DROP PROCEDURE IF EXISTS `fixavatars` $$CREATE DEFINER=`user`@`ipaddress` PROCEDURE `fixavatars`()BEGIN DECLARE done INT DEFAULT 0; DECLARE sig VARCHAR(255); DECLARE id INT; DECLARE cur1 CURSOR FOR SELECT uid,user_avatar FROM xoops_users whereuser_avatar <> 'blank.gif'; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN cur1;

Page 187: Drupal - Installation Guide

REPEAT FETCH cur1 INTO id,sig; IF NOT done THEN Set @picture=concat('sites/default/files/pictures/',sig); update users set picture=@picture where uid=id; END IF; UNTIL done END REPEAT;

CLOSE cur1;

END $$

DELIMITER ;

And to Fix the Signatures:

DELIMITER $$

DROP PROCEDURE IF EXISTS `fixsig` $$CREATE DEFINER=`user`@`ipaddress` PROCEDURE `fixsig`()BEGIN

DECLARE done INT DEFAULT 0; DECLARE sig VARCHAR(255); DECLARE id INT; DECLARE cur1 CURSOR FOR SELECT uid,user_sig FROM xoops_users; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN cur1;

REPEAT FETCH cur1 INTO id,sig; IF NOT done THEN update users set signature=sig where uid=id; END IF; UNTIL done END REPEAT;

CLOSE cur1;

END $$

DELIMITER ;

Sequences

NOTE: This is Not needed in Drupal 6.xOnce you have imported your nodes and comments you will need to edit the drupal sequencestable to reflect the new numbers. Warning: if you don't do this then new content will try andoverwrite existing nodes.

BBcode

If you allowed your users to use BBcode in posts you will need to enable the bbcode module andenable it in the default input filter.

URL Aliases

You can use the path module to create url aliases from your old Xoops links.

modules/news --> node modules/newbb --> forumregister.php --> user/registerlogin.php --> user/loginbackend.php --> rss.xmlmodules/contact --> contact

However, this is rather disappointing since menu items now appear as the OLD links. I can't find away to change alias precedence in path module - maybe someone else knows.

Search Index

You will need to index the site for searches in the admin - settings - search - re-index site.

Annoyances

Character Sets

I had problems moving between latin and unicode character sets / collations. When data wastransferred titles or posts were truncated at the site of multibyte characters. I ended up hacking thisbadly by removing all these characters from my xoops as they were only '' and --.

Migrating from boastMachineAfter recommending Drupal to a friend who had stuck with boastMachine for a long time, he toldme there was hardly any way for importing all of his content and child comments to drupal withoutgoing one by one. There seemed to be a half working script somewhere that he tried out (I couldn't

Page 188: Drupal - Installation Guide

find it) but ended up stuck with loads of php errors.

So I took a look and made a bunch of php scripts that do the trick. I wrote them for drupal 6.x andboastmachine version 3.1 with php 5.2.5 and MySQL 5.0.51a. They should work on >php4 (drupalrecommends 5.2 or higher) and all MySQL versions (although drupal6 only supports >MySQL4.1). What they do is export all the entries from two of boastmachine's database' tables ('comments'and 'posts') and import them into four of Drupal's ('comments', 'node', 'node_comment_statistics'and 'node_revisions'), so that all content gets ported.

The script is divided in 8 files (keep them in the same folder), with 'migrate.php' as the central one.This is the one to edit and execute via browser. Before you do so, make a clean drupal installation.Then add the content type you wish to import all posts to and enter its name into 'migrate.php'.Also, both databases need to be on the same MySQL.

Plenty of settings are modifiable. Feel free to use this as a template for your own script as long asyou stick to the (CC) licence. Contact me via reply or through the info on my user profile page(filiptc).

If you want to see the script's progress while executing, you need to disable output buffering(either in php.ini or in .htaccess).

Download script files in .zip

Migrating from ezPublishI've migrated an ezPublish site to drupal. Here are the steps:

1. I performed a basic installation of drupal, and created the first user.2. I used phpMyAdmin to extract the entire ezPublish database, then installed it at the target site.3. I used sql statements to extract articles, links, and users from ezPublish and insert them intodrupal database.4. I modified ezPublish's "printer-friendly" article template to insert html comments showing thestart and end of teaser and body.5. ezPublish maintains articles in ezxml. I used a perl script to fetch each ezPublish article withLWP::UserAgent, extract the html-formatted teaser and body, and update the content of the drupaldatabase.6. I used a perl script to extract user's first and last names from ezPublish and package them intothe users.data field for use by drupal's profile module.

Here are the sql and perl scripts I used. Please note the following limitations:

1. Doesn't know how to access ezPublish pages that require login; the content of these pages willbe left in ezxml.2. Doesn't do any content except articles, article categories, links, link categories, and users.Doesn't fix internal links (links to other pages on same site), but does identify nodes containingthem.

Move ezp database content to drupal database[note from editor ax: you have to escape the special characters < (&lt;), > (&gt;), and & (&amp;)]

mysql -ppassword drupal < migrate.sql

The following is the content of migrate.sql:

select @uid := if(max(uid),max(uid),0) from users;select @tid := if(max(tid),max(tid),0) from term_data;select @nid := if(max(nid),max(nid),0) from node;select @role_authenticated_user := rid from role where name = 'authenticateduser';select @ezp_url := "http://myezpsite.com";

## Insert all ezpublish articles as drupal "story" nodes#

INSERT INTO node(nid, type,title,uid,status,comment, promote, users, attributes, revisions,created,teaser,body)selectid+@nid, # nid'story', # typename, # title1, # uid1, # status2, # comment0, # promote'','','',created,contents,contentsfrom ezp.eZArticle_Articlewhere IsPublished;

Page 189: Drupal - Installation Guide

## Insert all ezpublish weblinks as nodes#

select @weblink_nid:= max(nid)+1 from node;

INSERT INTO node(nid, type, title, uid, status, comment, promote, users, attributes, revisions,created, teaser, body)selectid+@weblink_nid, 'weblink',name,1,1,2,0,'','','',created,description,descriptionfrom ezp.eZLink_Link;

INSERT INTO weblink(nid,weblink,click,monitor,#size,change_stamp,checked,#feed,refresh,threshold,spider_site#spider_url)selectid+@weblink_nid, if (url regexp '://', url, concat('http://', url)),0,0,0,0,21600,40,0from ezp.eZLink_Link;

## Discover vocabularies for ezarticle and one for ezlink# (These established manually by drupal configure/taxonomy UI)#

select @topic := vid from vocabulary where name = 'Topic';select @link := vid from vocabulary where name = 'Link';

## Insert ezarticle_category names as terms under topics vocabulary#

INSERT INTO term_data(tid,vid,name,description,weight)selectid+@tid,@topic,name,description,0from ezp.eZArticle_Category;

## The article categories (terms) are non-hierarchical#

insert into term_hierarchyselect id+@tid,0 from ezp.eZArticle_Category;

Page 190: Drupal - Installation Guide

## Insert categories assigned to ezarticles#

INSERT INTO term_node(nid,tid)selectarticleid+@nid,categoryid+@tidfrom ezp.eZArticle_ArticleCategoryLink;

## Insert eZLink_Category names as terms under vocabulary links#

select @weblink_tid := max(tid)+1 from term_data;

INSERT INTO term_data(tid,vid,name,description,weight)selectid+@weblink_tid,@link,name,description,0from ezp.eZLink_Category;

## The link categories (terms) are non-hierarchical#

insert into term_hierarchyselect id+@weblink_tid,0 from ezp.eZLink_Category;

## Insert categories assigned to ezlinks#

INSERT INTO term_node(nid,tid)selectlinkid+@weblink_nid,categoryid+@weblink_tidfrom ezp.eZLink_LinkCategoryLink;

## Insert users#

INSERT INTO users ( uid , name , pass , mail ,# mode ,# sort ,# threshold ,# theme , signature , timestamp , status , timezone ,# language , init ,# data , rid )selectid+@uid,login,password, # encryption differs, so users will have to reset their passwordsemail,signature,1074479825,1, # active status0, # timezoneemail, # init@role_authenticated_userfrom ezp.eZUser_User;

Page 191: Drupal - Installation Guide

## drupal declares these table primary keys as auto_increment, but# in fact actually assigns them explicitly. Update drupal's idea# of what id to assign next for each table.#

delete from sequences where name='users_uid';insert into sequences (name, id)select 'users_uid', max(uid) from users;

delete from sequences where name='term_data_tid';insert into sequences (name, id)select 'term_data_tid', max(tid) from term_data;

delete from sequences where name='node_nid';insert into sequences (name, id)select 'node_nid', max(nid) from node;

## Identify articles with internallinks (to be edited manually in drupal)#

select nid from node where body regexp @ezp_url;

Parse ezxml (in perl, with LWP::UserAgent)#!/usr/bin/perl -w

use strict;use LWP::UserAgent;use HTTP::Request::Common qw(POST); use DBI;use Carp;

sub parse;

my $server = 'localhost';my $database = 'drupal';my $username = 'me';my $password = 'foobar';my $verbose;

my $dbh = DBI->connect("dbi:mysql:$database:$server", $username, $password ) or croak "Can't connect to database";$dbh->{RaiseError} = 1;

my $select = $dbh->prepare( q/select nid from node where type='story'/ );my $update = $dbh->prepare( q/update node set teaser=?, body=? where nid=?/ );

$select->execute;while (my $id = $select->fetchrow) { my $ezpid = $id; # The following is the "printer-friendly" url for ezp article my $url = "http://mathiasconsulting.com/article/articleprint/$ezpid/-1/0/"; my $uri = URI->new( $url );

my $ua = LWP::UserAgent->new(); my $req = POST $uri, [ ];

# Send the request, receive the response

my $response = $ua->request($req)->as_string;

# print "******************\n", uc($url), "\n";# print "$response\n\n\n";

(my $teaser, my $body) = parse( $response ); if ($teaser and $body) {$update->execute( $teaser, "$teaser\n\n$body", $id ); } else {print "Can't parse $url\n"; }}

## Look for lines placed there by articleprint.tpl#

sub parse { my $s = shift; my $teaser;

Page 192: Drupal - Installation Guide

my $body;

if ($s =~ /<!-- teaser starts -->\n(.*?)<!-- teaser ends -->\n/ms) {$teaser = $1; } if ($s =~ /<!-- body starts -->\n(.*?)<!-- body ends -->\n/ms) {$body = $1; }

return $teaser, $body;}

Get ezpublish user real names for drupalprofile.module[note from ax to cheryl: this code triggers "suspicious input" because it of "data=". had to escapethis with "&#100;ata=". i also wrapped the lines ("my $template=") at 80 chars to make this lookbetter here - hope i didn't introduce any bugs]

#!/usr/bin/perl -w

use strict;

use DBI;use Carp;

my $server = 'localhost';my $database = 'drupal';my $username = 'me';my $password = 'password';my $verbose;

my $dbh = DBI->connect("dbi:mysql:$database:$server", $username, $password ) or croak "Can't connect to database";$dbh->{RaiseError} = 1;

# difference between ezp user id and drupal uid (see @uid in migrate.sql)my $iddifference = 1;

my $template='a:13:{s:16:"profile_realname";s:%d:"%s";s:15:"profile_address";\s:0:"";s:12:"profile_city";s:0:"";s:13:"profile_state";s:0:"";s:11:"profile_zip";\s:0:"";s:15:"profile_country";s:0:"";s:11:"profile_job";s:0:"";s:16:"profile_homepage";\s:0:"";s:17:"profile_biography";s:0:"";s:11:"weblink_new";s:1:"0";s:5:"pass1";\s:0:"";s:5:"pass2";s:0:"";s:5:"block";a:0:{}}';

my $select = $dbh->prepare( q/select ID, FirstName, LastName fromezp.eZUser_User/ );my $update = $dbh->prepare( q/update users set data=? where uid=?/ );

$select->execute;while ((my $id, my $first, my $last) = $select->fetchrow) { my $name = ($first || '') . ($first && $last ? ' ' : '') . ($last || '');

my $profile = sprintf( $template, length( $name ), $name ); $update->execute( $profile, $id+$iddifference );}

Migrating from phpBBFor the owners of a phpBB forum, there are two solutions:

either migrate the data of your board to a Drupal forum,or integrate the phpBB board within the Drupal web site.

phpBB integration solutionAn integrated phpBB forum will never be as tightly integrated as a native Drupal forum within awider Drupal site. But it may be the best solution for people who

have a phpBB installation which has a lot of traffic and too much data to migrate efficiently(though the module above has been tried on fairly large phpBB boards),who, more often, just don't like the default Drupal forum and prefer the feature set offeredby phpBB.

See the integrated phpbb project home page here:http://drupal.org/project/phpbb

See also phpbb, a Drupal group on phpBB integration.

phpBB migration solutionData Migration

Page 193: Drupal - Installation Guide

Drupal 6.x and 5.x

The module to move your phpBB data to a Drupal forum can be downloaded from the projecthome page.

The Drupal 6 module also allows to migrate data from phpBB3, while the drupal 5 versions arerestricted to phpBB2 only.

Post migration setupTo make the most of your new Drupal forum, you may want to check out the following:

Drupal modules equivalent to phpBB features

Questions? Problems? Comments?Please use the phpbb2drupal issue tracker for any of the following:

you find a bug or experience a problem when using the phpbb2drupal module.You are unclear on how to use it and would like assistance (submit a support request issue).You find that this documentation is not complete (don't submit the issue to the DrupalDocumentation Team but to the phpbb2drupal project)

Drupal modules equivalent to phpBB featuresMany people switching over from phpBB wonder if a native Drupal forum has the samefunctionality.While a Drupal forum will never be the same as a phpBB forum, there exist numerous contributedmodules who can do most of what phpBB does, and potentially more.

This page is aims to list such modules so that a former phpBB admin can find their way moreeasily within the maze of Drupal modules.

This list is not exhaustive. It will be completed progressively. If you have any question that youwould like to be answered within this page, then open a support request within the phpbb2drupalproject. You could also see Adding functionality to your forum with contribs.

Forum Theming and integrationAdvanced Forum makes a more forum like style available for themes and also integration withmany other modules for additional features.

Thread splittingThis feature is not yet well supported within Drupal. There exist however a promissing moduleprototype that would allow an admin to move a comment from one place to another, either withina thread or to another thread, or to create a new thread (new node).See the Comment mover module.

Private ForumsCurrently, the best Drupal solution to have private forums (i.e. forums where only a specific 'role'- e.g. Moderators - can post and view the topics), is to use the forum access module along withAccess Control Lists. An alternative approach is to use taxonomy access.

Concurrently, there is a feature request that would allow for the equivalent of private forums withthe only the Drupal core. See the Make posting/viewing permission more granular issue.

Private MessagingPrivatemsg Is the module to use for Private messaging. The phpbb2drupal module also supportsimporting existing phpbb messages.

Email notificationphpBB gives you the possibility to receive email notifications when a reply is posted to a thread.

Once again, a Drupal forum has no such feature out of the box, but a number of contributionmodule give you alternative ways to achieve the same:

Comment notify is a simple solution that works well. However there are also other options:Comment RSS: This module adds comment RSS serving capabilties to Drupal, which issuitable for some tracking of comments for your users.Notify: The notify module allows users to subscribe to periodic emails which include allnew or revised content and/or comments much like the daily news letters sent by somewebsites.Organic groups: Enable users to create and manage their own 'groups'. Each group can havesubscribers, and maintains a group home page where subscribers communicate amongst

Page 194: Drupal - Installation Guide

themselves. Organic groups is a fairly complex module: it provides email notification ofnew content posted on each group, according to the user's settings, but it also gives youmuch more than that.Subscriptions: This module enables users to subscribe to be notified of changes to nodes ortaxonomies, such as new comments in specific forums, or additions to some category ofblog. Once enabled, all nodes will have an additional link that allows the user to change theirsubscriptions. This module is probably the closest to phpBB email notification feature.

Editing postsThere are scores of contribution modules that makes editing posts easier. Browse the contributionmodules for the most appropriate filter/editor for your site.

In particular:

BUEditor: BUEditor allows you to add tagging buttons to the textarea without turning it intoa fully featured wysiwyg.Smileys: A filter that substitutes ASCII smileys with images.

Migrating from vBulletinThere are two possible solutions: migration or integration.

To migrate posts and users from a vBulletin forum to a Drupal forum, see:

vBulletin to Drupal - Module for migration from vBulletin to Drupal.Advanced Forum - Module to build Drupal forums similar to systems like vBulletin.Choosing Drupal forum over vBulletin - Article on this option.

To integrate a vBulletin forum within a Drupal website, see:

Drupal vB - Drupal module for integration between vBulletin and Drupal.vbDrupal - Fork of Drupal to combine the powers of Drupal and vBulletin.vBulletin - Drupal group on vBulletin integration.

Search engine-friendly site migrationWhen migrating a website from any system to Drupal you should be aware of existing inboundlinks to your site, as well as search engine indexes and ranking. In order to maintain your searchengine ranking and also not break inbound links you should plan to redirect inbound requests toold uris to your new drupal nodes.

Instead of offering up 404 Errors, you can direct users to the content they are looking for. In somecases using the path_redirect module may be sufficient. In other cases you may want to writeredirect rules in your .htaccess file, and in still other cases, the method described below may workfor you. Another step, which will help with search engine indexing is to install and configurexmlsitemap module and submit your sitemap to the major search engines for indexing.

The rest of this article describes an approach that will parse he Search Engine query from theHTTP_REFERER and search the drupal website for what the user was actually looking for.

Create a page node with PHP code enabled in the input format, and add the following code.

<?php $searchengines = array( '^http://www\.google.*$' => 'q', '^http://www.googel.fi.*$' => 'q', '^http://.*search.msn.co.*results.*$' => 'q', '^http://.*\.mysearch.com/jsp/GGmain.jsp?searchfor=.*$' =>'searchfor', '^http://search.freeserve.com/.*$' => 'q', '^http://aolsearch.aol.co.*$' => 'query', '^http://search.yahoo.com.*$' => 'va', '^http://search.yahoo.com.*$' => 'p', '^http://www.bbc.co.uk/cgi-bin/search/.*' => 'q', '^http://www.tiscali.co.uk/search/results.php.*$' => 'query', '^http://www.altavista.com/web/results.*$' => 'q', '^http://search.hotbot.co.uk/cgi-bin/pursuit.*$' => 'query', '^http://www.excite.co.uk/search/web/results.*$' => 'q', '^http://uk.search.yahoo.com/search.*$' => 'p', '^http://search.wanadoo.*$' => 'q' );

$referer = getenv("HTTP_REFERER"); while( list( $regexp, $qsitem ) = each( $searchengines ) ) { if( eregi( $regexp, $referer ) ) { echo( t("<br/><h2>Search Engine Detected</h2>It would appear you arrivedhere on the wings of a search engine, so, I will search my local database andshow you anything that matches what you were looking for:<br/>")); $url = parse_url( $referer ); $querystring = $url['query']; $querystring = explode( "&", $querystring ); while( list( , $value ) = each( $querystring ) )

Page 195: Drupal - Installation Guide

{ $item = explode( "=", $value ); if( $item[0] == $qsitem ) { if( trim( $item[1] ) != '' ) { $item[1] = urldecode( $item[1] ); echo ( search_data( $item[1] ) ); } } } } }?>

This provides a (partial) list of regular expressions for common search engines, with informationas to which query string parameter is the query the user entered. The HTTP_REFERER value (thesite the user clicked a link to get to your site) is then examined against this list. When a match isfound, a search is done using the standard Drupal search call (search_data). This locates potentialmatches, and hopefully, keeps the user on your site.

In order to use this, create a new node which allows PHP code. You can call it what you want,and put whatever explanatory text you like on it. You can set whatever path you like. Just drop theabove code-clip into place. Then, in Administration -> Settings set the 404 handler to be the pathto the new node you created, and voila, if the user arrives from a recognized search engine, theirsearch is performed on your site. It's working nicely for me.

Troubleshooting a migration into a Drupaldatabase: "page not found" or no titles listedAt times, after you've imported your content into the appropriate Drupal tables, you get a "page notfound" error or just various weirdnesses. Sometimes Drupal needs a kick in the pants to registeryour imported nodes.

First, clear your caches. If that doesn't work, try clearing them again and running cron. Next, youmay need some stronger medicine.

Loading your nodes programmatically and saving them using Drupal's built in functions allowsyour nodes to register themselves with the various contributed modules on your site and canresolve various issues.

I did this using a short script:

Caution: if you have Pathauto enabled with it's default settings, this will create new aliases for allyour nodes based on their titles. If you don't want this, either disable pathauto before running, orchange pathauto's settings to not automatically alias all saved nodes if they already have a URLalias.

<?php

/**this script can be copied to a file in the root of your drupal install** and invoked by visiting yoursite.com/name_of_file.php** This loads and then programmically saves all the nodes** in you drupal installation.** You must change the 'chdir' directory to your Drupal root.**/

//change this to the root directory of your drupal installation:chdir('/home/members/quixote/sites/d6');include_once('./includes/bootstrap.inc');include_once('./modules/node/node.pages.inc');

drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);db_set_active('default');

$sql = "SELECT `nid` FROM node ORDER BY node.nid";$results = db_query($sql);

$old_dump = array();

while( $nodes = db_fetch_object($results) ) { print_r ($nodes->nid); $currentnode = node_load( $nodes->nid ); print_r($currentnode); node_save( $currentnode );}?>

Importing CSV files into DrupalThe node import was not ready yet for D6 so I went with drupal 5. (though it will be ready shortly)

I had a content type with 30 or more fields.

These fields where a mix of CCK and Taxonomy - multi level.

Page 196: Drupal - Installation Guide

The client handed me a large spread sheet and the first thing I did (after hours of doing it thewrong way) was made a quick mysql table to import it into. The client made Columns perTaxonomy and Sub for example 2 rows of content would look like.

"eid","Taxonomic_Group", "Common_Name"5,"Mammal | Carnivora | Canis | lupus familiaris","Dog"6,"Mammal | Rodentia | Rattus | norvegicus","Brown Rat"

Lost more fields but this is a good example

eid was an external ID - CCK

Taxonomic_Group was three columns which I reduced to one via a mysql concat command (youcould do this in the spreadsheet but I am more comfortable with mysql) Here is the query I used.

SELECT eid, CONCAT_WS(" | ", tax_group, tax_subgroup, genus, species) as tax,`common_name`, CONCAT_WS(" | ", bio_tissue, bio_subtissue) as bio, CONCAT_WS(" | ",antomical_structure, antomical_sub_structure) as ant, `age`, `sex`, `condition`, `note`,CONCAT_WS(" | ", `mat_type`, `mat_sub`, `mat_sub_sub`) `coord`, `author1`, `author2`,`author3`, `author4`, `author5`, `author6`, `author7`, `author8`, `author9`, `author10`, `author11`,`author12`, `author13`, `author14`, `author15`, `year`, `journal_title`, `journal`, `volume`,`start_page`, `end_page`FROM `biology_dept`

Common Name was just the title of the node.

Thing is node import would not import and create heirarchy taxonomy so I used Taxonomy CSVimport

To help clean things up when I messed up but did not want to do a full database recovery

http://drupal.org/project/views_bulk_operations This creates and easy way to find and delete largeamounts of nodes

http://drupal.org/project/taxonomy_manager This can help move taxonomy around or delete aquick amount of items.

Then of course mysqldump at the command line for quic backups

Modules Used

http://drupal.org/project/taxonomy_csv

http://drupal.org/project/taxonomy_manager