├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── bin ├── common.sh ├── compile ├── compile_node ├── detect ├── release └── util │ └── autotune.php ├── conf ├── buildpack.conf ├── nginx │ ├── base.conf.erb │ ├── cakephp2.conf.erb │ ├── default_site.conf.erb │ ├── magento.conf.erb │ ├── silex.conf.erb │ ├── slim.conf.erb │ ├── symfony2.conf.erb │ ├── yii.conf.erb │ ├── zf1.conf.erb │ └── zf2.conf.erb └── php │ ├── newrelic.ini │ ├── php-fpm.conf │ └── php.ini ├── frameworks ├── cakephp2 ├── default ├── magento ├── silex ├── slim ├── symfony2 ├── yii └── zf2 ├── requirements.txt └── support ├── ext ├── amqp ├── apcu ├── igbinary ├── imagick ├── libevent ├── memcache ├── memcached ├── mongo ├── redis ├── ssh2 └── sundown ├── get_zlib ├── manifest ├── package-checksum ├── package_composer ├── package_ext ├── package_icu ├── package_jq ├── package_libmcrypt ├── package_libmemcached ├── package_librabbitmq ├── package_libssh2 ├── package_nginx └── package_php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.4.1, 2015-10-19 4 | 5 | * Autotune the PHP-FPM configuration based on the dyno size 6 | 7 | ## v0.4.0, 2015-04-28 8 | 9 | ### New features 10 | 11 | * Update PHP to 5.5.24 12 | * Improve the nginx config to support SSL endpoints 13 | * Add a way to authenticate github api calls for composer by setting an oauth token in ``COMPOSER_GITHUB_TOKEN`` 14 | * Add support for the Yii framework 15 | * Add support for the composer cakephp package to detect Cakephp 16 | * Add support of extension with dependencies in the compile script 17 | * Add support for the AMQP extension. Add ``ext-amqp`` to your requirements in your composer.json to enable it 18 | * Add support for the SSH2 extension. Add ``ext-ssh2`` to your requirements in your composer.json to enable it 19 | * Add support for the FTP extension. Add ``ext-ftp`` to your requirements in your composer.json to enable it 20 | 21 | ### Bug fixes 22 | 23 | * Made the build scripts compatible with Linux 24 | * Don't use the fifo for logs as it does not work on logplex 25 | * Show script name and line number when errors occur to make buildpack errors easier to debug 26 | * Update the build scripts to avoid using vulcan, which does not work anymore 27 | * Update the sorting of versions to handle them properly 28 | 29 | ## v0.3.7, 2015-04-28 30 | 31 | ### Changes 32 | 33 | * Use the official repo for pecl/memcache 34 | * Use the heroku env variables for the newrelic config 35 | 36 | ## v0.3.6, 2014-03-26 37 | 38 | ### Changes 39 | 40 | * Update PHP to 5.5.10 41 | * Tail CakePHP log files 42 | * Add `memcache` extension, you can enable it by putting 43 | `"ext-memcache": "*"` into your `composer.json` requirements 44 | * Set UTC as default timezone to prevent PHP notices. This can be 45 | changed anytime by your app via `date_default_timezone_set` or by 46 | setting `date.timezone` in your `php-config` section in 47 | `composer.json` 48 | 49 | ## v0.3.5, 2014-02-25 50 | 51 | ### Changes 52 | 53 | * Add support for new Heroku API for compile time user config variables. 54 | Variables set with `heroku config:set` are now always available at 55 | compile time. 56 | * Add support for Zend Framework 2 57 | * Enable Freetype support in PHP GD 58 | * Updated PHP to 5.5.9 59 | * Frameworks can now define which log files should be additionally 60 | "tailed" so they show up in `heroku logs` 61 | 62 | ## v0.3.4, 2014-01-24 63 | 64 | ### Changes 65 | 66 | * Add `application/x-javascript` to GZIP-able types 67 | * Add support for the Sundown extension. Add `ext-sundown` to your 68 | requirements in your `composer.json` and update your lockfile to enable it. 69 | 70 | ## v0.3.3, 2014-01-20 71 | 72 | ### Changes 73 | 74 | * Ignore when a prebuilt extension bundle was not found in S3, which 75 | fixes Composer requires for `ext-curl` for example. 76 | 77 | ## v0.3.2, 2014-01-14 78 | 79 | ### Changes 80 | 81 | * Update PHP to 5.5.8 82 | * Update NGINX to 1.4.4 83 | 84 | ## v0.3.1, 2014-01-12 85 | 86 | ### Changes 87 | 88 | * Add `apcu` as a separate extension bundle for easy updating 89 | * Install `apcu` from the separate extension bundle in `compile` to 90 | update all existing installations to APCU 4.0.2. This release features 91 | the return of the `apc_` functions for a real drop in replacement. 92 | * Merge PR #72 93 | 94 | ## v0.3.0, 2013-12-27 95 | 96 | ### Changes 97 | 98 | * Add support for wildcards in engine versions, e.g. `5.4.*` selects the 99 | latest available version of PHP 5.4. Staying up to date has never been easier! 100 | * Made document root overridable for Symfony apps 101 | * Rebuilt 5.5, 5.4.19 and 5.3.27 to include the [phpredis][], mongo, exif, 102 | readline, sockets and bcmath extensions. 103 | * Enable extensions in the `.ini` files distributed with the binaries. 104 | * Added `php-includes` config directive for `composer.json` for 105 | including additional PHP config files. 106 | * PHP, NGINX and Composer binaries are now cached and revalidated 107 | against MD5 hashes. This should provide notably faster deployments. 108 | * Add scripts for pre-building some popular extensions, like Mongo, Redis, 109 | Imagick, Libevent,… 110 | * Add support for adding extensions like Mongo on-demand, driven by 111 | `ext-` requirements in `composer.json`, e.g. require `ext-libevent` to 112 | add the `libevent` extension 113 | * Add BCMath and EXIF extensions to PHP 114 | * Add mcrypt to PHP 115 | * Add the `intl` extension 116 | * Add support for Slim, CakePHP and Magento frameworks 117 | * Add `sockets` to PHP 118 | * Add support for installing NPM packages found in `package.json` files, 119 | which can be used at compile time (e.g. the LESS compiler) 120 | * Add NewRelic support. 121 | * Add support for `imagick` extension 122 | * Frameworks now support a `post-compile` method 123 | * `composer.lock` is now mandatory 124 | * Composer packages are now detected by looking at the `composer.lock`. 125 | * Vulcan is now installed with bundler 126 | * A `HEROKU_BUILD_TIME` variable is now set when compiling the slug, 127 | which is available at runtime. 128 | * Symfony apps now only expose `app.php`, previously also `app_dev.php` 129 | was reachable. 130 | 131 | [phpredis]: http://github.com/nicolasff/phpredis 132 | 133 | ## v0.2.1, 2013-09-10 134 | 135 | ### Changes 136 | 137 | * Fix compile command evaluation 138 | * #28: Fix NGINX error caused by duplicate `root` directives 139 | 140 | ## v0.2.0, 2013-09-03 141 | 142 | ### Changes 143 | 144 | * Buildpack now works also only with an `index.php` in the project's 145 | root, without `composer.json`. This makes it possible to run apps 146 | which are built for the official Heroku PHP buildpack. 147 | * Packaging scripts now use zlib package from S3 bucket 148 | * Add APCu by default 149 | * Changed the default PHP to 5.5.3 150 | * Add `nginx-includes` config key to include custom NGINX config files. 151 | * Add the special `default` specifier for engine versions 152 | * New structure for NGINX configurations. All shared config (like port, 153 | etc.) is now in one shared file, framework configurations are now 154 | included into the `server` scope. 155 | 156 | ## v0.1.1, 2013-07-05 157 | 158 | ### Changes 159 | 160 | * PHP 5.5.0 is the new default 161 | * Added PHP 5.4.17 162 | 163 | ## v0.1.0 164 | 165 | ### Changes 166 | 167 | * Added 5.3.26, 5.4.16, 5.5.0 168 | * Added `buildpack.conf` to easily customize buildpack settings when 169 | forked 170 | * Add Opcache settings 171 | * Using Zend Opcache for all PHP builds, leads to better performance and 172 | is an uniform solution from 5.3 to 5.5 173 | * Removed APC, in favor of APCu. 174 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Branching 4 | 5 | The `master` branch should always contain production ready code. All 6 | features which are staged to go into the next release are found in the 7 | `development` branch. 8 | 9 | Releases are done by merging `development` to `master` and creating a 10 | tag on `master` which follows [Semantic Versioning][]. 11 | 12 | [Semantic Versioning]: http://semver.org 13 | 14 | Features should always live in their own branch. Feature branches start 15 | with `feature/`, e.g. a name for your feature branch might be `feature/my-awesome-feature`. 16 | Feature branches should branch off `master`, and get merged to 17 | `development` once they are reviewed. 18 | 19 | * * * 20 | 21 | Please submit pull requests to the `development` branch. The 22 | `development` branch is used to make new releases of this buildpack, 23 | which are available to _all_ users. 24 | 25 | ## Hacking 26 | 27 | ### Setup 28 | 29 | You need the following tools to hack on this project: 30 | 31 | * An Amazon S3 bucket 32 | * An heroku application using the cedar-10 stack (the buildpack is not compatible with the cedar-14 stack) to run the compilation 33 | 34 | Setup an S3 Bucket in Amazon. Then note the name of your bucket 35 | and set it as `S3_BUCKET` in `conf/buildpack.conf`. 36 | 37 | You can copy our bucket by running ``s3cmd cp --recursive --acl-public s3://chh-heroku-buildpack-php s3://your-bucket`` 38 | 39 | You should then configure the application to be ready to be used for packaging: 40 | 41 | ```bash 42 | # configure the application remote (assuming the app name "buildpack-packaging" here) 43 | $ heroku git:remote -a buildpack-packaging 44 | 45 | # configure the AWS credentials 46 | $ heroku config:set AWS_ACCESS_KEY='' AWS_SECRET_KEY='' 47 | 48 | # deploy the buildpack code to heroku (the development branch here 49 | $ git push heroku development:master 50 | ``` 51 | 52 | ### Packaging 53 | 54 | Packaging is done by running some scripts in a heroku dyno: 55 | 56 | ```bash 57 | $ heroku run bash 58 | ``` 59 | 60 | Compilation scripts can then be run on this dyno: 61 | 62 | ```bash 63 | $ cd support 64 | $ ./package_composer 65 | ``` 66 | 67 | All packaging scripts are in the `support` directory and are named 68 | `package_`, where `` is either `nginx` or `php`. All 69 | packaging scripts take the desired package version as first argument. 70 | 71 | When the packaging is complete, the manifest which lists all available 72 | package version is updated for the package type. Manifests are plain 73 | text files which list each available version on a separate line. 74 | 75 | They're uploaded to the S3 bucket as `manifest.` files, 76 | e.g. the manifest for PHP is `manifest.php`. 77 | 78 | Before packaging anything, you need to make sure that you've a Zlib 79 | tarball in your S3 bucket. Both NGINX and PHP depend on it. _You need 80 | the exact version which is set in the packaging scripts._ 81 | 82 | To get one, use `support/get_zlib `, for example: 83 | 84 | ./support/get_zlib 1.2.8 85 | 86 | #### Updating NGINX 87 | 88 | NGINX is packaged by the script `support/package_nginx`. 89 | 90 | For example, to build NGINX `1.5.2`: 91 | 92 | ./support/package_nginx 1.5.2 93 | 94 | #### Updating PHP 95 | 96 | PHP is packaged by the script `support/package_php`. 97 | 98 | For example, to build PHP `5.5.0`: 99 | 100 | ./support/package_php 5.5.0 101 | 102 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2013 Christoph Hochstrasser 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the “Software”), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced PHP Heroku Build Pack 2 | 3 | ## What makes it unique? 4 | 5 | * Supports PHP 5.3, 5.4 and 5.5 6 | * Uses the memory of the dyno more efficiently by going with NGINX and PHP-FPM instead of Apache/mod_php 7 | * Supports Composer out of the box 8 | * No writing NGINX configuration files: supports CakePHP, Classic PHP applications, Magento, Silex, Slim, Symfony 2 and ZF2 apps with a simple configuration driven by your `composer.json`. 9 | * Zero-Configuration Symfony 2 and Yii 1 deployment. 10 | * Dynamic installing of [supported extensions](support/ext) listed as `ext-` requirments in `composer.json`. 11 | 12 | ## How to use it 13 | 14 | Use the `--buildpack` parameter when creating a new app: 15 | 16 | heroku create --buildpack https://github.com/CHH/heroku-buildpack-php myapp 17 | 18 | Or set the `BUILDPACK_URL` config var on an existing app: 19 | 20 | heroku config:set BUILDPACK_URL=https://github.com/CHH/heroku-buildpack-php 21 | 22 | * * * 23 | 24 | If you want to be on the bleeding edge and use pre-release features, then use 25 | `git://github.com/CHH/heroku-buildpack-php#development` as buildpack 26 | url. 27 | 28 | ## Stack 29 | 30 | * NGINX 1.4 or 1.5 31 | * PHP 5.3, 5.4 and 5.5, with [ZendOpcache][] and [APCu][] ([Info](https://chh-php-test.herokuapp.com/info)) 32 | * PHP-FPM 33 | 34 | [ZendOpcache]: http://pecl.php.net/package/ZendOpcache 35 | [APCu]: http://pecl.php.net/package/apcu 36 | [Available PHP Versions]: http://chh-heroku-buildpack-php.s3.amazonaws.com/manifest.php 37 | [Available NGINX Versions]: http://chh-heroku-buildpack-php.s3.amazonaws.com/manifest.nginx 38 | 39 | ## Detection 40 | 41 | This buildpack detects apps when the app has a `composer.lock` in the 42 | app's root. 43 | 44 | If an `index.php` is detected in the app's root, then it switches to 45 | "classic mode", which means that every ".php" file is served with PHP, 46 | and the document root is set to the app root. 47 | 48 | When a `composer.lock` is detected, then the buildpack does `composer 49 | install --no-dev`. 50 | 51 | ## Environment 52 | 53 | This buildpack sets environment variables during compile and runtime: 54 | 55 | * `HEROKU_BUILD_TIME`: Time when the slug was compiled. Format is `%Y%m%d%H%M%S`, e.g. `20131103111548` 56 | 57 | This buildpack also detects when the app has a node `package.json` in the 58 | app's root. And will install node dependencies like less for example. 59 | 60 | ## Frameworks 61 | 62 | ### CakePHP 63 | 64 | Is used when the app requires the `pear-pear.cakephp.org/CakePHP` Pear package or when the 65 | `extra.heroku.framework` key is set to `cakephp2` in the `composer.json`. This project assumes the layout given in the [FriendsOfCake/app-template](https://github.com/FriendsOfCake/app-template) composer project. 66 | 67 | Options: 68 | 69 | * `index-document`: With CakePHP apps, this should be the file where `$Dispatcher->dispatch(new CakeRequest(), new CakeResponse());` 70 | is called. All requests which don't match an existing file will be forwarded to 71 | this document. 72 | 73 | ### Classic PHP 74 | 75 | The classic PHP configuration is used as fallback when no framework was detected. It serves every `.php` file relative to the document root. 76 | 77 | This is also used when an `index.php` file was found in the root of your 78 | project and no `composer.json`. 79 | 80 | ### Magento 81 | 82 | Is used when the `extra.heroku.framework` key is set to `magento` in the `composer.json`. 83 | 84 | ### Silex 85 | 86 | Is used when the app requires the `silex/silex` package or when the 87 | `framework` setting is set to `silex` in the `composer.json`. 88 | 89 | Options: 90 | 91 | * `index-document`: With Silex apps, this should be the file where `$app->run()` 92 | is called. All requests which don't match an existing file will be forwarded to 93 | this document. 94 | 95 | ### Slim 96 | 97 | Is used when the app requires the `slim/slim` package or when the 98 | `extra.heroku.framework` key is set to `slim` in the `composer.json`. 99 | 100 | Options: 101 | 102 | * `index-document`: With Slim apps, this should be the file where `$app->run()` 103 | is called. All requests which don't match an existing file will be forwarded to 104 | this document. 105 | 106 | ### Symfony 2 107 | 108 | Is detected when the app requires the `symfony/symfony` package or when the 109 | `framework` setting is set to `symfony2` in the `composer.json`. 110 | 111 | This framework preset doesn't need any configuration to work. 112 | 113 | Please note that if you use config vars in Composer hooks, or in `compile` 114 | scripts, then a new code push may be necessary if you decide to change a config variable. 115 | 116 | ### Yii 1 117 | 118 | Is detected when the app requires the `yiisoft/yii` package or when the 119 | `framework` setting is set to `yii` in the `composer.json`. 120 | 121 | This framework preset doesn't need any configuration to work. 122 | 123 | Options: 124 | 125 | * `index-document`: All requests which don't match an existing file will be forwarded to 126 | this document. Defaults to `index.php`. With Yii apps, this can be set to `index-test.php` 127 | for deployments used for acceptance testing. 128 | 129 | ## Extensions 130 | 131 | When the buildpack encounters `ext-` requirements in your `composer.json`, it will look 132 | up the extension name in the [supported extensions](support/ext) and install them. 133 | 134 | The version constraint is ignored currently. 135 | 136 | For example, to install the Sundown extension: 137 | 138 | ``` 139 | { 140 | "require": { 141 | "ext-sundown": "*" 142 | } 143 | } 144 | ``` 145 | 146 | Note that the extension requirements defined by dependencies are not taken into account there. 147 | It must be required by the project itself. 148 | 149 | ##Logging 150 | 151 | This buildpack defines default log files by framework. 152 | It also defines log files nginx and php. 153 | 154 | ## Configuration 155 | 156 | Configuration is done via a file named `composer.json` in the app's 157 | root. 158 | 159 | A simple configuration could look like this: 160 | 161 | { 162 | "require": { 163 | "php": ">=5.4.0", 164 | "silex/silex": "~1.0@dev" 165 | }, 166 | "extra": { 167 | "heroku": { 168 | "document-root": "web", 169 | "index-document": "index.php" 170 | } 171 | } 172 | } 173 | 174 | This configures an app with the document root set to the project's `web` 175 | directory, and sets that all requests should go through `web/index.php` 176 | which contains the application's front controller. 177 | 178 | ### Configuration Directives 179 | 180 | This buildpack supports configuration through directives placed in the `heroku` 181 | key in the `extra` object. 182 | 183 | #### framework 184 | 185 | _Default: Null_ 186 | 187 | Use a framework preset for configuration. Some configuration keys cannot 188 | be overriden! 189 | 190 | Available presets: 191 | 192 | * `cakephp2` 193 | * `magento` 194 | * `silex` (needs `document-root` and `index-document` set) 195 | * `slim` 196 | * `symfony2` 197 | * `zf2` 198 | 199 | Example: 200 | 201 | "framework": "silex" 202 | 203 | #### document-root 204 | 205 | Document root relative to the app root. Defaults to the app root. 206 | 207 | "document-root": "web" 208 | 209 | #### index-document 210 | 211 | _Default: "index.php"_ 212 | 213 | Index Document relative to the document root. 214 | 215 | "index-document": "app.php" 216 | 217 | #### engines 218 | 219 | Set PHP and NGINX versions. 220 | 221 | To launch the app with PHP 5.3.23 and NGINX 1.3.14: 222 | 223 | "engines": { 224 | "php": "5.3.23", 225 | "nginx": "1.3.14" 226 | } 227 | 228 | Set the version to "default" to use the current default version. The current 229 | default versions are NGINX `1.4.4` and PHP `5.5.10`. 230 | 231 | The version identifiers can also include wildcards, e.g. `5.4.*`. At the 232 | time of writing, PHP `5.4.26` would be used in this case. This also 233 | works for NGINX. 234 | 235 | When a file named `.php-version` exists in the project root, then the 236 | PHP version is read from this file instead. 237 | 238 | See also: 239 | 240 | * [Available NGINX Versions][] 241 | * [Available PHP Versions][] 242 | 243 | #### php-config 244 | 245 | _Default: []_ 246 | 247 | Add directives to the `php.ini`. 248 | 249 | "php-config": [ 250 | "display_errors=off", 251 | "short_open_tag=on" 252 | ] 253 | 254 | #### php-includes 255 | 256 | _Default: []_ 257 | 258 | Include additional .ini files that should be parsed after the default php.ini. File paths 259 | are treated relative to the app root. 260 | 261 | Example: 262 | 263 | "php-includes": ["etc/php.ini"] 264 | 265 | #### nginx-includes 266 | 267 | _Default: []_ 268 | 269 | Include additional config files into the NGINX configuration. Config 270 | files are included into the `server` scope and are loaded after the 271 | framework provided config. File paths are treated relative to the app 272 | root. 273 | 274 | Example: 275 | 276 | "nginx-includes": ["etc/nginx.conf"] 277 | 278 | #### compile 279 | 280 | _Default: []_ 281 | 282 | Run console commands on slug compilation. 283 | 284 | "compile": [ 285 | "php app/console assetic:dump --env=prod --no-debug" 286 | ] 287 | 288 | _Note: pecl is not runnable this way._ 289 | 290 | #### newrelic 291 | 292 | _Default: false_ 293 | 294 | Enable instrumentation support via [New Relic](http://newrelic.com). 295 | It's recommended to add the New Relic addon to your Heroku app, but you 296 | can also set your license key manually by setting the `NEW_RELIC_LICENSE_KEY` config var via `heroku config:set`. 297 | 298 | "newrelic": true 299 | 300 | #### log-files 301 | 302 | _Default: []_ 303 | 304 | The buildpack defines default log files by framework and some log files for php-fpm and nginx. 305 | Any file put in `log-files` will be be appended to the list. 306 | A tail on each unique log file will be run at application startup 307 | 308 | "log-files": [ 309 | "app/logs/rabbit-mq.log", 310 | "vendor/nginx/stuff.log" 311 | ], 312 | 313 | 314 | ## Node.Js 315 | 316 | If your app contains a `package.json` node and its dependencies will be installed 317 | 318 | The nodejs buildpack is based on the [heroku diet node.js buildpack](https://github.com/heroku/heroku-buildpack-nodejs/tree/diet). 319 | This diet branch of the buildpack is intended to replace the official Node.js buildpack once it has been tested by some users. 320 | 321 | It : 322 | - Uses the latest stable version of node and npm by default. 323 | - Allows any recent version of node to be used, including pre-release versions, as soon as they become available on [nodejs.org/dist](http://nodejs.org/dist/). 324 | - Uses the version of npm that comes bundled with node instead of downloading and compiling them separately. npm has been bundled with node since [v0.6.3 (Nov 2011)](http://blog.nodejs.org/2011/11/25/node-v0-6-3/). This effectively means that node versions `<0.6.3` are no longer supported, and that the `engines.npm` field in package.json is now ignored. 325 | - Makes use of an s3 caching proxy of nodejs.org for faster downloads of the node binaries. 326 | - Makes fewer HTTP requests when resolving node versions. 327 | - Uses an updated version of [node-semver](https://github.com/isaacs/node-semver) for dependency resolution. 328 | - No longer depends on SCONS. 329 | - Caches the `node_modules` directory across builds. 330 | - Runs `npm prune` after restoring cached modules, to ensure that any modules formerly used by your app aren't needlessly installed and/or compiled. 331 | 332 | A minimal `package.json` file with less will look like this : 333 | ```json 334 | { 335 | "author": "Your Name", 336 | "name": "App", 337 | "dependencies": { 338 | "less": ">= 1.4.*" 339 | } 340 | } 341 | ``` 342 | 343 | Node and its modules will be available at compilation meaning you could process nodejs script at that time. 344 | 345 | ## Authenticating Composer calls on the Github API 346 | 347 | Unauthenticated calls to the Github API are subject to a low rate limit. This includes calls to the download endpoint 348 | which is attempted by default during the Composer call because archives can be cached between deployments. 349 | 350 | The buildpack supports using authenticated API calls with Composer: 351 | 352 | - Create a personal API token on Github. You can [read more on this](https://github.com/blog/1509-personal-api-tokens). 353 | The token should have the minimal permissions needed by your project. If your project only relies on public 354 | Github repositories for its dependencies, the best choice is to restrict it to the "public access" permissions. 355 | - Set your token as the "COMPOSER_GITHUB_TOKEN" config variable in your heroku application. Any new deployment 356 | will use it to authenticate the composer calls. 357 | 358 | ## Contributing 359 | 360 | Please see the [CONTRIBUTING](/CONTRIBUTING.md) file for all the 361 | details. 362 | -------------------------------------------------------------------------------- /bin/common.sh: -------------------------------------------------------------------------------- 1 | error() { 2 | echo " ! $*" >&2 3 | exit 1 4 | } 5 | 6 | status() { 7 | echo "-----> $*" 8 | } 9 | 10 | protip() { 11 | echo 12 | echo "PRO TIP: $*" | indent 13 | echo "See https://devcenter.heroku.com/articles/nodejs-support" | indent 14 | echo 15 | } 16 | 17 | # sed -l basically makes sed replace and buffer through stdin to stdout 18 | # so you get updates while the command runs and dont wait for the end 19 | # e.g. npm install | indent 20 | indent() { 21 | c='s/^/ /' 22 | case $(uname) in 23 | Darwin) sed -l "$c";; # mac/bsd sed: -l buffers on line boundaries 24 | *) sed -u "$c";; # unix/gnu sed: -u unbuffered (arbitrary) chunks of data 25 | esac 26 | } 27 | 28 | cat_npm_debug_log() { 29 | test -f $build_dir/npm-debug.log && cat $build_dir/npm-debug.log 30 | } 31 | 32 | unique_array() { 33 | echo "$*" | tr ' ' '\n' | sort -u | tr '\n' ' ' 34 | } 35 | 36 | init_log_plex() { 37 | for log_file in $*; do 38 | echo "mkdir -p `dirname ${log_file}`" 39 | done 40 | for log_file in $*; do 41 | echo "touch ${log_file}" 42 | done 43 | } 44 | 45 | tail_log_plex() { 46 | for log_file in $*; do 47 | echo "tail -n 0 -qF --pid=\$\$ ${log_file} &" 48 | done 49 | } 50 | 51 | # Show script name and line number when errors occur to make buildpack errors easier to debug 52 | trap 'error "Script error in $0 on or near line ${LINENO}"' ERR 53 | -------------------------------------------------------------------------------- /bin/compile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -o pipefail 5 | shopt -s dotglob 6 | 7 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 8 | source "$basedir/../conf/buildpack.conf" 9 | source $basedir/common.sh 10 | 11 | if [ -n "$BUILDPACK_DEBUG" ]; then 12 | set -x 13 | fi 14 | 15 | BUILD_DIR="$1" 16 | CACHE_DIR="$2" 17 | 18 | cd "$BUILD_DIR" 19 | mkdir -p "$CACHE_DIR/package" 20 | 21 | function fetch_engine_package() { 22 | local engine="$1" 23 | local version="$2" 24 | local location="$3" 25 | 26 | fetch_package "${engine}-${version}" "$location" 27 | } 28 | 29 | function fetch_package() { 30 | local package="$1" 31 | local location="$2" 32 | 33 | mkdir -p "$location" 34 | 35 | local checksum_url="http://${S3_BUCKET}.s3.amazonaws.com/package/${package}.md5" 36 | local package_url="http://${S3_BUCKET}.s3.amazonaws.com/package/${package}.tgz" 37 | local checksum=$(curl "$checksum_url" 2> /dev/null) 38 | local cache_checksum= 39 | 40 | if [ -f "$CACHE_DIR/package/${package}.md5" ]; then 41 | local cache_checksum=$(cat "$CACHE_DIR/package/${package}.md5") 42 | fi 43 | 44 | mkdir -p "$CACHE_DIR/package/$(dirname "$package")" 45 | 46 | if [ "$cache_checksum" != "$checksum" ]; then 47 | curl "$package_url" -L -s > "$CACHE_DIR/package/${package}.tgz" 48 | echo "$checksum" > "$CACHE_DIR/package/${package}.md5" 49 | else 50 | echo "Checksums match. Fetching from cache." 51 | fi 52 | 53 | tar xzf "$CACHE_DIR/package/${package}.tgz" -C "$location" 54 | } 55 | 56 | function log_error() { 57 | local c='s/^/ ! /' 58 | case $(uname) in 59 | Darwin) echo "$*" | sed -l "$c";; 60 | *) echo "$*" | sed -u "$c";; 61 | esac 62 | } 63 | 64 | function indent() { 65 | local c='s/^/ /' 66 | case $(uname) in 67 | Darwin) sed -l "$c";; 68 | *) sed -u "$c";; 69 | esac 70 | } 71 | 72 | function install_composer_deps() { 73 | local cwd=$(pwd) 74 | local target="$1" 75 | 76 | if [ ! -f "$target/composer.json" ]; then 77 | return 0 78 | fi 79 | 80 | if [ ! -f "$target/composer.lock" ]; then 81 | log_error "Lockfile required. Please check it in." 82 | return 1 83 | fi 84 | 85 | export COMPOSER_CACHE_DIR=$CACHE_DIR/composer 86 | mkdir -p $COMPOSER_CACHE_DIR 87 | mkdir -p "$target/vendor/composer/bin" 88 | 89 | local checksum=$(curl --silent "http://${S3_BUCKET}.s3.amazonaws.com/composer/composer.phar.md5") 90 | 91 | status "Vendoring Composer" 92 | if [ ! -f "$CACHE_DIR/composer.phar.md5" ] || [ "$(cat $CACHE_DIR/composer.phar.md5)" != "$checksum" ]; then 93 | echo "Updating Composer" | indent 94 | curl --silent "http://${S3_BUCKET}.s3.amazonaws.com/composer/composer.phar" > "$CACHE_DIR/composer.phar" | indent 95 | chmod a+x "$CACHE_DIR/composer.phar" 96 | echo "$checksum" > $CACHE_DIR/composer.phar.md5 97 | fi 98 | 99 | cp "$CACHE_DIR/composer.phar" "$target/vendor/composer/bin/" 100 | 101 | local required_extensions=$(jq --raw-output '.require | keys | .[]' < "$BUILD_DIR/composer.json" | grep '^ext-' | sed 's/^ext-//') 102 | local ext_dir=/app/vendor/php/lib/php/extensions/no-debug-non-zts-$(php_api_version) 103 | if [ -n "$required_extensions" ]; then 104 | status "Bundling additional extensions" 105 | for ext in $required_extensions; do 106 | echo "$ext" | indent 107 | 108 | local ext_ini="/app/vendor/php/etc/conf.d/$ext.ini" 109 | 110 | if [ -f "$ext_ini" ]; then 111 | echo "Already installed" | indent 112 | elif [ -f "$ext_dir/$ext.so" ]; then 113 | echo "Enabling bundled extension" | indent 114 | echo "extension=$ext.so" > "$ext_ini" 115 | else 116 | local ext_dependency=${PHP_EXT_DEPENDENCIES["$ext"]} 117 | if [ -n "$ext_dependency" ]; then 118 | local ext_dependency_target=${DEPENDENCY_TARGET["$ext_dependency"]} 119 | if [ -n "$ext_dependency_target" ]; then 120 | fetch_package "$ext_dependency" "$ext_dependency_target" | indent 121 | ADDITIONAL_INSTALLED_LIBS+=("$ext_dependency_target") 122 | fi 123 | fi 124 | 125 | # TODO: Find a better way to ignore extensions which were not found in S3 126 | fetch_package "ext/$(php_api_version)/php-${ext}" "/app/vendor/php" 2>/dev/null | indent || true 127 | fi 128 | done 129 | fi 130 | 131 | php "vendor/composer/bin/composer.phar" self-update 132 | 133 | if [ -n "$COMPOSER_GITHUB_TOKEN" ]; then 134 | status "Configuring the github authentication for Composer" 135 | php "vendor/composer/bin/composer.phar" config -g github-oauth.github.com "$COMPOSER_GITHUB_TOKEN" --no-interaction 136 | fi 137 | 138 | status "Installing application dependencies with Composer" 139 | { 140 | cd "$target" 141 | php "vendor/composer/bin/composer.phar" install \ 142 | --prefer-dist \ 143 | --optimize-autoloader \ 144 | --no-interaction \ 145 | --no-dev \ 146 | 2>&1 147 | cd "$cwd" 148 | } | indent 149 | } 150 | 151 | function install_node_deps() { 152 | local cwd=$(pwd) 153 | local target="$1" 154 | 155 | if [ ! -f "$target/package.json" ]; then 156 | return 0 157 | fi 158 | 159 | status "NODE (package.json) app detected" 160 | 161 | source ${basedir}/compile_node $BUILD_DIR $CACHE_DIR 162 | 163 | local node_path='vendor/node' 164 | 165 | # Symlink node to /app/vendor/node so node and its modules are runnable. 166 | 167 | ln -s ${BUILD_DIR}/${node_path}/ /app/${node_path} 168 | ln -s ${BUILD_DIR}/node_modules /app/node_modules 169 | 170 | echo "Node " `node -v` | indent 171 | } 172 | 173 | export_env_dir() { 174 | env_dir=$1 175 | blacklist_regex=${3:-'^(PATH|GIT_DIR|CPATH|CPPATH|LD_PRELOAD|LIBRARY_PATH|LD_LIBRARY_PATH)$'} 176 | if [ -d "$env_dir" ]; then 177 | for e in $(ls $env_dir); do 178 | echo "$e" | grep -qvE "$blacklist_regex" && 179 | export "$e=$(cat $env_dir/$e)" 180 | : 181 | done 182 | fi 183 | } 184 | 185 | function mktmpdir() { 186 | dir=$(mktemp -t php-$1-XXXX) 187 | rm -rf $dir 188 | mkdir -p $dir 189 | echo $dir 190 | } 191 | 192 | function php_api_version() { 193 | basename "$(php-config --extension-dir)" | tr '-' ' ' | cut -f 5 -d ' ' 194 | } 195 | 196 | function install_newrelic() { 197 | status "Enabling Newrelic support" 198 | 199 | local version="$1" 200 | local cwd=$(pwd) 201 | local ext_dir=/app/vendor/php/lib/php/extensions/no-debug-non-zts-$(php_api_version) 202 | local tempdir=$(mktmpdir "newrelic") 203 | cd "$tempdir" 204 | 205 | curl --silent -L "http://download.newrelic.com/php_agent/archive/${version}/newrelic-php5-${version}-linux.tar.gz" | tar xz 206 | mkdir -p $BUILD_DIR/vendor/newrelic/{bin,etc} 207 | cd "newrelic-php5-${version}-linux" 208 | 209 | cp -f "daemon/newrelic-daemon.x64" $BUILD_DIR/vendor/newrelic/bin/newrelic-daemon 210 | cp -f "agent/x64/newrelic-$(php_api_version).so" "${ext_dir}/newrelic.so" 211 | cp -f "$basedir/../conf/php/newrelic.ini" "/app/vendor/php/etc/conf.d/newrelic.ini" 212 | 213 | cd "$cwd" 214 | } 215 | 216 | function package_document_root() { 217 | jq --raw-output '.extra.heroku["document-root"] // ""' < "$BUILD_DIR/composer.json" 218 | } 219 | 220 | function package_index_file() { 221 | jq --raw-output '.extra.heroku["index-document"] // "index.php"' < "$BUILD_DIR/composer.json" 222 | } 223 | 224 | function package_framework() { 225 | jq --raw-output '.extra.heroku.framework // ""' < "$BUILD_DIR/composer.json" 226 | } 227 | 228 | function package_nginx_version() { 229 | jq --raw-output ".extra.heroku.engines.nginx // \"default\"" < "$BUILD_DIR/composer.json" 230 | } 231 | 232 | function package_php_version() { 233 | jq --raw-output ".extra.heroku.engines.php // \"default\"" < "$BUILD_DIR/composer.json" 234 | } 235 | 236 | function package_php_config() { 237 | jq --raw-output '.extra.heroku["php-config"] // [] | .[]' < "$BUILD_DIR/composer.json" 238 | } 239 | 240 | function package_php_includes() { 241 | jq --raw-output '.extra.heroku["php-includes"] // [] | .[]' < "$BUILD_DIR/composer.json" 242 | } 243 | 244 | function package_nginx_includes() { 245 | jq --raw-output '.extra.heroku["nginx-includes"] // [] | .[]' < "$BUILD_DIR/composer.json" 246 | } 247 | 248 | function package_log_files() { 249 | jq --raw-output '.extra.heroku["log-files"] // [] | .[]' < "$BUILD_DIR/composer.json" 250 | } 251 | 252 | function package_compile_cmd() { 253 | jq --raw-output '.extra.heroku["compile"] // [] | .[]' < "$BUILD_DIR/composer.json" 254 | } 255 | 256 | function package_newrelic_enabled() { 257 | local val=$(jq --raw-output '.extra.heroku["newrelic"] // false' < "$BUILD_DIR/composer.json") 258 | 259 | if [ "$val" = "true" ]; then 260 | return 0 261 | else 262 | return 1 263 | fi 264 | } 265 | 266 | export_env_dir "$3" 267 | 268 | # Download jq binary for JSON processing 269 | export PATH="$HOME/bin:$PATH" 270 | curl "http://${S3_BUCKET}.s3.amazonaws.com/jq/jq" -L -s -o - > "$HOME/bin/jq" 271 | chmod +x "$HOME/bin/jq" 272 | 273 | DEFAULT_PHP="5.5.24" 274 | DEFAULT_NGINX="1.4.4" 275 | 276 | AVAILABLE_PHP_VERSIONS=$(curl "http://${S3_BUCKET}.s3.amazonaws.com/manifest.php" 2> /dev/null) 277 | AVAILABLE_NGINX_VERSIONS=$(curl "http://${S3_BUCKET}.s3.amazonaws.com/manifest.nginx" 2> /dev/null) 278 | 279 | MCRYPT_VERSION="2.5.8" 280 | PHP_VERSION="default" 281 | NGINX_VERSION="default" 282 | DOCUMENT_ROOT= 283 | INDEX_DOCUMENT="index.php" 284 | FRAMEWORK= 285 | PHP_EXTRA_CONFIG= 286 | PHP_INCLUDES= 287 | COMPILE_CMD= 288 | NGINX_INCLUDES= 289 | NEWRELIC_VERSION=4.4.5.35 290 | LOG_FILES=( "/app/vendor/nginx/logs/access.log" "/app/vendor/nginx/logs/error.log" "/app/vendor/php/var/log/error.log" ) 291 | ADDITIONAL_INSTALLED_LIBS=() 292 | 293 | # Read config variables from composer.json if it exists 294 | if [ -f "$BUILD_DIR/composer.json" ]; then 295 | PHP_VERSION=$(package_php_version) 296 | NGINX_VERSION=$(package_nginx_version) 297 | DOCUMENT_ROOT=$(package_document_root) 298 | INDEX_DOCUMENT=$(package_index_file) 299 | FRAMEWORK=$(package_framework) 300 | PHP_EXTRA_CONFIG=$(package_php_config) 301 | PHP_INCLUDES=$(package_php_includes) 302 | COMPILE_CMD=$(package_compile_cmd) 303 | NGINX_INCLUDES=$(package_nginx_includes) 304 | USER_LOG_FILES=$(package_log_files) 305 | fi 306 | 307 | # Try reading PHP version from .php-version file in project 308 | if [ -f "$BUILD_DIR/.php-version" ]; then 309 | PHP_VERSION=$(cat "$BUILD_DIR/.php-version") 310 | fi 311 | 312 | if [ "$PHP_VERSION" = "default" ]; then 313 | PHP_VERSION="$DEFAULT_PHP" 314 | fi 315 | 316 | if [ "$NGINX_VERSION" = "default" ]; then 317 | NGINX_VERSION="$DEFAULT_NGINX" 318 | fi 319 | 320 | # Look for ".*" versions, match them against all available versions 321 | # and select the latest version which was found. 322 | if echo "$PHP_VERSION" | grep '\*' &>/dev/null; then 323 | PHP_VERSION=$(echo "$AVAILABLE_PHP_VERSIONS" | grep "^$PHP_VERSION$" | sort -r -V | head -n1) 324 | fi 325 | 326 | if echo "$NGINX_VERSION" | grep '\*' &>/dev/null; then 327 | NGINX_VERSION=$(echo "$AVAILABLE_NGINX_VERSIONS" | grep "^$NGINX_VERSION$" | sort -r -V | head -n1) 328 | fi 329 | 330 | VENDORED_NGINX=/app/vendor/nginx 331 | VENDORED_PHP=/app/vendor/php 332 | 333 | [ ! -d "$BUILD_DIR/vendor" ] && mkdir -p "$BUILD_DIR/vendor" 334 | 335 | status "Bundling NGINX ${NGINX_VERSION}" 336 | fetch_engine_package nginx "$NGINX_VERSION" /app/vendor/nginx | indent 337 | 338 | status "Bundling PHP ${PHP_VERSION}" 339 | 340 | # Install libraries also on build container, so PHP doesn't wayne about missing 341 | # dynamic libraries when running it during the slug compilation. 342 | fetch_package "libicu-51" /app/vendor/libicu > /dev/null 343 | fetch_package "libmcrypt-${MCRYPT_VERSION}" /app/vendor/libmcrypt > /dev/null 344 | 345 | fetch_engine_package php "$PHP_VERSION" /app/vendor/php | indent 346 | 347 | test ! -d ".profile.d" && mkdir -p .profile.d || true 348 | 349 | cat > ".profile.d/php.sh" < /dev/null 381 | 382 | for conf in $PHP_EXTRA_CONFIG; do 383 | echo "$conf" >> "/app/vendor/php/etc/php.ini" 384 | done 385 | 386 | for include in $PHP_INCLUDES; do 387 | cp "$BUILD_DIR/$include" "/app/vendor/php/etc/conf.d/" 388 | done 389 | 390 | # Detect PHP framework 391 | for f in "$basedir/../frameworks/"*; do 392 | if "$f" detect "$BUILD_DIR"; then 393 | FRAMEWORK="$f" 394 | fi 395 | done 396 | 397 | # Fall back to classic mode 398 | if [ -z "$FRAMEWORK" ]; then 399 | FRAMEWORK="$basedir/../frameworks/default" 400 | fi 401 | 402 | # Try to load the framework from the "frameworks" directory if it's just a 403 | # simple framework name like "symfony2" 404 | if [ ! -f "$FRAMEWORK" ] && [ -f "$basedir/../frameworks/$FRAMEWORK" ]; then 405 | FRAMEWORK="$basedir/../frameworks/$FRAMEWORK" 406 | fi 407 | 408 | if [ ! -f "$FRAMEWORK" ]; then 409 | log_error "Framework \"$FRAMEWORK\" not found!" 410 | exit 1 411 | fi 412 | 413 | "$FRAMEWORK" compile "$BUILD_DIR" "$CACHE_DIR" 414 | 415 | install_node_deps "$BUILD_DIR" 416 | install_composer_deps "$BUILD_DIR" 417 | 418 | LOG_FILES=$(unique_array ${LOG_FILES[@]} ${USER_LOG_FILES[@]}) 419 | if [ -n "$FRAMEWORK" ] && [ -f "$FRAMEWORK" ]; then 420 | FRAMEWORK_LOG_FILES=$("$FRAMEWORK" get-log-files) 421 | LOG_FILES=$(unique_array ${LOG_FILES[@]} ${FRAMEWORK_LOG_FILES[@]}) 422 | fi 423 | 424 | if [ -n "$COMPILE_CMD" ]; then 425 | status "Running compile commands" 426 | while read -r cmd; do 427 | echo "Running '$cmd'" | indent 428 | eval $cmd | indent 429 | done <<< "$COMPILE_CMD" 430 | fi 431 | 432 | if [ -n "$FRAMEWORK" ] && [ -f "$FRAMEWORK" ]; then 433 | "$FRAMEWORK" end "$BUILD_DIR" "$CACHE_DIR" 434 | fi 435 | 436 | "$FRAMEWORK" post-compile "$BUILD_DIR" "$CACHE_DIR" || true 437 | 438 | status "Vendoring binaries into slug" 439 | ADDITIONAL_INSTALLED_LIBS=$(unique_array ${ADDITIONAL_INSTALLED_LIBS[@]}) 440 | 441 | mv /app/vendor/libmcrypt vendor/libmcrypt 442 | mv /app/vendor/libicu vendor/libicu 443 | mv /app/vendor/nginx vendor/nginx 444 | mv /app/vendor/php vendor/php 445 | for lib in $ADDITIONAL_INSTALLED_LIBS; do 446 | LIB_TARGET=$(basename "$lib") 447 | mv "$lib" "vendor/$LIB_TARGET" 448 | done 449 | 450 | mkdir -p "bin" 451 | 452 | cat > "bin/run" <> /app/vendor/php/etc/php-fpm.conf 461 | done 462 | 463 | export DOCUMENT_ROOT="$DOCUMENT_ROOT" 464 | export INDEX_DOCUMENT="$INDEX_DOCUMENT" 465 | export NGINX_INCLUDES="$NGINX_INCLUDES" 466 | 467 | if [ -n "\$NEW_RELIC_LICENSE_KEY" ]; then 468 | echo "newrelic.license=\"\$NEW_RELIC_LICENSE_KEY\"" > /app/vendor/php/etc/conf.d/newrelic_license.ini 469 | fi 470 | 471 | erb conf/nginx.conf.erb > /app/vendor/nginx/conf/nginx.conf 472 | erb conf/site.conf.erb > /app/vendor/nginx/conf/site.conf 473 | 474 | if [[ -z \${WEB_CONCURRENCY:-} ]]; then 475 | maxprocs=\$(ulimit -u) 476 | ram="512M" 477 | if [[ -n \${DYNO:-} && "\$maxprocs" == "32768" ]]; then 478 | echo "Optimizing defaults for PX dyno...." >&2 479 | ram="6G" 480 | ram="2560M" 481 | elif [[ -n ${DYNO:-} && "$maxprocs" == "16384" ]]; then 482 | echo "Optimizing defaults for IX dyno...." >&2 483 | elif [[ -n \${DYNO:-} && "\$maxprocs" == "512" ]]; then 484 | echo "Optimizing defaults for 2X dyno..." >&2 485 | ram="1G" 486 | elif [[ -n \${DYNO:-} && "\$maxprocs" == "256" ]]; then 487 | echo "Optimzing defaults for 1X dyno..." >&2 488 | elif [[ -n \${DYNO:-} || \$verbose ]]; then 489 | echo "No dyno detected; using defaults for 1X..." >&2 490 | fi 491 | 492 | # determine number of FPM processes to run 493 | read WEB_CONCURRENCY php_memory_limit <<<\$(php -c "/app/vendor/php/etc/php.ini" /app/conf/autotune.php -y "/app/vendor/php/etc/php-fpm.conf" -t "\$DOCUMENT_ROOT" "\$ram") 494 | [[ \$WEB_CONCURRENCY -lt 1 ]] && WEB_CONCURRENCY=1 495 | export WEB_CONCURRENCY 496 | 497 | echo "\${WEB_CONCURRENCY} processes at \${php_memory_limit}B memory limit." >&2 498 | else 499 | echo "Using WEB_CONCURRENCY=\${WEB_CONCURRENCY} processes." >&2 500 | fi 501 | 502 | 503 | `init_log_plex ${LOG_FILES}` 504 | `tail_log_plex ${LOG_FILES} ${SYS_LOG_FILES}` 505 | 506 | ( 507 | php-fpm -p "/app/vendor/php" 508 | echo "php-fpm" > \$pmsgr 509 | )& 510 | 511 | ( 512 | nginx -p "/app/vendor/nginx" -c /app/vendor/nginx/conf/nginx.conf 513 | echo "nginx" > \$pmsgr 514 | )& 515 | 516 | 517 | read exitproc <\$pmsgr 518 | echo "Boot failed: \$exitproc" 519 | exit 1 520 | SH 521 | 522 | chmod +x "bin/run" 523 | -------------------------------------------------------------------------------- /bin/compile_node: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # fail fast 4 | set -o pipefail # don't ignore exit codes when piping output 5 | # set -x # enable debugging 6 | 7 | # Configure directories 8 | build_dir=$1 9 | cache_basedir=$2 10 | bp_dir=$(cd $(dirname $0); cd ..; pwd) 11 | 12 | # Load some convenience functions like status() echo(), indent() 13 | source $bp_dir/bin/common.sh 14 | 15 | # Output npm debug info on error 16 | trap cat_npm_debug_log ERR 17 | 18 | # Look in package.json's engines.node field for a semver range 19 | semver_range=$(cat $build_dir/package.json | jq -r .engines.node) 20 | 21 | # Resolve node version using semver.io 22 | semver_url=http://semver.io/node/resolve/$semver_range 23 | node_version=$(curl --silent $semver_url) 24 | 25 | # Recommend using semver ranges in a safe manner 26 | if [ "$semver_range" == "null" ]; then 27 | protip "Specify a node version in package.json" 28 | semver_range="" 29 | elif [ "$semver_range" == "*" ]; then 30 | protip "Avoid using semver ranges like '*' in engines.node" 31 | elif [ ${semver_range:0:1} == ">" ]; then 32 | protip "Avoid using semver ranges starting with '>' in engines.node" 33 | fi 34 | 35 | # Output info about requested range and resolved node version 36 | if [ "$semver_range" == "" ]; then 37 | status "Defaulting to latest stable node: $node_version" 38 | else 39 | status "Requested node range: $semver_range" 40 | status "Resolved node version: $node_version" 41 | fi 42 | 43 | # Download node from Heroku's S3 mirror of nodejs.org/dist 44 | status "Downloading and installing node" 45 | node_url="http://s3pository.heroku.com/node/v$node_version/node-v$node_version-linux-x64.tar.gz" 46 | curl $node_url -s -o - | tar xzf - -C $build_dir 47 | 48 | # Move node into ./vendor and make it executable 49 | mkdir -p $build_dir/vendor 50 | mv $build_dir/node-v$node_version-linux-x64 $build_dir/vendor/node 51 | chmod +x $build_dir/vendor/node/bin/* 52 | PATH=$PATH:$build_dir/vendor/node/bin 53 | 54 | # Run subsequent node/npm commands from the build path 55 | cd $build_dir 56 | 57 | if test -f $build_dir/npm-shrinkwrap.json; then 58 | # Use npm-shrinkwrap.json's checksum as the cachebuster 59 | status "Found npm-shrinkwrap.json" 60 | shrinkwrap_checksum=$(cat $build_dir/npm-shrinkwrap.json | md5sum | awk '{print $1}') 61 | cache_dir="$cache_basedir/$shrinkwrap_checksum" 62 | test -d $cache_dir && status "npm-shrinkwrap.json unchanged since last build" 63 | else 64 | # Fall back to package.json as the cachebuster. 65 | protip "Use npm shrinkwrap to lock down dependency versions" 66 | package_json_checksum=$(cat $build_dir/package.json | md5sum | awk '{print $1}') 67 | cache_dir="$cache_basedir/$package_json_checksum" 68 | test -d $cache_dir && status "package.json unchanged since last build" 69 | fi 70 | 71 | if test -d $cache_dir; then 72 | status "Restoring node_modules from cache" 73 | test -d $cache_dir/node_modules && cp -r $cache_dir/node_modules $build_dir/ 74 | fi 75 | 76 | status "Installing dependencies" 77 | npm install --production 2>&1 | indent 78 | 79 | status "Pruning unused dependencies" 80 | npm prune 2>&1 | indent 81 | 82 | status "Caching node_modules for future builds" 83 | rm -rf $cache_dir 84 | mkdir -p $cache_dir 85 | test -d $build_dir/node_modules && cp -r $build_dir/node_modules $cache_dir/ 86 | 87 | status "Cleaning up node-gyp and npm artifacts" 88 | rm -rf "$build_dir/.node-gyp" 89 | rm -rf "$build_dir/.npm" 90 | 91 | # Update the PATH 92 | status "Building runtime environment" 93 | mkdir -p $build_dir/.profile.d 94 | echo "export PATH=\"\$HOME/vendor/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\"" > $build_dir/.profile.d/nodejs.sh 95 | 96 | # Post package.json to nomnom service 97 | # Use a subshell so it can't break the build. 98 | ( 99 | curl \ 100 | --data @$build_dir/package.json \ 101 | --fail \ 102 | --silent \ 103 | --request POST \ 104 | --header "content-type: application/json" \ 105 | https://nomnom.heroku.com/?request_id=$REQUEST_ID 106 | ) & -------------------------------------------------------------------------------- /bin/detect: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -f "$1/composer.lock" ]; then 4 | echo "PHP (composer.json)" && exit 0 5 | elif [ -f "$1/index.php" ]; then 6 | echo "PHP (classic)" && exit 0 7 | else 8 | exit 1 9 | fi 10 | -------------------------------------------------------------------------------- /bin/release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat << EOF 4 | --- 5 | addons: 6 | config_vars: 7 | PATH: /app/bin:/app/vendor/nginx/sbin:/app/vendor/php/bin:/app/vendor/php/sbin:/usr/local/bin:/usr/bin:/bin 8 | default_process_types: 9 | web: bin/run 10 | EOF 11 | -------------------------------------------------------------------------------- /bin/util/autotune.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | $directives) { 30 | foreach($directives as $key => $value) { 31 | if($section == "www" && $key == "php_admin_value" && isset($value['memory_limit'])) { 32 | $retval['php_admin_value'] = $value['memory_limit']; 33 | } elseif($section == "www" && $key == "php_value" && isset($value['memory_limit']) && !isset($retval['php_value'])) { 34 | // an existing value takes precedence 35 | // we can only emulate that for includes; within the same file, the INI parser overwrites earlier values :( 36 | $retval['php_value'] = $value['memory_limit']; 37 | } elseif($key == "include") { 38 | // values from the include don't overwrite existing values 39 | $retval = array_merge(get_fpm_memory_limit($value, $section), $retval); 40 | } 41 | 42 | if(isset($retval['php_admin_value'])) { 43 | // done for good as nothing can change this anymore, bubble upwards 44 | return $retval; 45 | } 46 | } 47 | } 48 | 49 | return $retval; 50 | } 51 | 52 | $opts = getopt("y:t:"); 53 | 54 | $limits = get_fpm_memory_limit(isset($opts["y"]) ? $opts["y"] : null); 55 | 56 | if( 57 | !$limits /* .user.ini memory limit is ignored if one is set via FPM */ && 58 | isset($opts['t']) && 59 | is_readable($opts['t'].'/.user.ini') 60 | ) { 61 | // we only read the topmost .user.ini inside document root 62 | $userini = parse_ini_file($opts['t'].'/.user.ini'); 63 | if(isset($userini['memory_limit'])) { 64 | $limits['php_value'] = $userini['memory_limit']; 65 | } 66 | } 67 | 68 | if(isset($limits['php_admin_value'])) { 69 | ini_set('memory_limit', $limits['php_admin_value']); 70 | } elseif(isset($limits['php_value'])) { 71 | ini_set('memory_limit', $limits['php_value']); 72 | } 73 | 74 | $limit = ini_get('memory_limit'); 75 | $ram = stringtobytes($argv[$argc-1]); // last arg is the available memory 76 | 77 | // assume 64 MB base overhead for web server and FPM, and 1 MB overhead for each worker 78 | // echo floor(($ram-stringtobytes('64M'))/(stringtobytes($limit)+stringtobytes('1M'))) . " " . $limit; 79 | echo floor($ram / (stringtobytes($limit)?:-1)) . " " . $limit; 80 | 81 | ?> -------------------------------------------------------------------------------- /conf/buildpack.conf: -------------------------------------------------------------------------------- 1 | # Change this to your S3 Bucket if you have custom binaries 2 | S3_BUCKET=chh-heroku-buildpack-php 3 | S3_REGION=eu-west-1 4 | 5 | # Uncomment if you want debug output and set -x 6 | # BUILDPACK_DEBUG=yes 7 | 8 | declare -A PHP_MODULE_API_VERSIONS 9 | PHP_MODULE_API_VERSIONS["5.3"]="20090626" 10 | PHP_MODULE_API_VERSIONS["5.4"]="20100525" 11 | PHP_MODULE_API_VERSIONS["5.5"]="20121212" 12 | 13 | declare -A PHP_EXT_DEPENDENCIES 14 | PHP_EXT_DEPENDENCIES["amqp"]="librabbitmq-0.5.2" 15 | PHP_EXT_DEPENDENCIES["ssh2"]="libssh2-1.4.3" 16 | 17 | declare -A DEPENDENCY_TARGET 18 | DEPENDENCY_TARGET["librabbitmq-0.5.2"]="/app/vendor/librabbitmq" 19 | DEPENDENCY_TARGET["libssh2-1.4.3"]="/app/vendor/libssh2" 20 | -------------------------------------------------------------------------------- /conf/nginx/base.conf.erb: -------------------------------------------------------------------------------- 1 | <% require "shellwords" %> 2 | worker_processes auto; 3 | daemon off; 4 | 5 | events { 6 | worker_connections 1024; 7 | } 8 | http { 9 | # Hide nginx version information. 10 | server_tokens off; 11 | 12 | sendfile on; 13 | tcp_nopush on; 14 | tcp_nodelay off; 15 | 16 | keepalive_timeout 65; 17 | 18 | error_log logs/error.log notice; 19 | access_log logs/access.log; 20 | 21 | client_max_body_size 100m; 22 | client_body_timeout 600s; 23 | 24 | # define the $proxied_https variable based on the forwarded proto as Nginx is not the SSL endpoint 25 | # The name $https cannot be used as the variable is already defined in Nginx core 26 | map $http_x_forwarded_proto $proxied_https { 27 | default off; 28 | https on; 29 | } 30 | 31 | upstream php { 32 | server unix:/tmp/php-fpm.sock max_fails=3 fail_timeout=3s; 33 | keepalive 16; 34 | } 35 | 36 | <% if ENV.has_key? "INDEX_DOCUMENT" and ENV['INDEX_DOCUMENT'].to_s != "" %> 37 | index <%= ENV['INDEX_DOCUMENT'] %> index.html index.htm index.xhtml; 38 | <% else %> 39 | index index.html index.htm index.xhtml; 40 | <% end %> 41 | 42 | include mime.types; 43 | default_type application/octet-stream; 44 | 45 | # Enable Gzip compression. 46 | gzip on; 47 | gzip_http_version 1.0; 48 | gzip_comp_level 5; 49 | gzip_min_length 256; 50 | gzip_proxied any; 51 | gzip_vary on; 52 | gzip_types 53 | application/atom+xml 54 | application/javascript 55 | application/x-javascript 56 | application/json 57 | application/rss+xml 58 | application/vnd.ms-fontobject 59 | application/x-font-ttf 60 | application/x-web-app-manifest+json 61 | application/xhtml+xml 62 | application/xml 63 | font/opentype 64 | image/svg+xml 65 | image/x-icon 66 | text/css 67 | text/plain 68 | text/x-component; 69 | # text/html is always compressed by HttpGzipModule 70 | 71 | server { 72 | server_name localhost; 73 | listen <%= ENV['PORT'] %>; 74 | 75 | #Specify a charset 76 | charset utf-8; 77 | 78 | include site.conf; 79 | 80 | <% Shellwords.split(ENV['NGINX_INCLUDES'].to_s).each do |f| %> 81 | include /app/<%= f %>; 82 | <% end %> 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /conf/nginx/cakephp2.conf.erb: -------------------------------------------------------------------------------- 1 | <% if ENV.has_key? "DOCUMENT_ROOT" and ENV['DOCUMENT_ROOT'].to_s != "" %> 2 | root /app/<%= ENV['DOCUMENT_ROOT'] %>; 3 | <% else %> 4 | root /app/webroot; 5 | <% end %> 6 | 7 | #all locations try other files first and go to our front controller if none of them exists 8 | location / { 9 | try_files $uri $uri/ /<%= ENV['INDEX_DOCUMENT'] %>?$uri&$args; 10 | } 11 | 12 | location ~ \.php$ { 13 | try_files $uri =404; 14 | fastcgi_pass php; 15 | include fastcgi_params; 16 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 17 | fastcgi_buffers 256 4k; 18 | fastcgi_param HTTPS $proxied_https; 19 | } 20 | -------------------------------------------------------------------------------- /conf/nginx/default_site.conf.erb: -------------------------------------------------------------------------------- 1 | # Default configuration for non-framework apps 2 | root /app/<%= ENV['DOCUMENT_ROOT'] %>; 3 | 4 | location ~ \.php$ { 5 | include fastcgi_params; 6 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 7 | fastcgi_pass php; 8 | fastcgi_buffers 256 4k; 9 | fastcgi_param HTTPS $proxied_https; 10 | } 11 | -------------------------------------------------------------------------------- /conf/nginx/magento.conf.erb: -------------------------------------------------------------------------------- 1 | root /app/<%= ENV['DOCUMENT_ROOT'] %>; 2 | 3 | include fastcgi_params; 4 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 5 | fastcgi_param HTTPS $proxied_https; 6 | 7 | # http://alanstorm.com/magento_exception_handling_developer_mode 8 | # fastcgi_param MAGE_IS_DEVELOPER_MODE true; 9 | 10 | location @handler { 11 | rewrite / /index.php; 12 | } 13 | location / { 14 | index index.php index.html; 15 | try_files $uri $uri/ @handler; 16 | expires 30d; 17 | } 18 | location ^~ /app/ { 19 | deny all; 20 | } 21 | location ^~ /includes/ { 22 | deny all; 23 | } 24 | location ^~ /media/downloadable/ { 25 | deny all; 26 | } 27 | location ^~ /pkginfo/ { 28 | deny all; 29 | } 30 | location ^~ /report/config.xml { 31 | deny all; 32 | } 33 | location ^~ /var/ { 34 | deny all; 35 | } 36 | location /. { 37 | return 404; 38 | } 39 | location ~ \.php { 40 | if (!-e $request_filename) { 41 | rewrite / /index.php last; 42 | } 43 | fastcgi_pass php; 44 | } 45 | -------------------------------------------------------------------------------- /conf/nginx/silex.conf.erb: -------------------------------------------------------------------------------- 1 | root /app/<%= ENV['DOCUMENT_ROOT'] %>; 2 | 3 | #site root is redirected to the app boot script 4 | location = / { 5 | try_files @site @site; 6 | } 7 | 8 | #all other locations try other files first and go to our front controller if none of them exists 9 | location / { 10 | try_files $uri $uri/ @site; 11 | } 12 | 13 | #return 404 for all php files as we do have a front controller 14 | location ~ \.php$ { 15 | return 404; 16 | } 17 | 18 | location @site { 19 | fastcgi_pass php; 20 | include fastcgi_params; 21 | fastcgi_param SCRIPT_FILENAME $document_root/<%= ENV['INDEX_DOCUMENT'] %>; 22 | fastcgi_buffers 256 4k; 23 | fastcgi_param HTTPS $proxied_https; 24 | } 25 | -------------------------------------------------------------------------------- /conf/nginx/slim.conf.erb: -------------------------------------------------------------------------------- 1 | # Default configuration for non-framework apps 2 | root /app/<%= ENV['DOCUMENT_ROOT'] %>; 3 | 4 | try_files $uri /index.php?$args; 5 | 6 | # this will only pass index.php to the fastcgi process which is generally safer but 7 | # assumes the whole site is run via Slim. 8 | location /index.php { 9 | include fastcgi_params; 10 | fastcgi_buffers 256 4k; 11 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 12 | fastcgi_pass php; 13 | fastcgi_param HTTPS $proxied_https; 14 | } 15 | -------------------------------------------------------------------------------- /conf/nginx/symfony2.conf.erb: -------------------------------------------------------------------------------- 1 | <% if ENV.has_key? "DOCUMENT_ROOT" and ENV['DOCUMENT_ROOT'].to_s != "" %> 2 | root /app/<%= ENV['DOCUMENT_ROOT'] %>; 3 | <% else %> 4 | root /app/web; 5 | <% end %> 6 | 7 | location / { 8 | # try to serve file directly, fallback to rewrite 9 | try_files $uri @rewriteapp; 10 | } 11 | 12 | location @rewriteapp { 13 | # rewrite all to app.php 14 | rewrite ^(.*)$ /app.php/$1 last; 15 | } 16 | 17 | location ~ ^/(app|app_dev|config)\.php(/|$) { 18 | fastcgi_pass php; 19 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 20 | include fastcgi_params; 21 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 22 | fastcgi_param HTTPS $proxied_https; 23 | 24 | fastcgi_buffer_size 128k; 25 | fastcgi_buffers 4 256k; 26 | fastcgi_busy_buffers_size 256k; 27 | } 28 | -------------------------------------------------------------------------------- /conf/nginx/yii.conf.erb: -------------------------------------------------------------------------------- 1 | <% if ENV.has_key? "DOCUMENT_ROOT" and ENV['DOCUMENT_ROOT'].to_s != "" %> 2 | root /app/<%= ENV['DOCUMENT_ROOT'] %>; 3 | <% else %> 4 | root /app; 5 | <% end %> 6 | 7 | # Attempt the uri, uri+/, then fall back to yii's index.php with args included 8 | location / { 9 | try_files $uri $uri/ /<%= ENV['INDEX_DOCUMENT'] %>?$args; 10 | } 11 | 12 | # Prevent access to yii protected directories 13 | location ~ ^/(protected|framework|themes/\w+/views) { 14 | deny all; 15 | } 16 | 17 | location ~ \.php { 18 | include fastcgi_params; 19 | fastcgi_buffers 256 4k; 20 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 21 | fastcgi_param HTTPS $proxied_https; 22 | fastcgi_pass php; 23 | } 24 | -------------------------------------------------------------------------------- /conf/nginx/zf1.conf.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CHH/heroku-buildpack-php/f5cd66588de126057254a069ff2308b91feaaed8/conf/nginx/zf1.conf.erb -------------------------------------------------------------------------------- /conf/nginx/zf2.conf.erb: -------------------------------------------------------------------------------- 1 | <% if ENV.has_key? "DOCUMENT_ROOT" and ENV['DOCUMENT_ROOT'].to_s != "" %> 2 | root /app/<%= ENV['DOCUMENT_ROOT'] %>; 3 | <% else %> 4 | root /app/public; 5 | <% end %> 6 | 7 | try_files $uri /index.php?$args; 8 | 9 | # this will only pass index.php to the fastcgi process which is generally safer but 10 | # assumes the whole site is run via Zend 2. 11 | location /index.php { 12 | include fastcgi_params; 13 | fastcgi_buffers 256 4k; 14 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 15 | fastcgi_param HTTPS $proxied_https; 16 | fastcgi_pass php; 17 | } 18 | -------------------------------------------------------------------------------- /conf/php/newrelic.ini: -------------------------------------------------------------------------------- 1 | extension=newrelic.so 2 | newrelic.appname=${NEW_RELIC_APP_NAME} 3 | newrelic.license=${NEW_RELIC_LICENSE_KEY} 4 | newrelic.logfile=${NEW_RELIC_LOG} 5 | newrelic.daemon.logfile=${NEW_RELIC_LOG} 6 | newrelic.daemon.location=/app/vendor/newrelic/bin/newrelic-daemon 7 | -------------------------------------------------------------------------------- /conf/php/php-fpm.conf: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;; 2 | ; FPM Configuration ; 3 | ;;;;;;;;;;;;;;;;;;;;; 4 | 5 | ; All relative paths in this configuration file are relative to PHP's install 6 | ; prefix. This prefix can be dynamicaly changed by using the 7 | ; '-p' argument from the command line. 8 | 9 | ; Include one or more files. If glob(3) exists, it is used to include a bunch of 10 | ; files from a glob(3) pattern. This directive can be used everywhere in the 11 | ; file. 12 | ; Relative path can also be used. They will be prefixed by: 13 | ; - the global prefix if it's been set (-p arguement) 14 | ; - the compile-time prefix otherwise 15 | ;include=etc/fpm.d/*.conf 16 | 17 | ;;;;;;;;;;;;;;;;;; 18 | ; Global Options ; 19 | ;;;;;;;;;;;;;;;;;; 20 | 21 | [global] 22 | ; Pid file 23 | ; Default Value: none 24 | ;pid = var/run/php-fpm.pid 25 | 26 | ; Error log file 27 | ; If it's set to "syslog", log is sent to syslogd instead of being written 28 | ; in a local file. 29 | ; Default Value: log/php-fpm.log 30 | error_log = var/log/error.log 31 | 32 | ; syslog_facility is used to specify what type of program is logging the 33 | ; message. This lets syslogd specify that messages from different facilities 34 | ; will be handled differently. 35 | ; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) 36 | ; Default Value: daemon 37 | ;syslog.facility = daemon 38 | 39 | ; syslog_ident is prepended to every message. If you have multiple FPM 40 | ; instances running on the same server, you can change the default value 41 | ; which must suit common needs. 42 | ; Default Value: php-fpm 43 | ;syslog.ident = php-fpm 44 | 45 | ; Log level 46 | ; Possible Values: alert, error, warning, notice, debug 47 | ; Default Value: notice 48 | ;log_level = notice 49 | 50 | ; If this number of child processes exit with SIGSEGV or SIGBUS within the time 51 | ; interval set by emergency_restart_interval then FPM will restart. A value 52 | ; of '0' means 'Off'. 53 | ; Default Value: 0 54 | ;emergency_restart_threshold = 0 55 | 56 | ; Interval of time used by emergency_restart_interval to determine when 57 | ; a graceful restart will be initiated. This can be useful to work around 58 | ; accidental corruptions in an accelerator's shared memory. 59 | ; Available Units: s(econds), m(inutes), h(ours), or d(ays) 60 | ; Default Unit: seconds 61 | ; Default Value: 0 62 | ;emergency_restart_interval = 0 63 | 64 | ; Time limit for child processes to wait for a reaction on signals from master. 65 | ; Available units: s(econds), m(inutes), h(ours), or d(ays) 66 | ; Default Unit: seconds 67 | ; Default Value: 0 68 | ;process_control_timeout = 0 69 | 70 | ; The maximum number of processes FPM will fork. This has been design to control 71 | ; the global number of processes when using dynamic PM within a lot of pools. 72 | ; Use it with caution. 73 | ; Note: A value of 0 indicates no limit 74 | ; Default Value: 0 75 | ;process.max = 128 76 | 77 | ; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. 78 | ; Default Value: yes 79 | daemonize = no 80 | 81 | ; Set open file descriptor rlimit for the master process. 82 | ; Default Value: system defined value 83 | ;rlimit_files = 1024 84 | 85 | ; Set max core size rlimit for the master process. 86 | ; Possible Values: 'unlimited' or an integer greater or equal to 0 87 | ; Default Value: system defined value 88 | ;rlimit_core = 0 89 | 90 | ; Specify the event mechanism FPM will use. The following is available: 91 | ; - select (any POSIX os) 92 | ; - poll (any POSIX os) 93 | ; - epoll (linux >= 2.5.44) 94 | ; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) 95 | ; - /dev/poll (Solaris >= 7) 96 | ; - port (Solaris >= 10) 97 | ; Default Value: not set (auto detection) 98 | ;events.mechanism = epoll 99 | 100 | ;;;;;;;;;;;;;;;;;;;; 101 | ; Pool Definitions ; 102 | ;;;;;;;;;;;;;;;;;;;; 103 | 104 | ; Multiple pools of child processes may be started with different listening 105 | ; ports and different management options. The name of the pool will be 106 | ; used in logs and stats. There is no limitation on the number of pools which 107 | ; FPM can handle. Your system will tell you anyway :) 108 | 109 | ; Start a new pool named 'web'. 110 | ; the variable $pool can we used in any directive and will be replaced by the 111 | ; pool name ('web' here) 112 | [web] 113 | 114 | ; Per pool prefix 115 | ; It only applies on the following directives: 116 | ; - 'slowlog' 117 | ; - 'listen' (unixsocket) 118 | ; - 'chroot' 119 | ; - 'chdir' 120 | ; - 'php_values' 121 | ; - 'php_admin_values' 122 | ; When not set, the global prefix (or the compile-time prefix) applies instead. 123 | ; Note: This directive can also be relative to the global prefix. 124 | ; Default Value: none 125 | ;prefix = /path/to/pools/$pool 126 | 127 | ; Unix user/group of processes 128 | ; Note: The user is mandatory. If the group is not set, the default user's group 129 | ; will be used. 130 | user = nobody 131 | ;group = nobody 132 | 133 | ; The address on which to accept FastCGI requests. 134 | ; Valid syntaxes are: 135 | ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on 136 | ; a specific port; 137 | ; 'port' - to listen on a TCP socket to all addresses on a 138 | ; specific port; 139 | ; '/path/to/unix/socket' - to listen on a unix socket. 140 | ; Note: This value is mandatory. 141 | listen = /tmp/php-fpm.sock 142 | 143 | ; Set listen(2) backlog. A value of '-1' means unlimited. 144 | ; Default Value: 128 (-1 on FreeBSD and OpenBSD) 145 | ;listen.backlog = -1 146 | 147 | ; Set permissions for unix socket, if one is used. In Linux, read/write 148 | ; permissions must be set in order to allow connections from a web server. Many 149 | ; BSD-derived systems allow connections regardless of permissions. 150 | ; Default Values: user and group are set as the running user 151 | ; mode is set to 0666 152 | ;listen.owner = nobody 153 | ;listen.group = nobody 154 | ;listen.mode = 0666 155 | 156 | ; List of ipv4 addresses of FastCGI clients which are allowed to connect. 157 | ; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original 158 | ; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address 159 | ; must be separated by a comma. If this value is left blank, connections will be 160 | ; accepted from any ip address. 161 | ; Default Value: any 162 | ;listen.allowed_clients = 127.0.0.1 163 | 164 | ; Choose how the process manager will control the number of child processes. 165 | ; Possible Values: 166 | ; static - a fixed number (pm.max_children) of child processes; 167 | ; dynamic - the number of child processes are set dynamically based on the 168 | ; following directives. With this process management, there will be 169 | ; always at least 1 children. 170 | ; pm.max_children - the maximum number of children that can 171 | ; be alive at the same time. 172 | ; pm.start_servers - the number of children created on startup. 173 | ; pm.min_spare_servers - the minimum number of children in 'idle' 174 | ; state (waiting to process). If the number 175 | ; of 'idle' processes is less than this 176 | ; number then some children will be created. 177 | ; pm.max_spare_servers - the maximum number of children in 'idle' 178 | ; state (waiting to process). If the number 179 | ; of 'idle' processes is greater than this 180 | ; number then some children will be killed. 181 | ; ondemand - no children are created at startup. Children will be forked when 182 | ; new requests will connect. The following parameter are used: 183 | ; pm.max_children - the maximum number of children that 184 | ; can be alive at the same time. 185 | ; pm.process_idle_timeout - The number of seconds after which 186 | ; an idle process will be killed. 187 | ; Note: This value is mandatory. 188 | pm = dynamic 189 | 190 | ; The number of child processes to be created when pm is set to 'static' and the 191 | ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. 192 | ; This value sets the limit on the number of simultaneous requests that will be 193 | ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. 194 | ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP 195 | ; CGI. The below defaults are based on a server without much resources. Don't 196 | ; forget to tweak pm.* to fit your needs. 197 | ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' 198 | ; Note: This value is mandatory. 199 | pm.max_children = ${WEB_CONCURRENCY} 200 | 201 | ; The number of child processes created on startup. 202 | ; Note: Used only when pm is set to 'dynamic' 203 | ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 204 | ;pm.start_servers = 2 205 | 206 | ; The desired minimum number of idle server processes. 207 | ; Note: Used only when pm is set to 'dynamic' 208 | ; Note: Mandatory when pm is set to 'dynamic' 209 | pm.min_spare_servers = 1 210 | 211 | ; The desired maximum number of idle server processes. 212 | ; Note: Used only when pm is set to 'dynamic' 213 | ; Note: Mandatory when pm is set to 'dynamic' 214 | pm.max_spare_servers = 2 215 | 216 | ; The number of seconds after which an idle process will be killed. 217 | ; Note: Used only when pm is set to 'ondemand' 218 | ; Default Value: 10s 219 | ;pm.process_idle_timeout = 10s; 220 | 221 | ; The number of requests each child process should execute before respawning. 222 | ; This can be useful to work around memory leaks in 3rd party libraries. For 223 | ; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. 224 | ; Default Value: 0 225 | pm.max_requests = 0 226 | 227 | ; The URI to view the FPM status page. If this value is not set, no URI will be 228 | ; recognized as a status page. It shows the following informations: 229 | ; pool - the name of the pool; 230 | ; process manager - static, dynamic or ondemand; 231 | ; start time - the date and time FPM has started; 232 | ; start since - number of seconds since FPM has started; 233 | ; accepted conn - the number of request accepted by the pool; 234 | ; listen queue - the number of request in the queue of pending 235 | ; connections (see backlog in listen(2)); 236 | ; max listen queue - the maximum number of requests in the queue 237 | ; of pending connections since FPM has started; 238 | ; listen queue len - the size of the socket queue of pending connections; 239 | ; idle processes - the number of idle processes; 240 | ; active processes - the number of active processes; 241 | ; total processes - the number of idle + active processes; 242 | ; max active processes - the maximum number of active processes since FPM 243 | ; has started; 244 | ; max children reached - number of times, the process limit has been reached, 245 | ; when pm tries to start more children (works only for 246 | ; pm 'dynamic' and 'ondemand'); 247 | ; Value are updated in real time. 248 | ; Example output: 249 | ; pool: www 250 | ; process manager: static 251 | ; start time: 01/Jul/2011:17:53:49 +0200 252 | ; start since: 62636 253 | ; accepted conn: 190460 254 | ; listen queue: 0 255 | ; max listen queue: 1 256 | ; listen queue len: 42 257 | ; idle processes: 4 258 | ; active processes: 11 259 | ; total processes: 15 260 | ; max active processes: 12 261 | ; max children reached: 0 262 | ; 263 | ; By default the status page output is formatted as text/plain. Passing either 264 | ; 'html', 'xml' or 'json' in the query string will return the corresponding 265 | ; output syntax. Example: 266 | ; http://www.foo.bar/status 267 | ; http://www.foo.bar/status?json 268 | ; http://www.foo.bar/status?html 269 | ; http://www.foo.bar/status?xml 270 | ; 271 | ; By default the status page only outputs short status. Passing 'full' in the 272 | ; query string will also return status for each pool process. 273 | ; Example: 274 | ; http://www.foo.bar/status?full 275 | ; http://www.foo.bar/status?json&full 276 | ; http://www.foo.bar/status?html&full 277 | ; http://www.foo.bar/status?xml&full 278 | ; The Full status returns for each process: 279 | ; pid - the PID of the process; 280 | ; state - the state of the process (Idle, Running, ...); 281 | ; start time - the date and time the process has started; 282 | ; start since - the number of seconds since the process has started; 283 | ; requests - the number of requests the process has served; 284 | ; request duration - the duration in µs of the requests; 285 | ; request method - the request method (GET, POST, ...); 286 | ; request URI - the request URI with the query string; 287 | ; content length - the content length of the request (only with POST); 288 | ; user - the user (PHP_AUTH_USER) (or '-' if not set); 289 | ; script - the main script called (or '-' if not set); 290 | ; last request cpu - the %cpu the last request consumed 291 | ; it's always 0 if the process is not in Idle state 292 | ; because CPU calculation is done when the request 293 | ; processing has terminated; 294 | ; last request memory - the max amount of memory the last request consumed 295 | ; it's always 0 if the process is not in Idle state 296 | ; because memory calculation is done when the request 297 | ; processing has terminated; 298 | ; If the process is in Idle state, then informations are related to the 299 | ; last request the process has served. Otherwise informations are related to 300 | ; the current request being served. 301 | ; Example output: 302 | ; ************************ 303 | ; pid: 31330 304 | ; state: Running 305 | ; start time: 01/Jul/2011:17:53:49 +0200 306 | ; start since: 63087 307 | ; requests: 12808 308 | ; request duration: 1250261 309 | ; request method: GET 310 | ; request URI: /test_mem.php?N=10000 311 | ; content length: 0 312 | ; user: - 313 | ; script: /home/fat/web/docs/php/test_mem.php 314 | ; last request cpu: 0.00 315 | ; last request memory: 0 316 | ; 317 | ; Note: The value must start with a leading slash (/). The value can be 318 | ; anything, but it may not be a good idea to use the .php extension or it 319 | ; may conflict with a real PHP file. 320 | ; Default Value: not set 321 | ;pm.status_path = /status 322 | 323 | ; The ping URI to call the monitoring page of FPM. If this value is not set, no 324 | ; URI will be recognized as a ping page. This could be used to test from outside 325 | ; that FPM is alive and responding, or to 326 | ; - create a graph of FPM availability (rrd or such); 327 | ; - remove a server from a group if it is not responding (load balancing); 328 | ; - trigger alerts for the operating team (24/7). 329 | ; Note: The value must start with a leading slash (/). The value can be 330 | ; anything, but it may not be a good idea to use the .php extension or it 331 | ; may conflict with a real PHP file. 332 | ; Default Value: not set 333 | ping.path = /ping 334 | 335 | ; This directive may be used to customize the response of a ping request. The 336 | ; response is formatted as text/plain with a 200 response code. 337 | ; Default Value: pong 338 | ;ping.response = pong 339 | 340 | ; The access log file 341 | ; Default: not set 342 | ;access.log = var/log/access.log 343 | 344 | ; The access log format. 345 | ; The following syntax is allowed 346 | ; %%: the '%' character 347 | ; %C: %CPU used by the request 348 | ; it can accept the following format: 349 | ; - %{user}C for user CPU only 350 | ; - %{system}C for system CPU only 351 | ; - %{total}C for user + system CPU (default) 352 | ; %d: time taken to serve the request 353 | ; it can accept the following format: 354 | ; - %{seconds}d (default) 355 | ; - %{miliseconds}d 356 | ; - %{mili}d 357 | ; - %{microseconds}d 358 | ; - %{micro}d 359 | ; %e: an environment variable (same as $_ENV or $_SERVER) 360 | ; it must be associated with embraces to specify the name of the env 361 | ; variable. Some exemples: 362 | ; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e 363 | ; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e 364 | ; %f: script filename 365 | ; %l: content-length of the request (for POST request only) 366 | ; %m: request method 367 | ; %M: peak of memory allocated by PHP 368 | ; it can accept the following format: 369 | ; - %{bytes}M (default) 370 | ; - %{kilobytes}M 371 | ; - %{kilo}M 372 | ; - %{megabytes}M 373 | ; - %{mega}M 374 | ; %n: pool name 375 | ; %o: ouput header 376 | ; it must be associated with embraces to specify the name of the header: 377 | ; - %{Content-Type}o 378 | ; - %{X-Powered-By}o 379 | ; - %{Transfert-Encoding}o 380 | ; - .... 381 | ; %p: PID of the child that serviced the request 382 | ; %P: PID of the parent of the child that serviced the request 383 | ; %q: the query string 384 | ; %Q: the '?' character if query string exists 385 | ; %r: the request URI (without the query string, see %q and %Q) 386 | ; %R: remote IP address 387 | ; %s: status (response code) 388 | ; %t: server time the request was received 389 | ; it can accept a strftime(3) format: 390 | ; %d/%b/%Y:%H:%M:%S %z (default) 391 | ; %T: time the log has been written (the request has finished) 392 | ; it can accept a strftime(3) format: 393 | ; %d/%b/%Y:%H:%M:%S %z (default) 394 | ; %u: remote user 395 | ; 396 | ; Default: "%R - %u %t \"%m %r\" %s" 397 | ;access.format = %R - %u %t "%m %r%Q%q" %s %f %{mili}d %{kilo}M %C%% 398 | 399 | ; The log file for slow requests 400 | ; Default Value: not set 401 | ; Note: slowlog is mandatory if request_slowlog_timeout is set 402 | ;slowlog = log/slow.log 403 | 404 | ; The timeout for serving a single request after which a PHP backtrace will be 405 | ; dumped to the 'slowlog' file. A value of '0s' means 'off'. 406 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) 407 | ; Default Value: 0 408 | ;request_slowlog_timeout = 0 409 | 410 | ; The timeout for serving a single request after which the worker process will 411 | ; be killed. This option should be used when the 'max_execution_time' ini option 412 | ; does not stop script execution for some reason. A value of '0' means 'off'. 413 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) 414 | ; Default Value: 0 415 | ;request_terminate_timeout = 0 416 | 417 | ; Set open file descriptor rlimit. 418 | ; Default Value: system defined value 419 | ;rlimit_files = 1024 420 | 421 | ; Set max core size rlimit. 422 | ; Possible Values: 'unlimited' or an integer greater or equal to 0 423 | ; Default Value: system defined value 424 | ;rlimit_core = 0 425 | 426 | ; Chroot to this directory at the start. This value must be defined as an 427 | ; absolute path. When this value is not set, chroot is not used. 428 | ; Note: you can prefix with '$prefix' to chroot to the pool prefix or one 429 | ; of its subdirectories. If the pool prefix is not set, the global prefix 430 | ; will be used instead. 431 | ; Note: chrooting is a great security feature and should be used whenever 432 | ; possible. However, all PHP paths will be relative to the chroot 433 | ; (error_log, sessions.save_path, ...). 434 | ; Default Value: not set 435 | ;chroot = 436 | 437 | ; Chdir to this directory at the start. 438 | ; Note: relative path can be used. 439 | ; Default Value: current directory or / when chroot 440 | ;chdir = /var/www 441 | 442 | ; Redirect worker stdout and stderr into main error log. If not set, stdout and 443 | ; stderr will be redirected to /dev/null according to FastCGI specs. 444 | ; Note: on highloaded environement, this can cause some delay in the page 445 | ; process time (several ms). 446 | ; Default Value: no 447 | ;catch_workers_output = yes 448 | 449 | ; Limits the extensions of the main script FPM will allow to parse. This can 450 | ; prevent configuration mistakes on the web server side. You should only limit 451 | ; FPM to .php extensions to prevent malicious users to use other extensions to 452 | ; exectute php code. 453 | ; Note: set an empty value to allow all extensions. 454 | ; Default Value: .php 455 | ;security.limit_extensions = .php .php3 .php4 .php5 456 | 457 | ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from 458 | ; the current environment. 459 | ; Default Value: clean env 460 | ;env[HOSTNAME] = $HOSTNAME 461 | ;env[PATH] = /usr/local/bin:/usr/bin:/bin 462 | ;env[TMP] = /tmp 463 | ;env[TMPDIR] = /tmp 464 | 465 | ; Additional php.ini defines, specific to this pool of workers. These settings 466 | ; overwrite the values previously defined in the php.ini. The directives are the 467 | ; same as the PHP SAPI: 468 | ; php_value/php_flag - you can set classic ini defines which can 469 | ; be overwritten from PHP call 'ini_set'. 470 | ; php_admin_value/php_admin_flag - these directives won't be overwritten by 471 | ; PHP call 'ini_set' 472 | ; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. 473 | 474 | ; Defining 'extension' will load the corresponding shared extension from 475 | ; extension_dir. Defining 'disable_functions' or 'disable_classes' will not 476 | ; overwrite previously defined php.ini values, but will append the new value 477 | ; instead. 478 | 479 | ; Note: path INI options can be relative and will be expanded with the prefix 480 | ; (pool, global or compile-time prefix) 481 | 482 | ; Default Value: nothing is defined by default except the values in php.ini and 483 | ; specified at startup with the -d argument 484 | ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com 485 | ;php_flag[display_errors] = off 486 | ;php_admin_value[error_log] = /var/log/fpm-php.www.log 487 | ;php_admin_flag[log_errors] = on 488 | ;php_admin_value[memory_limit] = 32M 489 | -------------------------------------------------------------------------------- /conf/php/php.ini: -------------------------------------------------------------------------------- 1 | ; Logging 2 | display_errors=off 3 | log_errors=on 4 | error_reporting=E_ALL | E_STRICT 5 | 6 | ; Required timezone 7 | date.timezone = UTC 8 | 9 | ; Security 10 | expose_php=off 11 | cgi.fix_pathinfo=0 12 | 13 | memory_limit=128M 14 | 15 | ; Opcache 16 | opcache.memory_consumption=128 17 | opcache.interned_strings_buffer=8 18 | opcache.max_accelerated_files=4000 19 | opcache.validate_timestamps=off 20 | opcache.fast_shutdown=0 21 | opcache.enable_cli=1 22 | -------------------------------------------------------------------------------- /frameworks/cakephp2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="$2" 4 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 5 | source $basedir/../bin/common.sh 6 | 7 | function requires_cakephp2_pear() { 8 | [ $(jq --raw-output '.require["pear-pear.cakephp.org/CakePHP"]' < "$BUILD_DIR/composer.json") != "null" ] 9 | } 10 | 11 | function requires_cakephp2_composer() { 12 | [ $(jq --raw-output '.require["cakephp/cakephp"]' < "$BUILD_DIR/composer.json") != "null" ] 13 | } 14 | 15 | function sets_framework_cakephp2() { 16 | [ $(jq --raw-output '.extra.heroku.framework' < "$BUILD_DIR/composer.json") == "cakephp2" ] 17 | } 18 | 19 | case "$1" in 20 | detect) 21 | if [ ! -f "$BUILD_DIR/composer.json" ]; then 22 | exit 1 23 | fi 24 | 25 | if requires_cakephp2_pear || requires_cakephp2_composer || sets_framework_cakephp2; then 26 | echo "-----> Detected CakePHP2 App" 27 | exit 0 28 | else 29 | exit 1 30 | fi 31 | ;; 32 | get-log-files) 33 | echo "/app/tmp/logs/debug.log" "/app/tmp/logs/error.log" 34 | ;; 35 | compile) 36 | echo "-----> Setting up CakePHP2 app" 37 | cp "$basedir/../conf/nginx/cakephp2.conf.erb" "$BUILD_DIR/conf/site.conf.erb" 38 | ;; 39 | esac 40 | -------------------------------------------------------------------------------- /frameworks/default: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="$2" 4 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 5 | 6 | case "$1" in 7 | detect) 8 | exit 1 9 | ;; 10 | compile) 11 | echo "-----> Setting up default configuration" 12 | cp "$basedir/../conf/nginx/default_site.conf.erb" "$BUILD_DIR/conf/site.conf.erb" 13 | ;; 14 | esac 15 | -------------------------------------------------------------------------------- /frameworks/magento: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="$2" 4 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 5 | 6 | function sets_framework_magento() { 7 | [ $(jq --raw-output '.extra.heroku.framework' < "$BUILD_DIR/composer.json") == "magento" ] 8 | } 9 | 10 | case "$1" in 11 | detect) 12 | if [ ! -f "$BUILD_DIR/composer.json" ]; then 13 | exit 1 14 | fi 15 | 16 | if sets_framework_magento; then 17 | echo "-----> Detected Magento app" 18 | exit 0 19 | else 20 | exit 1 21 | fi 22 | ;; 23 | compile) 24 | echo "-----> Setting up Magento app" 25 | cp "$basedir/../conf/nginx/magento.conf.erb" "$BUILD_DIR/conf/site.conf.erb" 26 | ;; 27 | esac 28 | -------------------------------------------------------------------------------- /frameworks/silex: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="$2" 4 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 5 | 6 | function requires_silex() { 7 | jq --raw-output '.packages | .[] | .name' < "$BUILD_DIR/composer.lock" | grep -q '^silex/silex$' 8 | } 9 | 10 | function sets_framework_silex() { 11 | [ $(jq --raw-output '.extra.heroku.framework' < "$BUILD_DIR/composer.json") == "silex" ] 12 | } 13 | 14 | case "$1" in 15 | detect) 16 | if [ ! -f "$BUILD_DIR/composer.json" ]; then 17 | exit 1 18 | fi 19 | 20 | if requires_silex || sets_framework_silex; then 21 | echo "-----> Detected Silex app" 22 | exit 0 23 | else 24 | exit 1 25 | fi 26 | ;; 27 | compile) 28 | echo "-----> Setting up Silex app" 29 | cp "$basedir/../conf/nginx/silex.conf.erb" "$BUILD_DIR/conf/site.conf.erb" 30 | ;; 31 | esac 32 | -------------------------------------------------------------------------------- /frameworks/slim: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="$2" 4 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 5 | 6 | function requires_slim() { 7 | jq --raw-output '.packages | .[] | .name' < "$BUILD_DIR/composer.lock" | grep -q '^slim/slim$' 8 | } 9 | 10 | function sets_framework_slim() { 11 | [ $(jq --raw-output '.extra.heroku.framework' < "$BUILD_DIR/composer.json") == "slim" ] 12 | } 13 | 14 | case "$1" in 15 | detect) 16 | if [ ! -f "$BUILD_DIR/composer.json" ]; then 17 | exit 1 18 | fi 19 | 20 | if requires_slim || sets_framework_slim; then 21 | echo "-----> Detected Slim app" 22 | exit 0 23 | else 24 | exit 1 25 | fi 26 | ;; 27 | compile) 28 | echo "-----> Setting up Slim app" 29 | cp "$basedir/../conf/nginx/slim.conf.erb" "$BUILD_DIR/conf/site.conf.erb" 30 | ;; 31 | esac 32 | -------------------------------------------------------------------------------- /frameworks/symfony2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="$2" 4 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 5 | source $basedir/../bin/common.sh 6 | 7 | function requires_symfony2() { 8 | jq --raw-output '.packages | .[] | .name' < "$BUILD_DIR/composer.lock" | grep -q '^symfony/symfony$' 9 | } 10 | 11 | function sets_framework_symfony2() { 12 | [ $(jq --raw-output '.extra.heroku.framework' < "$BUILD_DIR/composer.json") == "symfony2" ] 13 | } 14 | 15 | case "$1" in 16 | detect) 17 | if [ ! -f "$BUILD_DIR/composer.json" ]; then 18 | exit 1 19 | fi 20 | 21 | if requires_symfony2 || sets_framework_symfony2; then 22 | echo "-----> Detected Symfony2 App" 23 | exit 0 24 | else 25 | exit 1 26 | fi 27 | ;; 28 | get-log-files) 29 | echo "app/logs/prod.log" "app/logs/dev.log" 30 | ;; 31 | compile) 32 | echo "-----> Setting up Symfony2 app" 33 | cp "$basedir/../conf/nginx/symfony2.conf.erb" "$BUILD_DIR/conf/site.conf.erb" 34 | ;; 35 | end) 36 | BUILD_DIR="$1" 37 | CACHE_DIR="$2" 38 | APP_DIR="/app" 39 | 40 | status "Warming up cache" 41 | rm -rf app/cache/* 42 | php app/console cache:warmup --env=prod --no-debug | indent 43 | 44 | 45 | status "In-place replacement of $CACHE_DIR to $APP_DIR" 46 | find $CACHE_DIR/app/cache/prod -type f -exec sed -i "s@$CACHE_DIR@$APP_DIR@g" {} \; | indent 47 | grep $CACHE_DIR/app/cache/prod -r . && error "Could find some '$CACHE_DIR' :/ " 48 | 49 | status "End" 50 | ;; 51 | esac 52 | -------------------------------------------------------------------------------- /frameworks/yii: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="$2" 4 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 5 | 6 | function requires_yii() { 7 | jq --raw-output '.packages | .[] | .name' < "$BUILD_DIR/composer.lock" | grep -q '^yiisoft/yii$' 8 | } 9 | 10 | function sets_framework_yii() { 11 | [ $(jq --raw-output '.extra.heroku.framework' < "$BUILD_DIR/composer.json") == "yii" ] 12 | } 13 | 14 | case "$1" in 15 | detect) 16 | if [ ! -f "$BUILD_DIR/composer.json" ]; then 17 | exit 1 18 | fi 19 | 20 | if requires_yii || sets_framework_yii; then 21 | echo "-----> Detected Yii app" 22 | exit 0 23 | else 24 | exit 1 25 | fi 26 | ;; 27 | compile) 28 | echo "-----> Setting up Yii app" 29 | cp "$basedir/../conf/nginx/yii.conf.erb" "$BUILD_DIR/conf/site.conf.erb" 30 | ;; 31 | esac 32 | -------------------------------------------------------------------------------- /frameworks/zf2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="$2" 4 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 5 | 6 | function requires_zf2() { 7 | jq --raw-output '.packages | .[] | .name' < "$BUILD_DIR/composer.lock" | grep -q '^zendframework/zendframework$' 8 | } 9 | 10 | function sets_framework_zf2() { 11 | [ $(jq --raw-output '.extra.heroku.framework' < "$BUILD_DIR/composer.json") == "zf2" ] 12 | } 13 | 14 | case "$1" in 15 | detect) 16 | if [ ! -f "$BUILD_DIR/composer.json" ]; then 17 | exit 1 18 | fi 19 | 20 | if requires_zf2 || sets_framework_zf2; then 21 | echo "-----> Detected Zend2 app" 22 | exit 0 23 | else 24 | exit 1 25 | fi 26 | ;; 27 | compile) 28 | echo "-----> Setting up Zend2 app" 29 | cp "$basedir/../conf/nginx/zf2.conf.erb" "$BUILD_DIR/conf/site.conf.erb" 30 | ;; 31 | esac 32 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | https://github.com/s3tools/s3cmd/archive/v1.5.2.zip 2 | -------------------------------------------------------------------------------- /support/ext/amqp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | amqp_version=1.6.0beta2 7 | librabbitmq_version=0.5.2 8 | 9 | mkdir -p /app/vendor/librabbitmq 10 | curl "http://${S3_BUCKET}.s3.amazonaws.com/package/librabbitmq-${librabbitmq_version}.tgz" | tar xzv -C /app/vendor/librabbitmq 11 | 12 | curl -L "http://pecl.php.net/get/amqp-${amqp_version}.tgz" \ 13 | | tar xzv 14 | 15 | cd amqp-${amqp_version} 16 | /app/vendor/php/bin/phpize 17 | ./configure --with-php-config=/app/vendor/php/bin/php-config \ 18 | --with-librabbitmq-dir=/app/vendor/librabbitmq \ 19 | --with-amqp 20 | 21 | make 22 | cp modules/amqp.so "$EXT_DIR/amqp.so" 23 | echo "extension=amqp.so" > "$PREFIX/etc/conf.d/amqp.ini" 24 | -------------------------------------------------------------------------------- /support/ext/apcu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | apcu_version=4.0.2 7 | 8 | curl -L "http://pecl.php.net/get/apcu-${apcu_version}.tgz" \ 9 | | tar xzv 10 | 11 | cd apcu-${apcu_version} 12 | /app/vendor/php/bin/phpize 13 | ./configure --with-php-config=/app/vendor/php/bin/php-config 14 | 15 | make 16 | cp modules/apcu.so "$EXT_DIR/apcu.so" 17 | echo "extension=apcu.so" > "$PREFIX/etc/conf.d/apcu.ini" 18 | -------------------------------------------------------------------------------- /support/ext/igbinary: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | igbinary_version="1.1.1" 7 | 8 | curl -L "https://github.com/igbinary/igbinary/archive/${igbinary_version}.tar.gz" \ 9 | | tar xzv 10 | 11 | cd "igbinary-${igbinary_version}" 12 | /app/vendor/php/bin/phpize 13 | ./configure --with-php-config=/app/vendor/php/bin/php-config \ 14 | --enable-igbinary 15 | 16 | make 17 | cp modules/igbinary.so "$EXT_DIR/igbinary.so" 18 | echo "extension=igbinary.so" > "$PREFIX/etc/conf.d/igbinary.ini" 19 | -------------------------------------------------------------------------------- /support/ext/imagick: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | imagick_version="3.1.2" 7 | 8 | curl -L "http://pecl.php.net/get/imagick-${imagick_version}.tgz" \ 9 | | tar xzv 10 | 11 | cd imagick-${imagick_version} 12 | /app/vendor/php/bin/phpize 13 | ./configure --with-php-config=/app/vendor/php/bin/php-config 14 | 15 | make 16 | cp modules/imagick.so "$EXT_DIR/imagick.so" 17 | echo "extension=imagick.so" > "$PREFIX/etc/conf.d/imagick.ini" 18 | -------------------------------------------------------------------------------- /support/ext/libevent: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | libevent_version="0.1.0" 7 | 8 | curl -L "http://pecl.php.net/get/libevent-${libevent_version}.tgz" \ 9 | | tar xzv 10 | 11 | cd libevent-${libevent_version} 12 | /app/vendor/php/bin/phpize 13 | ./configure --with-php-config=/app/vendor/php/bin/php-config 14 | 15 | make 16 | cp modules/libevent.so "$EXT_DIR/libevent.so" 17 | echo "extension=libevent.so" > "$PREFIX/etc/conf.d/libevent.ini" 18 | -------------------------------------------------------------------------------- /support/ext/memcache: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | php_memcache_version=85a86d8d0ce7c333a88bc378d5aca91dd5f910ff 7 | 8 | curl -L "https://github.com/php/pecl-caching-memcache/archive/${php_memcache_version}.tar.gz" \ 9 | | tar xzv 10 | 11 | cd pecl-caching-memcache-${php_memcache_version} 12 | /app/vendor/php/bin/phpize 13 | ./configure --with-php-config=/app/vendor/php/bin/php-config 14 | 15 | make 16 | cp modules/memcache.so "$EXT_DIR/memcache.so" 17 | echo "extension=memcache.so" > "$PREFIX/etc/conf.d/memcache.ini" 18 | -------------------------------------------------------------------------------- /support/ext/memcached: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | php_memcached_version=40ce9b4633de5d70f056e4d434d9b064263348d0 7 | 8 | curl -L "https://github.com/andreiz/php-memcached/archive/${php_memcached_version}.tar.gz" \ 9 | | tar xzv 10 | 11 | mkdir -p /app/vendor/libmemcached 12 | curl "https://s3-eu-west-1.amazonaws.com/chh-heroku-buildpack-php/package/libmemcached-1.0.17.tgz" \ 13 | | tar xzv -C /app/vendor/libmemcached 14 | 15 | cd php-memcached-${php_memcached_version} 16 | /app/vendor/php/bin/phpize 17 | ./configure --with-php-config=/app/vendor/php/bin/php-config \ 18 | --with-libmemcached-dir=/app/vendor/libmemcached 19 | --enable-memcached 20 | 21 | make 22 | cp modules/memcached.so "$EXT_DIR/memcached.so" 23 | echo "extension=memcached.so" > "$PREFIX/etc/conf.d/memcached.ini" 24 | -------------------------------------------------------------------------------- /support/ext/mongo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | mongo_version="1.4.4" 7 | 8 | curl -L "https://github.com/mongodb/mongo-php-driver/archive/${mongo_version}.tar.gz" \ 9 | | tar xzv 10 | 11 | cd mongo-php-driver-${mongo_version} 12 | /app/vendor/php/bin/phpize 13 | ./configure --with-php-config=/app/vendor/php/bin/php-config \ 14 | --enable-mongo 15 | 16 | make 17 | cp modules/mongo.so "$EXT_DIR/mongo.so" 18 | echo "extension=mongo.so" > "$PREFIX/etc/conf.d/mongo.ini" 19 | -------------------------------------------------------------------------------- /support/ext/redis: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | phpredis_version="2.2.4" 7 | curl -L "https://github.com/nicolasff/phpredis/archive/${phpredis_version}.tar.gz" \ 8 | | tar -xzv 9 | 10 | cd phpredis-${phpredis_version} 11 | 12 | /app/vendor/php/bin/phpize 13 | ./configure --with-php-config=/app/vendor/php/bin/php-config \ 14 | --enable-redis 15 | 16 | make 17 | cp modules/redis.so "$EXT_DIR/redis.so" 18 | echo "extension=redis.so" > "$PREFIX/etc/conf.d/redis.ini" 19 | -------------------------------------------------------------------------------- /support/ext/ssh2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | ssh2_version=0.12 7 | libssh2_version=1.4.3 8 | 9 | mkdir -p /app/vendor/libssh2 10 | curl "http://${S3_BUCKET}.s3.amazonaws.com/package/libssh2-${libssh2_version=1.4.3}.tgz" | tar xzv -C /app/vendor/libssh2 11 | 12 | curl -L "http://pecl.php.net/get/ssh2-${ssh2_version}.tgz" \ 13 | | tar xzv 14 | 15 | cd ssh2-${ssh2_version} 16 | /app/vendor/php/bin/phpize 17 | ./configure --with-php-config=/app/vendor/php/bin/php-config \ 18 | --with-ssh2=/app/vendor/libssh2 \ 19 | 20 | make 21 | cp modules/ssh2.so "$EXT_DIR/ssh2.so" 22 | echo "extension=ssh2.so" > "$PREFIX/etc/conf.d/ssh2.ini" 23 | -------------------------------------------------------------------------------- /support/ext/sundown: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | sundown_version=0.3.11 7 | 8 | curl -L "http://pecl.php.net/get/sundown-${sundown_version}.tgz" \ 9 | | tar xzv 10 | 11 | cd sundown-${sundown_version} 12 | /app/vendor/php/bin/phpize 13 | ./configure --with-php-config=/app/vendor/php/bin/php-config 14 | 15 | make 16 | cp modules/sundown.so "$EXT_DIR/sundown.so" 17 | echo "extension=sundown.so" > "$PREFIX/etc/conf.d/sundown.ini" 18 | -------------------------------------------------------------------------------- /support/get_zlib: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | zlib_version="$1" 7 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 8 | 9 | source "$basedir/../conf/buildpack.conf" 10 | 11 | tempdir="$( mktemp -t zlib_XXXX )" 12 | rm -rf $tempdir 13 | mkdir -p $tempdir 14 | cd $tempdir 15 | 16 | echo "-----> Downloading ZLib v${zlib_version}" 17 | curl -LO "http://zlib.net/zlib-${zlib_version}.tar.gz" 18 | 19 | s3cmd put --acl-public --verbose "zlib-${zlib_version}.tar.gz" \ 20 | "s3://$S3_BUCKET/zlib/zlib-${zlib_version}.tar.gz" 21 | -------------------------------------------------------------------------------- /support/manifest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | manifest_type="$1" 7 | 8 | if [ -z "$manifest_type" ]; then 9 | echo "Usage: $0 " >&2 10 | exit 1 11 | fi 12 | 13 | indent() { 14 | local expr='s/^/ /' 15 | 16 | if [ $(uname -s) = "Darwin" ]; then 17 | sed -l "$expr" 18 | else 19 | sed -u "$expr" 20 | fi 21 | } 22 | 23 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 24 | 25 | source "$basedir/../conf/buildpack.conf" 26 | 27 | if [ -z "$S3_BUCKET" ]; then 28 | echo "S3_BUCKET must be set" >&2 29 | exit 1 30 | fi 31 | 32 | # make a temp directory 33 | tempdir="$( mktemp -t php_XXXX )" 34 | rm -rf $tempdir 35 | mkdir -p $tempdir 36 | pushd $tempdir > /dev/null 37 | 38 | echo "-----> Manifest for $manifest_type" 39 | 40 | s3cmd ls "s3://$S3_BUCKET/package/" \ 41 | | awk '{ print $4 }' \ 42 | | sed "s/^s3:\/\/$S3_BUCKET\/package\///" \ 43 | | grep "\.tgz$" \ 44 | | grep "${manifest_type}" \ 45 | | grep -v -e ".md5" \ 46 | | sed -e "s/${manifest_type}-\([0-9.]*\)\\.tgz/\\1/" \ 47 | | awk 'BEGIN {FS="."} {printf("%03d.%03d.%03d %s\n",$1,$2,$3,$0)}' \ 48 | | sort -r \ 49 | | cut -d" " -f2 \ 50 | > manifest.${manifest_type} 51 | 52 | cat "manifest.${manifest_type}" | indent 53 | 54 | echo 55 | echo "-----> Uploading manifest for ${manifest_type} to S3" 56 | 57 | s3cmd put --acl-public --mime-type="text/plain" \ 58 | manifest.${manifest_type} "s3://$S3_BUCKET" \ 59 | | fold -w 70 | indent 60 | -------------------------------------------------------------------------------- /support/package-checksum: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 7 | source "$basedir/../conf/buildpack.conf" 8 | 9 | if [ -z "$S3_BUCKET" ]; then 10 | echo "Must set S3_BUCKET environment variable" >&2 11 | exit $E_S3_BUCKET_MISSING 12 | fi 13 | 14 | package="$1" 15 | 16 | tempdir="$( mktemp -t s3_XXXX )" 17 | rm -rf $tempdir 18 | mkdir -p $tempdir 19 | cd $tempdir 20 | 21 | echo "-----> Creating checksum for ${package}" 22 | 23 | s3cmd get "s3://$S3_BUCKET/package/${package}.tgz" "${package}.tgz" 24 | if hash md5sum 2>/dev/null; then 25 | md5sum "${package}.tgz" > "${package}.md5" 26 | else 27 | md5 -r "${package}.tgz" > "${package}.md5" 28 | fi 29 | s3cmd put \ 30 | --verbose --acl-public \ 31 | "${package}.md5" "s3://$S3_BUCKET/package/${package}.md5" 32 | -------------------------------------------------------------------------------- /support/package_composer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 7 | source "$basedir/../conf/buildpack.conf" 8 | 9 | tempdir="$( mktemp -t composer_XXXX )" 10 | rm -rf $tempdir 11 | mkdir -p $tempdir 12 | cd $tempdir 13 | 14 | curl -L http://getcomposer.org/composer.phar > composer.phar 15 | if hash md5sum 2>/dev/null; then 16 | md5sum composer.phar > composer.phar.md5 17 | else 18 | md5 -r composer.phar > composer.phar.md5 19 | fi 20 | 21 | s3cmd put --verbose --acl-public \ 22 | ./composer.phar s3://$S3_BUCKET/composer/composer.phar 23 | 24 | s3cmd put --verbose --acl-public \ 25 | ./composer.phar.md5 s3://$S3_BUCKET/composer/composer.phar.md5 26 | -------------------------------------------------------------------------------- /support/package_ext: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | if [ -z "$1" ]; then 7 | echo "Usage: package_ext EXT API..." 8 | exit 1 9 | fi 10 | 11 | indent() { 12 | c='s/^/ /' 13 | case $(uname) in 14 | Darwin) sed -l "$c";; 15 | *) sed -u "$c";; 16 | esac 17 | } 18 | 19 | build_ext() { 20 | local ext_name="$1" 21 | local php_series="$2" 22 | local zend_api_version=${PHP_MODULE_API_VERSIONS["$php_series"]} 23 | 24 | tempdir="$( mktemp -t php${ext_name}_XXXX )" 25 | rm -rf $tempdir 26 | mkdir -p $tempdir 27 | cd $tempdir 28 | 29 | local php_version=$(\ 30 | echo "$php_versions" \ 31 | | grep "^${php_series}.*$" | sort -r -V | head -n1) 32 | 33 | echo "-----> Building $ext_name for PHP module API version ${zend_api_version} using PHP ${php_version}" 34 | 35 | local ext_dir="lib/php/extensions/no-debug-non-zts-${zend_api_version}" 36 | local php_package="http://${S3_BUCKET}.s3.amazonaws.com/package/php-${php_version}.tgz" 37 | 38 | cp "$basedir/ext/${ext_name}" "$tempdir/build.sh" 39 | 40 | cd "$tempdir" 41 | 42 | mkdir -p /app/vendor/php 43 | mkdir -p "/tmp/out/$ext_dir" 44 | mkdir -p "/tmp/out/etc/conf.d" 45 | curl -L "$php_package" | tar -xzv -C /app/vendor/php 46 | 47 | echo "-----> Compiling the extension" 48 | 49 | PREFIX="/tmp/out" EXT_DIR="/tmp/out/$ext_dir" S3_BUCKET="$S3_BUCKET" ./build.sh 50 | 51 | echo "-----> Building the archive" 52 | 53 | pushd /tmp/out/ 54 | 55 | tar czf "$tempdir/php-${ext_name}.tgz" * 56 | 57 | popd 58 | 59 | s3cmd put --verbose \ 60 | --acl-public \ 61 | "$tempdir/php-${ext_name}.tgz" \ 62 | "s3://$S3_BUCKET/package/ext/${zend_api_version}/php-${ext_name}.tgz" 63 | 64 | "$basedir/package-checksum" "ext/${zend_api_version}/php-${ext_name}" 65 | } 66 | 67 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 68 | source "$basedir/../conf/buildpack.conf" 69 | 70 | export PATH=${basedir}/../vendor/bin:$PATH 71 | 72 | php_versions=$(curl --silent "http://${S3_BUCKET}.s3.amazonaws.com/manifest.php") 73 | 74 | ext_name="$1" 75 | shift 76 | php_api="$@" 77 | 78 | if [ ! -f "$basedir/ext/$ext_name" ]; then 79 | echo "No build manifest found for '$ext_name'" >&2 80 | exit 1 81 | fi 82 | 83 | echo "-----> Building $ext_name for PHP versions [$php_api]" 84 | 85 | for api in $php_api; do 86 | build_ext "$ext_name" "$api" 87 | done 88 | -------------------------------------------------------------------------------- /support/package_icu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | download_url="http://download.icu-project.org/files/icu4c/51.2/icu4c-51_2-src.tgz" 7 | 8 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 9 | source "$basedir/../conf/buildpack.conf" 10 | 11 | export PATH=${basedir}/../vendor/bin:$PATH 12 | 13 | if [ -z "$S3_BUCKET" ]; then 14 | echo "Must set S3_BUCKET environment variable" >&2 15 | exit 1 16 | fi 17 | 18 | tempdir="$( mktemp -t libicu_XXXX )" 19 | rm -rf $tempdir 20 | mkdir -p $tempdir 21 | cd $tempdir 22 | 23 | echo "-----> Downloading libicu" 24 | 25 | curl -L "$download_url" | tar xzv 26 | 27 | echo "-----> Compiling" 28 | 29 | mkdir -p /app/vendor/libicu 30 | cd icu 31 | ./source/runConfigureICU Linux --prefix=/app/vendor/libicu 32 | make 33 | make install 34 | 35 | echo "-----> Building the archive" 36 | 37 | pushd /app/vendor/libicu 38 | 39 | tar czf "${tempdir}/libicu-51.tgz" * 40 | 41 | popd 42 | 43 | s3cmd put \ 44 | --verbose --acl-public \ 45 | "$tempdir/libicu-51.tgz" \ 46 | "s3://$S3_BUCKET/package/libicu-51.tgz" 47 | 48 | "$basedir/package-checksum" "libicu-51" 49 | -------------------------------------------------------------------------------- /support/package_jq: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 7 | source "$basedir/../conf/buildpack.conf" 8 | 9 | tempdir="$( mktemp -t jq_XXXX )" 10 | rm -rf $tempdir 11 | mkdir -p $tempdir 12 | cd $tempdir 13 | 14 | echo "----> Vendoring 'jq'" 15 | curl -L http://stedolan.github.io/jq/download/linux64/jq > jq 16 | s3cmd put --verbose --acl-public ./jq s3://$S3_BUCKET/jq/jq 17 | -------------------------------------------------------------------------------- /support/package_libmcrypt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | mcrypt_version="$1" 7 | 8 | if [ -z "$mcrypt_version" ]; then 9 | echo "Usage: $(basename "$0") VERSION" >&2 10 | exit 1 11 | fi 12 | 13 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 14 | source "$basedir/../conf/buildpack.conf" 15 | 16 | export PATH=${basedir}/../vendor/bin:$PATH 17 | 18 | if [ -z "$S3_BUCKET" ]; then 19 | echo "Must set S3_BUCKET environment variable" >&2 20 | exit 1 21 | fi 22 | 23 | tempdir="$( mktemp -t libmcrypt_XXXX )" 24 | rm -rf $tempdir 25 | mkdir -p $tempdir 26 | cd $tempdir 27 | 28 | echo "-----> Downloading libmcrypt ${mcrypt_version}" 29 | curl -L "http://sourceforge.net/projects/mcrypt/files/Libmcrypt/${mcrypt_version}/libmcrypt-${mcrypt_version}.tar.gz/download" \ 30 | | tar xzv 31 | 32 | echo "-----> Compiling" 33 | 34 | mkdir -p /app/vendor/libmcrypt 35 | cd libmcrypt-${mcrypt_version} 36 | ./configure --disable-posix-threads --prefix=/app/vendor/libmcrypt 37 | make 38 | make install 39 | 40 | echo "-----> Building the archive" 41 | 42 | pushd /app/vendor/libmcrypt 43 | 44 | tar czf "${tempdir}/libmcrypt-${mcrypt_version}.tgz" * 45 | 46 | popd 47 | 48 | s3cmd put \ 49 | --verbose --acl-public \ 50 | "$tempdir/libmcrypt-${mcrypt_version}.tgz" \ 51 | "s3://$S3_BUCKET/package/libmcrypt-${mcrypt_version}.tgz" 52 | 53 | "$basedir/package-checksum" "libmcrypt-${mcrypt_version}" 54 | -------------------------------------------------------------------------------- /support/package_libmemcached: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 7 | source "$basedir/../conf/buildpack.conf" 8 | 9 | export PATH=${basedir}/../vendor/bin:$PATH 10 | 11 | if [ -z "$S3_BUCKET" ]; then 12 | echo "Must set S3_BUCKET environment variable" >&2 13 | exit 1 14 | fi 15 | 16 | tempdir="$( mktemp -t libmemcached_XXXX )" 17 | rm -rf $tempdir 18 | mkdir -p $tempdir 19 | cd $tempdir 20 | 21 | memcached_version=1.0.17 22 | 23 | echo "-----> Downloading libmemcached" 24 | 25 | curl -LO "https://launchpad.net/libmemcached/1.0/${memcached_version}/+download/libmemcached-${memcached_version}.tar.gz" 26 | tar -xzvf "libmemcached-${memcached_version}.tar.gz" 27 | 28 | echo "-----> Compiling" 29 | 30 | cd libmemcached-${memcached_version} 31 | mkdir -p /app/vendor/libmemcached 32 | ./configure --without-memcached --prefix=/app/vendor/libmemcached 33 | make 34 | make install 35 | 36 | echo "-----> Building the archive" 37 | 38 | pushd /app/vendor/libmemcached 39 | 40 | tar czf "$tempdir/libmemcached-${memcached_version}.tgz" * 41 | 42 | popd 43 | 44 | s3_path=s3://$S3_BUCKET/package/libmemcached-${memcached_version}.tgz 45 | 46 | echo "-----> Uploading package to ${s3_path}" 47 | 48 | s3cmd put --verbose \ 49 | --acl-public \ 50 | "$tempdir/libmemcached-${memcached_version}.tgz" \ 51 | "${s3_path}" 52 | 53 | "$basedir/package-checksum" libmemcached-${memcached_version} 54 | 55 | echo "-----> Done building libmemcached package!" 56 | -------------------------------------------------------------------------------- /support/package_librabbitmq: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 7 | source "$basedir/../conf/buildpack.conf" 8 | 9 | export PATH=${basedir}/../vendor/bin:$PATH 10 | 11 | if [ -z "$S3_BUCKET" ]; then 12 | echo "Must set S3_BUCKET environment variable" >&2 13 | exit 1 14 | fi 15 | 16 | tempdir="$( mktemp -t librabbitmq_XXXX )" 17 | rm -rf $tempdir 18 | mkdir -p $tempdir 19 | cd $tempdir 20 | 21 | rabbitmq_version=0.5.2 22 | 23 | echo "-----> Downloading librabbitmq" 24 | 25 | curl -L "https://github.com/alanxz/rabbitmq-c/releases/download/v${rabbitmq_version}/rabbitmq-c-${rabbitmq_version}.tar.gz" \ 26 | | tar xzv 27 | 28 | echo "-----> Compiling" 29 | 30 | # Using the legacy autotools build rather than cmake as heroku does not provide cmake 31 | mkdir -p /app/vendor/librabbitmq 32 | cd rabbitmq-c-${rabbitmq_version} 33 | autoreconf -i --force 34 | ./configure --prefix=/app/vendor/librabbitmq 35 | make 36 | make install 37 | 38 | echo "-----> Building the archive" 39 | 40 | pushd /app/vendor/librabbitmq 41 | 42 | tar czf "${tempdir}/librabbitmq-${rabbitmq_version}.tgz" * 43 | 44 | popd 45 | 46 | s3cmd put \ 47 | --verbose --acl-public \ 48 | "$tempdir/librabbitmq-${rabbitmq_version}.tgz" \ 49 | "s3://$S3_BUCKET/package/librabbitmq-${rabbitmq_version}.tgz" 50 | 51 | "$basedir/package-checksum" "librabbitmq-${rabbitmq_version}" 52 | -------------------------------------------------------------------------------- /support/package_libssh2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 7 | source "$basedir/../conf/buildpack.conf" 8 | 9 | export PATH=${basedir}/../vendor/bin:$PATH 10 | 11 | if [ -z "$S3_BUCKET" ]; then 12 | echo "Must set S3_BUCKET environment variable" >&2 13 | exit 1 14 | fi 15 | 16 | tempdir="$( mktemp -t libssh2_XXXX )" 17 | rm -rf $tempdir 18 | mkdir -p $tempdir 19 | cd $tempdir 20 | 21 | libssh2_version=1.4.3 22 | 23 | echo "-----> Downloading libssh2" 24 | 25 | curl -L "http://www.libssh2.org/download/libssh2-${libssh2_version}.tar.gz" \ 26 | | tar xzv 27 | 28 | echo "-----> Compiling" 29 | 30 | mkdir -p /app/vendor/libssh2 31 | cd libssh2-${libssh2_version} 32 | ./configure --prefix=/app/vendor/libssh2 --with-openssl 33 | make 34 | make install 35 | 36 | echo "-----> Building the archive" 37 | 38 | pushd /app/vendor/libssh2 39 | 40 | tar czf "${tempdir}/libssh2-${libssh2_version}.tgz" * 41 | 42 | popd 43 | 44 | s3cmd put \ 45 | --verbose --acl-public \ 46 | "$tempdir/libssh2-${libssh2_version}.tgz" \ 47 | "s3://$S3_BUCKET/package/libssh2-${libssh2_version}.tgz" 48 | 49 | "$basedir/package-checksum" "libssh2-${libssh2_version}" 50 | -------------------------------------------------------------------------------- /support/package_nginx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | nginx_version="$1" 7 | 8 | E_ARG_MISSING=127 9 | E_S3_BUCKET_MISSING=2 10 | 11 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 12 | source "$basedir/../conf/buildpack.conf" 13 | 14 | export PATH=${basedir}/../vendor/bin:$PATH 15 | 16 | if [ -z "$nginx_version" ]; then 17 | echo "Usage: $0 " >&2 18 | exit $E_ARG_MISSING 19 | fi 20 | 21 | if [ -z "$NGINX_ZLIB_VERSION" ]; then 22 | NGINX_ZLIB_VERSION=1.2.8 23 | fi 24 | 25 | if [ -z "$NGINX_PCRE_VERSION" ]; then 26 | NGINX_PCRE_VERSION=8.32 27 | fi 28 | 29 | zlib_version="$NGINX_ZLIB_VERSION" 30 | pcre_version="$NGINX_PCRE_VERSION" 31 | 32 | tempdir="$( mktemp -t nginx_XXXX )" 33 | rm -rf $tempdir 34 | mkdir -p $tempdir 35 | cd $tempdir 36 | 37 | echo "-----> Downloading dependency PCRE ${pcre_version}" 38 | 39 | curl -LO "http://sourceforge.net/projects/pcre/files/pcre/${pcre_version}/pcre-${pcre_version}.tar.gz" 40 | tar -xzvf "pcre-${pcre_version}.tar.gz" 41 | 42 | echo "-----> Downloading dependency zlib ${zlib_version}" 43 | 44 | curl -LO "http://${S3_BUCKET}.s3.amazonaws.com/zlib/zlib-${zlib_version}.tar.gz" 45 | tar -xzvf "zlib-${zlib_version}.tar.gz" 46 | 47 | echo "-----> Downloading NGINX ${nginx_version}" 48 | 49 | curl -LO "http://nginx.org/download/nginx-${nginx_version}.tar.gz" 50 | tar -xzvf "nginx-${nginx_version}.tar.gz" 51 | 52 | echo "-----> Compiling" 53 | 54 | cd nginx-${nginx_version} 55 | ./configure --prefix=/app/vendor/nginx --with-http_ssl_module --with-pcre=../pcre-${pcre_version} --with-zlib=../zlib-${zlib_version} 56 | make 57 | make install 58 | 59 | echo "-----> Building the archive" 60 | 61 | pushd /app/vendor/nginx 62 | 63 | tar czf "$tempdir/nginx-${nginx_version}.tgz" * 64 | 65 | popd 66 | 67 | echo "-----> Uploading package to s3://$S3_BUCKET/package/nginx-${nginx_version}.tgz" 68 | 69 | s3cmd put --verbose \ 70 | --acl-public \ 71 | "$tempdir/nginx-${nginx_version}.tgz" \ 72 | "s3://$S3_BUCKET/package/nginx-${nginx_version}.tgz" 73 | 74 | "$basedir/manifest" nginx 75 | "$basedir/package-checksum" "nginx-${nginx_version}" 76 | 77 | echo "-----> Done building NGINX package!" 78 | -------------------------------------------------------------------------------- /support/package_php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | basedir="$( cd -P "$( dirname "$0" )" && pwd )" 7 | source "$basedir/../conf/buildpack.conf" 8 | 9 | export PATH=${basedir}/../vendor/bin:$PATH 10 | 11 | if [ -z "$1" ]; then 12 | echo "Usage: $0 " >&2 13 | exit 1 14 | fi 15 | 16 | php_version="$1" 17 | mcrypt_version="2.5.8" 18 | 19 | if [ -z "$PHP_ZLIB_VERSION" ]; then 20 | PHP_ZLIB_VERSION=1.2.8 21 | fi 22 | 23 | echo "-----> Packaging PHP $php_version" 24 | 25 | tempdir="$( mktemp -t php_XXXX )" 26 | rm -rf $tempdir 27 | mkdir -p $tempdir 28 | cd $tempdir 29 | 30 | echo "-----> Downloading dependency zlib ${zlib_version}" 31 | 32 | curl -LO "http://$S3_BUCKET.s3.amazonaws.com/zlib/zlib-${PHP_ZLIB_VERSION}.tar.gz" 33 | tar -xzvf "zlib-${PHP_ZLIB_VERSION}.tar.gz" 34 | 35 | echo "-----> Downloading PHP $php_version" 36 | curl -LO "http://php.net/distributions/php-${php_version}.tar.gz" 37 | tar -xzvf "php-${php_version}.tar.gz" 38 | 39 | echo "-----> Downloading dependencies (libmcrypt, libicu)" 40 | 41 | mkdir -p "/app/vendor/php/zlib" "/app/vendor/libmcrypt" "/app/vendor/libicu" 42 | curl "http://${S3_BUCKET}.s3.amazonaws.com/package/libicu-51.tgz" | tar xzv -C /app/vendor/libicu 43 | curl "http://${S3_BUCKET}.s3.amazonaws.com/package/libmcrypt-${mcrypt_version}.tgz" | tar xzv -C /app/vendor/libmcrypt 44 | export LD_LIBRARY_PATH=/app/vendor/libicu/lib 45 | export PATH="/app/vendor/libicu/bin:$PATH" 46 | 47 | echo "-----> Compiling ZLIB" 48 | 49 | pushd zlib-${PHP_ZLIB_VERSION} 50 | ./configure --prefix=/app/vendor/php/zlib 51 | make 52 | make install 53 | popd 54 | 55 | echo "-----> Compiling PHP" 56 | 57 | mkdir -p "/app/vendor/php/etc/conf.d" 58 | 59 | cd php-${php_version} 60 | ./configure --prefix=/app/vendor/php \ 61 | --with-config-file-path=/app/vendor/php/etc \ 62 | --with-config-file-scan-dir=/app/vendor/php/etc/conf.d \ 63 | --enable-intl \ 64 | --with-gd \ 65 | --with-mysql \ 66 | --with-mysqli \ 67 | --with-pdo-mysql \ 68 | --with-pdo-sqlite \ 69 | --with-pdo-pgsql=/usr/bin/pg_config \ 70 | --with-pgsql \ 71 | --enable-shmop \ 72 | --enable-zip \ 73 | --with-jpeg-dir=/usr \ 74 | --with-png-dir=/usr \ 75 | --with-freetype-dir=/usr \ 76 | --enable-exif \ 77 | --with-zlib=/app/vendor/php/zlib \ 78 | --with-bz2 \ 79 | --with-openssl \ 80 | --enable-soap \ 81 | --enable-xmlreader \ 82 | --with-xmlrpc \ 83 | --with-curl=/usr \ 84 | --with-xsl \ 85 | --enable-fpm \ 86 | --enable-mbstring \ 87 | --enable-pcntl \ 88 | --enable-sockets \ 89 | --enable-bcmath \ 90 | --with-readline \ 91 | --with-mcrypt=/app/vendor/libmcrypt \ 92 | --enable-ftp=shared \ 93 | --disable-debug 94 | make 95 | make install 96 | /app/vendor/php/bin/pear config-set php_dir /app/vendor/php 97 | 98 | echo "-----> Installing OPCache" 99 | 100 | if [[ "$php_version" =~ 5.5 ]]; then 101 | echo "zend_extension=opcache.so" >> /app/vendor/php/etc/conf.d/opcache.ini 102 | else 103 | /app/vendor/php/bin/pecl install ZendOpcache-beta 104 | echo "zend_extension=$(/app/vendor/php/bin/php-config --extension-dir)/opcache.so" >> /app/vendor/php/etc/conf.d/opcache.ini 105 | fi 106 | 107 | echo "-----> Building the archive" 108 | 109 | pushd /app/vendor/php 110 | 111 | tar czf "$tempdir/php-$php_version.tgz" * 112 | 113 | popd 114 | 115 | echo "-----> Moving package to S3" 116 | 117 | s3cmd put \ 118 | --verbose --acl-public \ 119 | "$tempdir/php-${php_version}.tgz" \ 120 | "s3://$S3_BUCKET/package/php-${php_version}.tgz" 121 | 122 | "$basedir/manifest" php 123 | "$basedir/package-checksum" "php-${php_version}" 124 | 125 | echo "-----> Done building PHP package!" 126 | --------------------------------------------------------------------------------