Using AppFog With PHP

Managing applications across cloud platforms requires a flexible and efficient deployment process. Handling configurations, securing connections, and integrating databases are critical aspects of ensuring reliability and performance. With support for multiple programming languages and infrastructure providers, applications can be deployed with automated settings and resource management. Addressing potential challenges early in the setup process helps maintain stability and prevents unexpected disruptions.

Sign Up for AppFog

AppFog is a Platform as a Service (PaaS) solution built on the open-source Cloud Foundry project. It supports multiple programming languages and allows application deployment across various infrastructure providers, including Amazon AWS, HP OpenStack, Microsoft Azure, and Rackspace DFW. Signing up is straightforward—simply provide an email address and password to gain access to the free plan, which includes 2GB of RAM, 10 services (such as databases) with a maximum of 100MB each, and a 50GB data transfer limit. This is a substantial offering for a free service. Additionally, applications can be migrated to any Cloud Foundry-compatible platform. Create an AppFog account to proceed.

Setting Up the Local Application

Download the latest version of CakePHP, extract it, and rename it accordingly (e.g., FogNotes). Configure the directory for web server access using a friendly URL (e.g., http://fognotes.local). Set the document root to the app/webroot directory and create an empty MySQL database (e.g., fognotes_local). When accessed in a browser, the CakePHP default homepage should be visible—any warnings will be addressed later.

Create a data directory with config and logs subdirectories. Move the app/tmp directory into data and ensure that both tmp and logs are writable by the web server. Create an alias for CakePHP’s console command in the application’s root directory:

~/FogNotes$ ln -s lib/Cake/Console/cake cake

The resulting directory structure should be:

FogNotes/

    app/

    data/

        config/

        logs/

        tmp/

            cache/

            logs/

            sessions/

            tests/

    lib/

        Cake/

    plugins/

    vendors/

    cake

    index.php

This setup separates application code (app) from the framework (lib/Cake) and external libraries (plugins and vendors). The application’s configuration and data are centralized in data/, facilitating updates, backups, and maintenance.

Configuring CakePHP

To specify a custom temporary directory, edit app/webroot/index.php and insert the following code after the define(‘ROOT’,…) statement:

// Custom TMP directory

define(‘TMP’, ROOT . DS . ‘data’ . DS . ‘tmp’ . DS);

Next, modify the database configuration to use environment-specific settings. Copy app/Config/database.php.default to app/Config/database.php and replace its contents with:

class DATABASE_CONFIG {

    public $default = null;

    public $test = null;

    public $env = null;

    function __construct() {

        if (!defined(‘APP_ENV’)) {

            return false;

        }

        $this->env = APP_ENV;

        $config = Configure::read(‘Database.config’);

        if (!is_array($config)) {

            return false;

        }

        foreach ($config as $name => $data) {

            $this->$name = $data;

        }

        if (empty($config[‘default’]) || empty($this->default)) {

            return false;

        }

    }

}

This approach, adapted from the CakePHP developer community, allows configuration settings to be loaded dynamically based on the application environment.

In app/Config/bootstrap.php, register the data/config directory with CakePHP by adding this code after the Configure::write(‘Dispatcher.filters’…) statement:

App::uses(‘PhpReader’, ‘Configure’);

Configure::config(‘default’, new PhpReader(ROOT . DS . ‘data’ . DS . ‘config’ . DS));

if ($env = getenv(‘APP_ENV’)) {

    define(‘APP_ENV’, $env);

} else {

    define(‘APP_ENV’, ‘local’);

}

AppFog allows setting the APP_ENV variable; if not set, the application defaults to local mode. At the end of bootstrap.php, insert:

try {

    Configure::load(APP_ENV);

} catch (ConfigureException $e) {

    // Handle errors appropriately

}

This instructs CakePHP to look in data/config for a configuration file matching the environment (e.g., local.php or prod.php).

A sample local.php configuration file:

$config = array(

    ‘debug’ => 1

);

Configure::write(‘Security.salt’, ‘SomeSuperSecretLongString’);

Configure::write(‘Security.cipherSeed’, ‘SomeSuperSecretLongNumber’);

Configure::write(‘Database.config’, array(

    ‘default’ => array(

        ‘datasource’ => ‘Database/Mysql’,

        ‘persistent’ => false,

        ‘host’ => ‘localhost’,

        ‘login’ => ‘root’,

        ‘password’ => ‘secret_password’,

        ‘database’ => ‘fognotes_local’,

        ‘prefix’ => ”,

        ‘encoding’ => ‘utf8’,

        ‘unix_socket’ => ‘/tmp/mysql.sock’,

    )

));

CakeLog::config(‘default’, array(

    ‘engine’ => ‘FileLog’,

    ‘path’   => ROOT . DS . ‘data’ . DS . ‘logs’ . DS

));

After these configurations, any warning messages on the CakePHP homepage should be resolved.

Deploying an Application in AppFog

Step 1: Create a New Application

Log into your AppFog console and set up a new application. Choose PHP as the application type, select your preferred infrastructure provider (e.g., AWS Europe), and assign a name. Click “Create App”, and within seconds, you’ll be redirected to the app’s Mission Control.

By default, AppFog initializes the project with an index.php file containing a basic “Hello World” script. Before uploading your custom code, you must bind a database service.

Step 2: Configure Database Service

  1. Go to the Services panel;
  2. Select MySQL, assign a name (e.g., fognotes_prod), and create the service;
  3. The database credentials will be stored in the VCAP_SERVICES environment variable.

Next, define a custom environment variable:

  1. Open the Env Variables panel;
  2. Create a new variable: APP_ENV = “prod”;
  3. Save the changes.

Step 3: Configure Database Connection

  1. Copy data/config/local.php and rename it data/config/prod.php;
  2. Open the new file in an editor and configure the database settings using AppFog’s guidelines:

<?php

// AppFog Database Configuration

$services_json = json_decode(getenv(‘VCAP_SERVICES’), true);

$af_mysql_config = $services_json[‘mysql-5.1’][0][‘credentials’];

Configure::write(‘Database.config’, array(

    ‘default’ => array(

        ‘datasource’ => ‘Database/Mysql’,

        ‘persistent’ => false,

        ‘host’ => $af_mysql_config[‘hostname’],

        ‘login’ => $af_mysql_config[‘username’],

        ‘password’ => $af_mysql_config[‘password’],

        ‘database’ => $af_mysql_config[‘name’],

        ‘prefix’ => ”,

        ‘encoding’ => ‘utf8’,

    )

));

?>

Step 4: Deploy the Application

  1. Install the af utility following the instructions in the Update Source Code panel;
  2. Open a terminal and go to the project root;
  3. Authenticate using the CLI but avoid downloading the remote project code;
  4. Deploy the local code using:

af update FogNotes

Within a minute, your application will be live, reflecting the production environment and database connection.

Finalizing the Application Setup

Now that the application is deployed, it’s time to add some essential code and data. CakePHP will handle most of the heavy lifting.

Step 1: Create the Database Table

Create a new file: data/config/notes.sql and add the following SQL script:

CREATE TABLE notes (

    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,

    title VARCHAR(255) NOT NULL,

    content TEXT NOT NULL,

    created DATETIME NULL DEFAULT NULL,

    modified DATETIME NULL DEFAULT NULL,

    INDEX (title, created, modified)

) ENGINE=INNODB;

Import this SQL file into the local database using the command line or a MySQL management tool of your choice.

Step 2: Generate Model, View, and Controller

Go to the application root and run:

~/FogNotes$ ./cake bake

Follow the prompts to generate the model, view, and controller for the notes table. CakePHP will automatically create the necessary files.

Step 3: Update Routing Configuration

Modify the routing file to set the notes list as the default home page.

Open app/Config/routes.php

Replace the first Router::connect() statement with:

<?php

Router::connect(‘/’, 

  array(‘controller’ => ‘notes’, ‘action’ => ‘index’));

?>

Reload the local home page, and you should see a fully functional application displaying notes.

Step 4: Deploy the Changes

To push the updated code to the remote server, run:

af update FogNotes

However, if you reload the remote app immediately, you’ll encounter an error because the database table doesn’t exist yet.

Step 5: Import the Database to the Remote Server

The easiest way to create the table remotely is by establishing a database tunnel:

Open a terminal and run:

af tunnel

When prompted, select “none” as the client type.

In a separate terminal, use the provided tunnel connection details to import the SQL file:

mysql –protocol=TCP –host=localhost –port=10000 –user=RemoteUserName \

–password=RemotePassword RemoteLongDifficultDBName < /path/to/notes.sql

Alternatively, if you’re on a Mac, you can use Sequel Pro, or if you’re on Windows/Linux, MySQL Workbench works as long as the tunnel remains open. Monitoring Linux metrics can also help ensure optimal database performance and resource utilization.

Once the table is successfully created, the remote application will function correctly.

Key Considerations for Hosting Applications on AppFog

Hosting a website on AppFog comes with several challenges. Here are some key issues and their solutions to ensure smooth application deployment.

No CRON Support for Automated Tasks

AppFog lacks built-in CRON services for scheduling automated tasks.

Solution:

  1. Use third-party services like IronWorker for scheduled tasks;
  2. Write custom scripts in Ruby or Python for task scheduling;
  3. Alternatively, use a PHP script with an infinite loop and sleep intervals:

while (true) {

    // Add scheduled tasks (e.g., email sending, score calculations)

    sleep(10); // Executes every 10 seconds

}

PHP’s mail() Function is Disabled

AppFog does not support PHP’s native mail() function, making email delivery difficult.

Solution:

  1. Use libraries like PHP-Mailer to send emails via SMTP;
  2. Consider third-party email services like MailGun for better reliability.

Incorrect User IP Address Due to Load Balancer

AppFog’s load balancer assigns its own IP instead of the actual user’s IP.

Solution:

Modify the Yii framework request settings to extract the correct IP:

$user_ip_all = $user_ip = Yii::app()->getRequest()->getUserHostAddress();

if (isset($_SERVER[‘HTTP_X_FORWARDED_FOR’])) {

    $user_ip = explode(‘,’, $_SERVER[‘HTTP_X_FORWARDED_FOR’]);

    $user_ip = trim($user_ip[0]); // Retrieves the first valid IP

}

User Sessions Expire After Application Updates

All logged-in users are automatically logged out when the application updates.

Solution:

Set a unique application ID in config/main.php:

return array(

    ‘basePath’ => dirname(__FILE__) . DIRECTORY_SEPARATOR . ‘..’,

    ‘name’ => ‘YourAppName’,

    ‘id’ => ‘unique_application_id’,  // Prevents session loss

);

Yii Assets Manager Fails to Publish Files Correctly

Certain assets (e.g., jquery.yiiactiveform.js) may not be properly published, causing 404 errors.

Solution:

  1. Copy jquery.yiiactiveform.js manually to the /assets directory;
  2. Add the following script in your Yii template to load the file correctly:

<script type=”text/javascript”>

    (function(d,s){

        if(typeof $.fn.yiiactiveform===’function’) return;

        var j = d.createElement(s); j.type = ‘text/javascript’;

        j.src = “<?php echo Yii::app()->homeUrl; ?>/assets/js/jquery.yiiactiveform.js”;

        d.getElementsByTagName(‘script’)[0].parentNode.insertBefore(j, d);

    })(document, ‘script’);

</script>

Database Username and Password Change Automatically

AppFog sometimes changes database credentials unexpectedly, causing access issues, especially for triggers and stored procedures.

Solution:

  • Regularly check and update database credentials;
  • If MySQL triggers stop working due to a missing definer, recreate them manually;
  • Grant permissions to all necessary users to prevent errors like:

SQLSTATE[HY000]: General error: 1449 The user specified as a definer does not exist.

Conclusion

AppFog provides a flexible environment for deploying and managing applications across various infrastructure providers. With features like auto reconfiguration, SSL support, and database management, it simplifies application scaling and integration. While some challenges, such as CRON job limitations and database credential changes, require additional configuration, solutions exist to maintain stability and performance. By using environment-specific settings and troubleshooting common issues, applications can run efficiently on AppFog’s cloud platform.

Alex Carter

Alex Carter

Alex Carter is a cybersecurity enthusiast and tech writer with a passion for online privacy, website performance, and digital security. With years of experience in web monitoring and threat prevention, Alex simplifies complex topics to help businesses and developers safeguard their online presence. When not exploring the latest in cybersecurity, Alex enjoys testing new tech tools and sharing insights on best practices for a secure web.