What is the most scalable PHP-based directory structure for a large site?
You should have one directory as web root, where only files you want exposed to the whole internet should reside.
project/
web/
index.php
css/
js/
images/
config/
lib/
- web/ is the root shown to visitors
- lib/ is here the library folder, and where autoload look for files.
You can add more subfolders to project/ like controller, modules, view, helper, etc. This depends on your framework.
EDIT:
If you use composer (which I recommend) and maybe npm with grunt and less your file structure would be the following:
project/
web/
js/
css/
images/
index.php
cli/
config/
config.php
node_modules/
src/
test/
vendor/
composer.json
composer.lock
packages.json
- web/ has all your public files
- cli/ scripts and programs to be run from command line NOT the web
- config/ has all your config files (in git you ignore config.php and instead have config.dist.php without usernames, passwords, validation codes and table prefixes/suffixes and other "secrets")
- node_modules/ has all your library files from npm (in git I suggest you put this in a submodule)
- src has all your local PHP files in psr4 structure, set up to autoload in composer.json
- test/ has all your unit tests for your src classes, set up in autload-dev in composer.json (remember to use composer install --no-dev on live, maybe add -o if you don't have too many classes)
- vendor has all your library files from composer and the ONE AND ONLY autoload.php to be included in web/index.php and any cli scripts (in git I suggest you ignore this vendor folder)
Add other folders and files as required for your project.
For deployment use this structure:
/sites/project/ (project is your projectname)
current (alias to current release folder releases/v1.1.0)
previous (optional alias to previous release folder releases/v1.0.1)
releases/
v1.0.0/ (git checkout of tag v1.0.0)
v1.0.1/ (git checkout of tag v1.0.1)
v1.1.0/ (git checkout of tag v1.1.0)
shared/ (has all your shared files and folders to be aliased in all releases - maybe something like GlusterFS)
Make a deployment script. Something like this:
First take backup of db or to copy it to a new database, checkout git repo to new folder with release tag, get all git submodules, run composer install --no-dev, setup any aliases for shared folders and files like uploaded images and configuration files, generate js/css with grunt and less or equivalent, point current alias to the new folder with the tag, run update database script, restart nginx/apache/fpm-php services, run tests to check the website is up.
Have a script to go back to previous version (or a guide so you know what to do).
For core files which are included: approot/inc/
For data access functions and classes are in: approot/dao/
For javascripts: approot/scripts/
For CSS: approot/styles/
For images: approot/img/
For static content (normally for user profile pictures or uploaded images): approot/static/
For caches: approot/caches/
For templates or View files: approot/templates/
All pages file: approot/
Structure from Samstyle PHP Framework
The answer I posted here was from 2009. Over the years more standards were published, including PSR-0 which covers the topic on folder structure. I also have a new (and I feel that it's better) folder structure with Packfire Framework.
This is my setup. It's worked great for me for small - very large projects (including a social network).
These folders would all live within my main application folder:
- config - contains custom PHP config files
- css - contains the project's CSS files
- helpers - contains 'helper' files (each file is a collection of functions)
- images - contains the project's images
- js - contains the project's Javascript files
- lib - contains PHP classes specific to the project
-
modules - My MVC framework allows packaging site sections as modules
-
blog - An example module
- controllers - contains the controllers for the module
- models - contains the models for the module
- views - contains the views for the module
-
blog - An example module
- views - contains views that should be globally accessible (page header, footer, etc)
All the directories could obviously contain sub-folders that would further organize your files. For example, the 'css' folder could have sub-folders named 'web' and 'mobile'. The 'images' folder could contain a 'user_uploaded' folder which could then contain`'profile'. And of course you can add folders as you see fit, in one project I have a folder called 'uploaders' which just contains stand-alone upload scripts.
I also use convenience methods which help construct the filenames of what I want to load. For example, my loadView() will look for the view file in the current module directory, or if you pass an optional $module argument, it will look specifically within that module's folder.
I hope this helps.