Writing One-Clicks

From apnsGuide

(Redirected from Esprit:Writing One-Clicks)
Jump to: navigation, search

Contents

Introduction

What is a "One-Click"?

The "One-Click" system is an answer to Fantastico, seen on cPanel-based control panels. As Apis Networks develops their own control panel, cPanel is not a viable option which thus rules out Fantastico inclusion. One-clicks arose as a method to address the problem with customers wishing to dabble in the newest Web applications, yet are afraid of going through the sometimes arduous (see Trac) process of setting it up. It also lets the other skilled programmers either share their application with users or even help simplify their lives.

Basic requirements

You may do two things with a one-click, you may either install any of the applications available on the server to an existing subdomain or to a new location under your Web site's document root. Optionally, you may enroll in the auto-update facility. At this time it is not implemented; however, it will provide a way to automatically upgrade your one-click application to the most recent version. In the event an upgrade fails due to heavy modification, you can always revert changes back to the original state.

Aside from those two options, every one-click has its own configuration options, defined by the driver. A driver is a PHP5 script that consists of six methods, outlined below in the examples. Programmers may require certain options based upon the constraints of the application, for example: does it need database access? If so, then you may be prompted for a MySQL login and password to install the schema into. Is there an administrative login? If so the application may prompt you for a login and password to use for administrative functions. Every one-click varies based on what is required to make it work.

As a casual user, this means nothing to you. As a programmer implementing the one-click framework though, you have several options when writing the driver.

Writing Your Own

To start things off, we'll throw out two quick examples of applications. Note the similarities with the two drivers. A driver is nothing more than a PHP5 class file that implements seven methods:

  • pre_configuration
  • post_configuration
  • install
  • post_install
  • pre_patch
  • patch
  • post_patch

The last three, related to the auto-update system, can be implemented, yet empty at this time. Once the auto-update system is in place though, we ask that you make changes to do any special upgrade tasks required outside of the basic patch/diff commands.

First Example: Lucida

Lucida is a lightweight photo album. Initially this was selected to help us determine a definite structure for the new one-click system without adding too many complexities (which will come once Trac is added).

Every one-click consists of three files:

  • XML description
  • PHP5 class
  • Optional logo

All three files should bear the internal name of the application, which in this case happens to be "lucida".

First, our XML description, named lucida.xml:

<?xml version="1.0" encoding="utf-8"?>
    <application name="lucida">
        <description>
            Lucida is a fast, clean, robust web based photo gallery written in PHP. It will parse any standard 
            directory structure on demand, treating directories as galleries, with unlimited recursion so 
            galleries can contain any number of subgalleries and images. Lucida uses ImageMagick to generate 
            thumbnails and resize images automatically, caching the results to speed up later pageviews.
            <br/><br />Lucida is extremely configurable and customizable, with a completely web based configuration 
            and administration system. All settings are stored in simple flat files, so there's no need for the 
            unnecessary overhead and complexity of a database.
            <br /><br />
            <em>Note:</em> Lucida is no longer supported by the author and may be removed from future versions of 
            the one-click install provision.  We chose Lucida as our first one-click application
            in esprit due to the simple installation process.
        </description>
        <version>0.1</version>
        <size units="KB">252</size>
        <dependencies><dependency name="PHP" /><dependency name="ImageMagick" /></dependencies>
        <website>http://wiki.wonko.com/software/lucida/</website>
    </application>


Second, our PHP5 driver, lucida.php:

<?php
    /**
     * @class lucida_Install
     * @author Matt Saladna <msaladna@apisnetworks.com>
     *
     * Provides basic hooks for the Lucida application in esprit's one-click
     * installation system
     */
    final class lucida_Install extends One_Click_Generic {
 
        public function __construct($mApp) {
            parent::__construct($mApp);
        }
 
        /**
          * Pre configuration hooks.  This function is reserved for
          * ensuring that the user has the necessary features enabled for
          * the account in order to install the application fine.
          *
          * Use:
          * return false;
          * at the end of the function to prohibit the user from configuring
          * or installing the application.
          *
          * return true;
          * allows the user to proceed with configuration of the application.
          *
          * Example:
          *
          * if (!$this->sql_service_enabled('mysql'))
          *     return false; // MySQL is not enabled for the account
          *
          * Alternatively you can be a bit more verbose by returning an Exception
          * if (!$this->sql_service_enabled('mysql'))
          *     return new PermissionError("MySQL not enabled for account");
          */
        public function pre_configuration() {
            /**
             * Set our configuration options
             */
            $this->configuration_options =
                    array('showfooter'    => array('label' => 'Show footer',
                                                  'type' => bool,
                                                  'default' => true),
                          'debug'         => array('label' => 'Enable debugging',
                                                   'type' => bool,
                                                   'default' => false),
                          'title'         => array('label' => 'Album title',
                                                   'minlength' => 1,
                                                   'constraints' => OPT_REQUIRED,
                                                   'default' => 'Photos',
                                                   'type'    => string),
                          'adminuser'     => array('label' => 'Administrative username',
                                                   'type' => string,
                                                   'minlength' => 3,
                                                   'maxlength' => 12,
                                                   'constraints' => OPT_REQUIRED,
                                                   'help' => 'Administrative user to access the account',
                                                   'regex' => '!^[a-z0-9A-Z_-]+$!'),
                          'adminpassword' => array('label' => 'Administrative password',
                                                   'type' => string, 'default' => '',
                                                   'minlength' => 3, 'maxlength' => 12,
                                                   'constraints' => OPT_REQUIRED,
                                                   'desc' => 'Administrative password',
                                                   'regex' => '!^[a-z0-9A-Z_-]+$!'),
                          'defaultres'    => array('label' => 'Default photo resolution',
                                                   'type' => enum,
                                                   'default' => '800x600',
                                                   'values' => array('original', '640x480',
                                                                     '800x600',  '1024x768',
                                                                     '1280x1024','1600x1200'),
                                                   'help' => 'This is the default resolution that all photos will be displayed as.'));
            return true;
        }
 
        /**
         * Validate input.
         * Return a value of false to force the user to reconfigure.
         *
         * Return an exception of type ArgumentError to let the user know
         * what options are invalid.  Example:
         *
         * if (!preg_match('/^[a-z]+$/',$password))
         *      return new ArgumentError(array("password" => "Invalid password"));
         */
        public function post_configuration() {
            return true;
        }
 
        /**
         * Ensure that the filesystem meets the needs of the application.
         */
        public function pre_install() {
            return true;
        }
 
        /**
         * Perform the application installation process
         *
         * This includes copying files into the system and updating any databases
         */
        public function install() {
            /**
             * void parent::log_status(string $mMsg)
             * Writes a string to the status file displayed in the browser
             * instantaneously.  Useful for notifying the user of the progress
             * of the install.
             *
             * NOTE: Broken in IE; IE doesn't handle the interactive state correctly
             * and only displays data once the XMLHTTP instance hits state 4 (completed).
             */
            $this->log_status("Copying files...");
 
            /**
             * bool parent::copy_storehouse(string $mSrc, string $mDest)
             *
             * Recursively copy the storehouse install to the destination.
             * Actual paths are prepended to the $mSrc and $mDest variables,
             * thus "/www/" would refer to the directory under
             * var/storehouse/lucida/0.1/ in esprit.
             *
             * The file structure looks a bit like:
             *
             *  [storehouse/lucida/0.1]# ls -l
             *  total 44
             *  -r--r--r--    1 nobody   nobody        15423 Mar 26  2004 LICENSE
             *  -r--r--r--    1 nobody   nobody         2901 Mar 26  2004 README
             *  -r--r--r--    1 nobody   nobody          150 Mar 26  2004 TODO
             *  drwxr-xr-x    5 nobody   nobody         4096 Jan  9 02:22 www/
             *
             *  The second parameter is based upon the input from the user, e.g.
             *  subdomain installation would put the distribution under
             *  /home/SUBDOMAIN/public_html/ or /var/subdomain/SUBDOMAIN/ or
             *  /var/www/html/DIRECTORY/
             */
 
            /** Copy files over ... */
            try {
                $this->copy_storehouse("/www/", "/");
            } catch (Exception $e) {
                return $e;
            }
            /**
             * Now we'll make a temp file and write out the configuration.
             * Once that's done, copy the file to the application install
             *
             * int parent::get_site_id()
             * get_site_id() returns the site number of an account, which is
             * how it is stored on the filesystem.  When attempting to write
             * to files in a PHP script, the siteNN notation is required
             * as open_basedir is dumb in resolving the symlinks, i.e.:
             * /home/virtual/<DOMAIN>/ throws an error when trying to write to a
             * file... /home/virtual/site<NUM>/fst/ works fine.
             *
             * string parent::get_install_path()
             * Returns the chroot'd installation location for a script, e.g.
             * if a user elects to install it under the main document root with
             * a path value of "/myapplication", then the function will return
             * /var/www/html/myapplication
             *
             * If it's a subdomain, depending on whether it's a concrete subdomain,
             * such that the user created a new user with a subdomain or a
             * virtual subdomain -- the user created a new subdomain that links
             * to another directory -- then get_install_path() will return
             * that chroot'd path.
             */
            $tmpConfig = array ('photodir' => '/home/virtual/site'.$this->get_site_id().'/fst/'.
                                               ltrim($this->get_install_path(),'/'),
                                'cachedir' => '/home/virtual/site'.$this->get_site_id().'/fst/'.
                                               ltrim($this->get_install_path(),'/').'/data/cache',
                                'extensions' => 'bmp,gif,jng,jp2,jpc,jpeg,jpg,pcd,png,psd,tga,tif,'.
                                                'tiff,wmf,xcf,PNG,JPG,JPEG,GIF',
                                'defaultres' => $this->postback_options['defaultres'],
                                'validreslist' => 'original,640x480,800x600,1024x768,1280x1024,1600x1200',
                                'resizequality' => '75',
                                'debug' => (bool)$this->postback_options['debug'],
                                'adminuser' => $this->postback_options['adminuser'],
                                'adminpass' => $this->postback_options['adminpassword'],
                                'title' => $this->postback_options['title'],
                                'style' => 'lib/styles/lucida.css',
                                'gallerypreviews' => true,
                                'displayexifdata' => true,
                                'customexifstring' => '<b>EXIF Data:</b>
 
                              %[EXIF:*]',
                                'showfooter' => $this->postback_options['showfooter'],
                                'showbenchmark' => true,
                                'footertext' => 'Copyright &copy; 2004. All rights reserved.<br />
                              Images and content may not be distributed or reproduced without permission.',
                              );
            /**
             * Lucida stores its configuration in a serialized text file with
             * <?exit;?> at the beginning of the script.  We will replicate
             * this behavior by serializing its internal data structure
             * and then writing it to the file
             */
            $lucidaConfig = '<?exit;?>'.serialize($tmpConfig);
            $this->file_put_file_contents($this->get_install_path().'/data/galleries.lucida.php',
                                          /** Data must be base64 encoded */
                                          base64_encode($lucidaConfig),
                                          !file_exists('/home/virtual/'.$this->domain.'/'.
                                                       $this->get_install_path().
                                                       '/data/galleries.lucida.php'));
            try {
                /**
                 * Directory might exist if overriding an install, so let's catch the
                 * error is silently discard it.
                 */
                $this->file_create_directory($this->get_install_path().'/data/cache');
            } catch (FileError $e) { /** do nothing */ }
            /**
             * parent::fix_apache_perms(string $mPath, bool $mRecurse)
             * Call fix_apache_dir(string) on any directory that a PHP script
             * will write to.  This function does two things, first it sets the
             * sticky setgid bit on the directory to ensure all files created
             * within there will be under the site's quota.
             *
             * Secondly, it changes the owner to apache, allowing the Web server
             * to write to the file and then uses ACLs
             * {@link http://acl.bestbits.at/} to permit the main user to delete
             * files from the directory.
             */
 
            $this->fix_apache_perms('/data/cache/',true);
            $this->log_status("Done!");
            return true;
        }
 
        /**
         * Clean-up any remaining files, reinitialize variables, et cetera
         */
        public function post_install() {
            /**
             * We have nothing further to do, so just return true
             */
            return true;
        }
 
        /**
         * Double check files exist prior to patch
         */
        public function pre_patch() {
            return true;
        }
 
        /**
         * Call diff command, patch application, do anything else...
         * Not yet implemented.
         */
        public function patch() {
            return new apnscpException("Not yet implemented.");
        }
 
        /**
         * Post-patch cleanup
         */
        public function post_patch() {
            return true;
        }
    }
?>

and finally, if Lucida had a logo, we'd drop a logo named lucida.gif in the driver directory. The source code should go in the storehouse/ directory for Lucida, uncompressed. The state reflected should be one that it's ready to install from your browser. Do not upload compressed applications.

Second Example: punBB

punBB is very similar to the Lucida setup, except now we have a MySQL database that needs to be initialized in order for the forum software to function properly. Redundant comments that appeared in the Lucida example have been snipped out of this example. The XML configuration file, named punBB.xml has been removed as well.

PHP5 driver, punBB.php:
<?php
    /**
     * @class punBB_Install
     * @author Matt Saladna <msaladna@apisnetworks.com>
     *
     * Provides basic hooks for the punBB application in esprit's one-click
     * installation system
     */
    final class punBB_Install extends One_Click_Generic {
        public function __construct($mApp) {
            parent::__construct($mApp);
        }
 
        public function pre_configuration() {
            $this->configuration_options =
                    array('salt'         => array('label' => 'Cookie seed',
                                                   'type' => string,
                                                   'minlength' => 3,
                                                   'constraints' => OPT_REQUIRED,
                                                   'maxlength' => 16,
                                                   'default' => substr(md5(microtime(true)),0,16)),
                          'mysql_db'         => array('label' => 'MySQL database',
                                                   'constraints' => OPT_REQUIRED,
                                                   'default' => 'Photos',
                                                   'type'    => enum,
                                                   'values'  => $this->sql_list_mysql_databases()),
                          'mysql_user'     => array('label' => 'Database username',
                                                   'type' => enum,
                                                   'constraints' => OPT_REQUIRED,
                                                   'values' => array_keys($this->sql_list_mysql_users()),
                                                   'help' => 'User must have access to the database (see &quot;MySQL Manager&quot; provision)',
                                                   'regex' => '!^[a-z0-9A-Z_-]+$!'),
                          'mysql_password'=> array('label' => 'Database password',
                                                   'type' => string, 'default' => '',
                                                   'help' => 'Password for the user account',
                                                   'minlength' => 3, 'maxlength' => 16,
                                                   'constraints' => OPT_REQUIRED,
                                                   'desc' => 'Administrative password',
                                                   'regex' => '!^[a-z0-9A-Z_-]+$!'),
                          'prefix'       => array('label' => 'Database Prefix',
                                                  'type' => string,
                                                  'default' => 'punbb_'),
                          'admin_username' => array('label' => "Forum administrator login",
                                                    'type'  => string,
                                                    'default' => 'admin',
                                                    'constraints' => OPT_REQUIRED,
                                                    'minlength' => 3,
                                                    'maxlength' => 15),
                          'admin_password' => array('label' => "Forum admin password",
                                                    'type' => string,
                                                    'constraints' => OPT_REQUIRED),
                          'admin_email'    => array('label' => "Forum admin e-mail",
                                                    'type'  => string,
                                                    'constraints' => OPT_REQUIRED,
                                                    'minlength' => 7,
                                                    'default' => $this->common_get_admin_email() ));
 
            return true;
        }
 
        public function post_configuration() {
            /**
             * If a user enters incorrect information for the MySQL password
             * corresponding to the user/database combination, setup_mysql()
             * will throw an error.  Catch the error if it happens and gracefully
             * return.
             */
            try {
                $this->setup_mysql($this->postback_options['mysql_user'],
                                   $this->postback_options['mysql_password'],
                                   $this->postback_options['mysql_db']);
            } catch (MySQLError $e) {
                return $e;
            }
            return true;
        }
 
        public function pre_install() {
            return true;
        }
 
        public function install() {
            $this->log_status("Copying files...");
 
            /** Copy files over ... */
            try {
                $this->copy_storehouse("/upload/", "/");
            } catch (Exception $e) {
                /** unrecoverable error happened, bail out */
                return $e;
            }
 
            /**
             * Directory /cache/ will be written to by the Web server, so let's
             * allow apache to write to it with fix_apache_perms()
             *
             * As there is no need to fix any subdirectories under cache, we can
             * omit the second parameter, $mRecurse (default: false)
             */
            $this->log_status("Fixing permissions...");
            $this->fix_apache_perms('/cache/');
            $this->fix_apache_perms('/img/avatars/');
 
            /** Now enter the SQL information */
            $this->log_status("Importing default SQL data...");
            $sql = /** snipped out for length reasons, see "View Source" in esprit for punBB */;
 
            /**
             * open up a temp file and store its contents to be called by
             * parent::mysql_import(string $mScript)
             *
             * Note that parent::setup_mysql() must be called first
             * (see post-configuration section)
             */
            $fname = tempnam("/tmp","punbb_dump");
            $fp = fopen($fname, "w+"); fwrite($fp,$sql); fclose($fp);
 
            try {
                $status = $this->mysql_import($fname);
            } catch (Exception $e) {
                unlink($fname);
                return $e;
            }
 
            unlink($fname);
            /**
             * Finally insert the new configuration file
             */
            $punbb_config = <<<EOF
<?php
\$db_type = 'mysqli';
\$db_host = 'localhost';
\$db_name = '{$this->postback_options['mysql_db']}';
\$db_username = '{$this->postback_options['mysql_user']}';
\$db_password = '{$this->postback_options['mysql_password']}';
\$db_prefix = '{$this->postback_options['prefix']}';
\$p_connect = false;
 
\$cookie_name = 'punbb_cookie';
\$cookie_domain = '';
\$cookie_path = '/';
\$cookie_secure = 0;
\$cookie_seed = '{$this->postback_options['salt']}';
 
define('PUN', 1);
?>
EOF;
            $this->file_put_file_contents($this->get_install_path().'/config.php',
                                          /** Data must be base64 encoded */
                                          base64_encode($punbb_config),
                                          /** overwrite? */
                                          !file_exists('/home/virtual/'.$this->domain.'/'.
                                                       $this->get_install_path().
                                                       '/config.php'));
            $this->log_status("Done!");
            return true;
        }
 
        public function post_install() {
            return true;
        }
 
        public function pre_patch() {
            return true;
        }
 
        public function patch() {
            return new apnscpException("Not yet implemented.");
        }
 
        public function post_patch() {
            return true;
        }
    }
?>

Driver Components

Every driver must set a class property named configuration_options. This class property is responsible for the on-screen configuration. Handled as an array, the left-hand side is the configuration option name and the right-hand side is option parameters. This property should be set in the pre_configuration method. Avoid setting this property in the __construct() method. Necessary initializations occur after the driver is instantiated and before driver_Install::pre_configuration() is called.

The following example:

public function pre_configuration() {
    $this->configuration_options =
        array('your_name' => array('label' => "Your name",
                                       'type'  => string,
                                       'minlength' => 3));                     
}

produces

Image:one-click-ex1.png

Once a user clicks on the "Begin Install" process, a new property is populated, driver_Install::postback_options, accessible from post_configuration and onward. Example for accessing the your_name configuration option:
public function post_configuration() {
    if ($this->postback_options['your_name'] == "Matt") {
        return true;
    } else {
        return false;
    }
}
If the user enters a value of Matt, then the installation process continues to the following function, driver_Install::post_configuration, otherwise it halts with an error.

Image:one-click-return_false.png

Alternatively, if you want to be more verbose in a failed step of the process, you can use an exception in PHP5, with the first parameter being the failed configuration option and second a descriptive message as to why it failed. For example, we can rewrite the aforementioned example to:

public function post_configuration() {
    if ($this->postback_options['your_name'] == "Matt") {
        return true;
    } else {
        return new ArgumentError("your_name","Invalid name");
    }
}

which results in

Image:one-click-return_exception.png

Configuration Parameters

The following is a list of recognized configuration parameters, case sensitive:

Parameter Description
constraints Special constraints that must be enforced for the variable to work, currently just the constant OPT_REQUIRED is supported, meaning there must be data entered. Equivalent to minlength of 1 for strings, ints, doubles and a checkbox being checked for bool types
default Default value to use
help Data that appears on the mouse-over of "inline help"
label Label applied to the left side of the configuration option when displayed in the browser
type Variable type, e.g. bool, int, string,... Depending upon the type, there is a different HTML markup used (see the following section)
minlength Minimum length that the data can be
maxlength Maximum length that the data can be
regex A PCRE that is enforced when checking the input data, delimiters must be used
values An array of values, used in conjunction with types: enum, enum_radio, or set. This may also hold another set of configuration names and parameters in the case of a recursive configuration, i.e. pick a or b, if a then configure c and d, else configure e

Exceptions

The following is a list of recognized exceptions in apnscp esprit:

Exception Type Usage
apnscpException Catch-all used for rare errors (e.g. reflection failing on an invalid class)
ArgumentError Invalid arguments passed to a function
FileError Unable to perform a file operation
IOError Error while reading device, file, or stream
MySQLError Invalid MySQL query/result or unable to connect to MySQL datbase
PermissionError Unable to access function due to insufficient permissions
PostgreSQLError Invalid PostgreSQL query/result or unable to connect to PostgreSQL database
SocketError Error communicating through a TCP/IP socket
TypeError Wrong type, expected bool, got int
ValueError Value listed is not in the accepted state, e.g. values between [1,3] are allowed, value of 4 outside
You can add your own exception by extending the class apnscpException:
class MyError extends apnscpException { 
    public function __construct ($mMessage = NULL, $mCode = 0) { 
        $this->class = __CLASS__; $this->message = $mMessage; $this->code = $mCode;
    }
}

The Storehouse

Upon delegating a new one-click application, two directories are created, <install location>/<application name>/driver/ and <install location>/<application name>/storehouse/. We have already discussed the driver portion and now it's time to explain the storehouse.

The storehouse, as the name implies, is the location of the application uncompressed. copy_storehouse($mSrc, $mDest) uses this location to copy the application to the installation location provided by the user.

Function Reference

Embedded Functions, Native to One-Clicks

There are a handful of functions that are derived solely from the One_Click_Generic class that wraps around every one-click install.

Function:
final protected function copy_storehouse($mSrc, $mDest)
Parameters: string $mSrc: source path, relative to the storehouse

string $mDest: destination path

Throws: FileError, file copy failed

Description: Copies source $mSrc to destination $mDest. Both paths are relative to the storehouse and destination paths, thus normally a parameter of "/" for both $mSrc and $mDest is adequate to recursively all files under <application name>/<application version>/ to <install destination>/. For example, let's say we create an application named "myapp". The tarball, decompressed results in three directories: /upload/, /contrib/, and finally, /docs/. The files a user is interested in uploading to site are located conveniently under /upload/. Thus to copy the application's files, the following will suffice: <php>$this->copy_storehouse("/upload/","/");</php>


Function:
final protected function fix_apache_perms(string $mPath, bool $mRecurse = false)
Parameters: string $mPath: path relative to the installation tree, e.g. supplying a value of /data/ refers to installation location + /data/

bool $mRecurse: recursively apply the function to all files and directories underneath $mPath

Description: One_Click_Install::fix_apache_perms performs two tasks critical to PHP files only. First, it changes ownership of the directory to apache:group id of domain, which permits the Web server to write to the directory. Next, it changes permissions to 2710; the 2 sets a setgid bit on the directory causing any files to be created within there to assume the group id of the parent. In this case, that is the group id the server uses to track quotas per account. Finally, two ACLs are set. The first sets the default mask on all files created within there to be accessible by the main user of the account. The second ACL allows the user to create new files under that directory.


Function:
final protected function get_install_path()
Parameters: None.

Description: Returns the chroot'd base directory of the application installation. If installed under a subdomain,


Function:
final protected function get_install_url()
Parameters: None.

Description: If installed under a subdomain, returns a string of the format http://&lt;subdomain&gt;.&lt;domain&gt;/ otherwise, if relative to the document root, returns http://www.&lt;domain&gt;/&lt;path relative to document root&gt;/.


Function:
final protected function log_status(string $mMsg)
Parameters: string $mMsg: Message to log

Description: Sends the string, $mMsg, to the pseudo-tee file picked up by the AJAX component of the one-click facility. As a result, any string passed to One_Click_Install::$log_status is instantaneously logged and displayed in the Output Status cell.

Function:
final protected function mysql_import(string $mScript)
Parameters: string $mScript: SQL dump file

Description: Attempts to import a script, $mScript on the database. setup_mysql must be called first before this function is activated.


Function:
final protected function pgsql_import(string $mScript)
Parameters: string $mScript: SQL dump file

Description: Attempts to import a script, $mScript on the database. setup_pgsql must be called first before this function is activated.


Function:
final protected function setup_mysql(string $mUser, string $mPassword, string $mDB)
Parameters: string $mUser: MySQL database username

string $mPassword: MySQL database password

string $mDatabase: MySQL database

Throws: MySQLError type if specified username, password, and database are an invalid combination

Description: Creates a new mysqli object and attempts to connect the database. Once successful, a property named One_Click_Install::mysql is defined and can be accessed as a normal mysqli object, example:
$this->mysqli->prepare("INSERT INTO table_name (a, b) VALUES(?,?)");
.
Function:
final protected function setup_pgsql(string $mUser, string $mPassword, string $mDB)
Parameters: string $mUser: PostgreSQL database username

string $mPassword: PostgreSQL database password

string $mDatabase: PostgreSQL database

Throws: PostgreSQLError type if specified username, password, and database are an invalid combination

Description: Creates a new PostgreSQL connection resource and attempts to connect the database. Once successful, a property named One_Click_Install::pgsql is defined and can be accessed as a normal pgsql connection resource, example:
pg_prepare("INSERT INTO table_name (a, b) VALUES(?,?)",$this->pgsql);
.

Generic esprit Commands

Aside from the commands indigenous to the one-click facility, you can also invoke any command provided through esprit. One_Click_Generic has a __call method defined (final & protected) that acts as a generic interceptor to undefined methods. Standard protocol is to invoke the method as you would a SOAP operation, i.e. $this->file_copy($param1, $param2);. This example calls File_Module::Copy with two arguments.

Tips and Tricks

Mounting the One-Click from Linux

If you have access to Linux and SSH (shell access), then you can simplify the editing process by mounting the directory to somewhere on your filesystem.

  • Download shfs
  • Unpack, tar -xvzf shfs-0.35.tar.gz && cd shfs-0.35/
  • If your kernel is setup properly, running make && make install should build and install the kernel module
  • Load the module into the kernel by typing, insmod shfs
  • Mount the remote directory to somewhere in the filesystem, shfsmount username#domain@domain:/var/www/html/<path to one-click>/ /<some mount point>/

And you're done! Open up skeleton.php with your favorite IDE, rename it to the internal name of the application and start coding.

Mounting the One-Click from Windows

Warning: this does not work on Windows XP 64-Bit Edition.

Using Novell's NetDrive application, availble off of Loyola, you can map a FTP directory as a drive on the computer.

Personal tools