mirror of https://github.com/hauke68/Magallanes
Matt Lowe
11 years ago
1 changed files with 669 additions and 0 deletions
@ -0,0 +1,669 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* This allows intergrating IonCube PHP |
||||
* encoder into deployment system |
||||
* It takes the source path renames |
||||
* it to .raw creates a fresh source |
||||
* path and runs ioncube encoder placing |
||||
* encoded files into source folder. |
||||
* Afterwards it removes the old .raw |
||||
* folder This means that we dont have |
||||
* to change the source path within the |
||||
* main scripts and allows the built |
||||
* in rsync and other tasks to operate |
||||
* on the encrypted files. |
||||
* |
||||
* Example enviroment.yaml file at end |
||||
* |
||||
* @todo add support for creating license files. |
||||
* |
||||
* (c) ActWeb 2013 |
||||
* (c) Matt Lowe (marl.scot.1@googlemail.com) |
||||
* |
||||
* Extends Magallanes (c) Andrés Montañez <andres@andresmontanez.com> |
||||
* |
||||
*/ |
||||
namespace Mage\Task\BuiltIn\Ioncube; |
||||
|
||||
use Mage\Task\AbstractTask; |
||||
use Mage\Console; |
||||
use Mage\Task\ErrorWithMessageException; |
||||
use Mage\Task\ErrorWithMessageException; |
||||
use Mage\Task\ErrorWithMessageException; |
||||
use Mage\Task\ErrorWithMessageException; |
||||
use Mage\Task\ErrorWithMessageException; |
||||
|
||||
class EncryptTask extends AbstractTask { |
||||
/** |
||||
* Name of the task |
||||
* |
||||
* @var string |
||||
*/ |
||||
private $name = 'IonCube Encoder'; |
||||
|
||||
/** |
||||
* Array of default Ioncube |
||||
* options |
||||
* |
||||
* @var array |
||||
*/ |
||||
private $default = array (); |
||||
|
||||
/** |
||||
* Array of YAML Ioncube |
||||
* options |
||||
* |
||||
* @var array |
||||
*/ |
||||
private $yaml = array (); |
||||
|
||||
/** |
||||
* Array of file Ioncube |
||||
* options (taken from additional |
||||
* external config file if supplied) |
||||
* |
||||
* @var array |
||||
*/ |
||||
private $file = array (); |
||||
|
||||
/** |
||||
* Source directory as used by |
||||
* main scripts |
||||
* |
||||
* @var string |
||||
*/ |
||||
private $source = ''; |
||||
|
||||
/** |
||||
* Name of tempory folder |
||||
* for source code to be moved |
||||
* to. |
||||
* |
||||
* @var string |
||||
*/ |
||||
private $ionSource = ''; |
||||
|
||||
/** |
||||
* How the default/yaml/project |
||||
* files interact with each other |
||||
* |
||||
* @var string |
||||
*/ |
||||
private $ionOverRide = ''; |
||||
|
||||
/** |
||||
* Config options from the |
||||
* enviroment config file |
||||
* |
||||
* @var array |
||||
*/ |
||||
private $mageConfig = array (); |
||||
|
||||
/** |
||||
* Final version of the IonCube |
||||
* options, after merging all |
||||
* sources together |
||||
* |
||||
* @var array |
||||
*/ |
||||
private $ionCubeConfig = array (); |
||||
|
||||
/** |
||||
* Default encoder version to use |
||||
* for the ioncube encoder |
||||
* |
||||
* @var string |
||||
*/ |
||||
private $encoder = 'ioncube_encoder54'; |
||||
|
||||
/** |
||||
* Name of tempory IonCube Project |
||||
* file, used when running encoder |
||||
* |
||||
* @var string |
||||
*/ |
||||
private $projectFile = ''; |
||||
|
||||
/** |
||||
* (non-PHPdoc) |
||||
* |
||||
* @see \Mage\Task\AbstractTask::getName() |
||||
*/ |
||||
public function getName() { |
||||
return $this->name; |
||||
} |
||||
|
||||
/** |
||||
* (non-PHPdoc) |
||||
* |
||||
* @see \Mage\Task\AbstractTask::init() |
||||
*/ |
||||
public function init() { |
||||
// Get any options specfic to this task |
||||
$this->mageConfig = $this->getConfig ()->environmentConfig( 'ioncube' ); |
||||
/* |
||||
* Get all our IonCube config options |
||||
*/ |
||||
$this->_getAllIonCubeConfigs(); |
||||
/* |
||||
* get the source code location |
||||
*/ |
||||
$this->source = $this->getConfig ()->deployment ( 'from' ); |
||||
/* |
||||
* remove trailing slash if present |
||||
*/ |
||||
if (substr ( $this->source, - 1 ) == DIRECTORY_SEPARATOR) { |
||||
$this->source = substr ( $this->source, 0, - 1 ); |
||||
} |
||||
/* |
||||
* Set the name of the folder that the un-encrypted |
||||
* files will be moved into |
||||
*/ |
||||
$this->ionSource = $this->source . '.raw'; |
||||
/* |
||||
* set the filename for the ioncube project build file |
||||
*/ |
||||
$this->projectFile = $this->source . '.prj'; |
||||
/* |
||||
* Check if we have been given an encoder script |
||||
* If not then we will just use the default |
||||
*/ |
||||
if (isset ( $this->mageConfig ['encoder'] )) { |
||||
$this->encoder = $this->mageConfig ['encoder']; |
||||
} |
||||
/* |
||||
* Check if a differant merge type has been |
||||
* supplied, this defines how the 3 differant |
||||
* config files will be merged together. |
||||
*/ |
||||
if (isset ( $this->mageConfig ['override'] )) { |
||||
$this->ionOverRide = $this->mageConfig ['override']; |
||||
} |
||||
/* |
||||
* now merge all the config options together |
||||
*/ |
||||
$this->ionCubeConfig = $this->mergeConfigFiles (); |
||||
} |
||||
|
||||
/** |
||||
* This gets all the Ioncube configs |
||||
* Basicly it gets the default options contianed within this script |
||||
* It reads any project options from the enviroment.yaml config file |
||||
* It reads any additional options from external project file if set |
||||
* |
||||
* @return void |
||||
*/ |
||||
private function _getAllIonCubeConfigs() |
||||
{ |
||||
|
||||
/* |
||||
* Get a set of default IonCube options |
||||
*/ |
||||
$this->default = $this->getOptionsDefault (); |
||||
/* |
||||
* Check if there is a 'project' section, |
||||
* if so then get the options from there |
||||
*/ |
||||
if (isset ( $this->mageConfig ['project'] )) { |
||||
$this->yaml = $this->getOptionsFromYaml ( $this->mageConfig ['project'] ); |
||||
} else { |
||||
$this->yaml = array ( |
||||
's' => array (), |
||||
'p' => array () |
||||
); |
||||
} |
||||
/* |
||||
* Check if a seperate projectfile has been specified, and if so |
||||
* then read the options from there. |
||||
*/ |
||||
if (isset ( $this->mageConfig ['projectfile'] )) { |
||||
$this->file = $this->getOptionsFromFile ( $this->mageConfig ['projectfile'] ); |
||||
} else { |
||||
$this->file = array ( |
||||
's' => array (), |
||||
'p' => array () |
||||
); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Encrypt the project |
||||
* Steps are as follows : |
||||
* Switch our current source dir to the ioncube srouce dir and create new empty dir to encrypt into |
||||
* Write the IonCube project file (this is the file that controls IonCube encoder) |
||||
* Run IonCube encoder |
||||
* Delete the tempory files that we created (so long as we hadn't set 'keeptemp') |
||||
* Return the result of the IonCube encoder |
||||
* |
||||
* @see \Mage\Task\AbstractTask::run() |
||||
* |
||||
* @return bool |
||||
*/ |
||||
public function run() { |
||||
$this->switchSrcToTmp (); |
||||
$this->writeProjectFile (); |
||||
$result = $this->runIonCube (); |
||||
$this->deleteTmpFiles (); |
||||
return $result; |
||||
} |
||||
|
||||
/** |
||||
* Deletes tempory folder and project file |
||||
* if 'keeptemp' is set then skips delete |
||||
* process |
||||
* |
||||
* @throws ErrorWithMessageException If there was a problem with deleting the tempory files |
||||
* |
||||
* @return void |
||||
*/ |
||||
private function deleteTmpFiles() { |
||||
if (isset ( $this->mageConfig ['keeptemp'] )) { |
||||
return; |
||||
} |
||||
$ret1 = $this->runCommandLocal ( 'rm -Rf ' . $this->ionSource, $out1 ); |
||||
$ret2 = $this->runCommandLocal ( 'rm ' . $this->projectFile, $out2 ); |
||||
if ($ret1 && $ret2) { |
||||
return; |
||||
} |
||||
throw new ErrorWithMessageException ( 'Error deleting temp files :' . $out1 . ' : ' . $out2, 40 ); |
||||
} |
||||
|
||||
/** |
||||
* Builds the ioncube command |
||||
* and runs it, returning the result |
||||
* |
||||
* @return bool |
||||
*/ |
||||
private function runIonCube() { |
||||
$cli = $this->encoder . ' --project-file ' . $this->projectFile . ' ' . $this->ionSource . DIRECTORY_SEPARATOR.'*'; |
||||
$ret = $this->runCommandLocal ( $cli, $out ); |
||||
return $ret; |
||||
} |
||||
|
||||
/** |
||||
* Write the config options into |
||||
* a project file ready for use |
||||
* with ioncube cli |
||||
* |
||||
* @throws ErrorWithMessageException If it cant write the project file |
||||
* |
||||
* @return void |
||||
*/ |
||||
private function writeProjectFile() { |
||||
// array used to build config file into |
||||
$out = array (); |
||||
// set the project destination |
||||
$out [] = '--into ' . $this->source . PHP_EOL; |
||||
// output the switches |
||||
foreach ( $this->ionCubeConfig ['s'] as $key => $value ) { |
||||
if ($value) { |
||||
// switch was set to true, so output it |
||||
$out [] = '--' . $key . PHP_EOL; |
||||
} |
||||
} |
||||
// output the options |
||||
foreach ( $this->ionCubeConfig ['p'] as $key => $value ) { |
||||
// check if we have an array of values |
||||
if (is_array ( $value )) { |
||||
foreach ( $value as $entry ) { |
||||
$out [] = '--' . $key . ' "' . $entry . '"' . PHP_EOL; |
||||
} |
||||
} else { |
||||
// ok just a normal single option |
||||
if (strlen ( $value ) > 0) { |
||||
$out [] = '--' . $key . ' "' . $value . '"' . PHP_EOL; |
||||
} |
||||
} |
||||
} |
||||
$ret = file_put_contents ( $this->projectFile, $out ); |
||||
if (! $ret) { |
||||
// something went wrong |
||||
$this->deleteTmpFiles (); |
||||
throw new ErrorWithMessageException ( 'Unable to create project file.', 20 ); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This merges the 3 config arrays |
||||
* depending on the 'override' option |
||||
* |
||||
* @return array Final config array |
||||
*/ |
||||
private function mergeConfigFiles() { |
||||
/* |
||||
* Options are the order the arrays are in |
||||
* F - Project File |
||||
* Y - YAML config options (enviroment file) |
||||
* D - Default options as stored in script |
||||
* |
||||
* more options could be added to make this a bit more flexable |
||||
* @todo I'm sure this could be combined into a loop to make it easier and shorter |
||||
* |
||||
*/ |
||||
$s = array (); |
||||
$p = array (); |
||||
switch (strtolower ( $this->ionOverRide )) { |
||||
case 'fyd' : |
||||
// FILE / YAML / DEFAULT |
||||
$s = array_merge ( $this->file ['s'], $this->yaml ['s'], $this->default ['s'] ); |
||||
$p = array_merge ( $this->file ['p'], $this->yaml ['p'], $this->default ['p'] ); |
||||
break; |
||||
|
||||
case 'yfd' : |
||||
// YAML / FILE / DEFAULT |
||||
$s = array_merge ( $this->yaml ['s'], $this->file ['s'], $this->default ['s'] ); |
||||
$p = array_merge ( $this->yaml ['p'], $this->file ['p'], $this->default ['p'] ); |
||||
break; |
||||
case 'dyf' : |
||||
// DEFAULT / YAML / FILE |
||||
$s = array_merge ( $this->default ['s'], $this->yaml ['s'], $this->file ['s'] ); |
||||
$p = array_merge ( $this->default ['p'], $this->yaml ['p'], $this->file ['p'] ); |
||||
break; |
||||
case 'd' : |
||||
default : |
||||
// Use defaults only |
||||
$s = $this->default ['s']; |
||||
$p = $this->default ['p']; |
||||
break; |
||||
} |
||||
return array ( |
||||
's' => $s, |
||||
'p' => $p |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Switches the original source |
||||
* code dir to tempory name |
||||
* and recreates orginal dir |
||||
* allows encryption to be done |
||||
* into source dir, so other functions |
||||
* work without changing |
||||
* |
||||
* @throws ErrorWithMessageException If source dir can't be renamed |
||||
* @throws ErrorWithMessageException If original source dir cant be created |
||||
* |
||||
* @return bool |
||||
*/ |
||||
private function switchSrcToTmp() { |
||||
echo "Switching :" . $this->source . " -> "; |
||||
echo "To :" . $this->ionSource . "\n"; |
||||
$ret = $this->runCommandLocal ( 'mv ' . $this->source . ' ' . $this->ionSource, $out ); |
||||
if (! $ret) { |
||||
throw new ErrorWithMessageException ( 'Cant create tmp dir :' . $out, $ret ); |
||||
} |
||||
$ret = $this->runCommandLocal ( 'mkdir -p ' . $this->source, $out ); |
||||
if (! $ret) { |
||||
throw new ErrorWithMessageException ( 'Cant re-create dir :' . $out, $ret ); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Reads a set of options taken from the YAML config |
||||
* Compares keys against the default ioncube settings |
||||
* if a key doesnt appear in the default options, it |
||||
* is ignored |
||||
* |
||||
* return array |
||||
*/ |
||||
private function getOptionsFromYaml($options) { |
||||
$s = array (); |
||||
$p = array (); |
||||
foreach ( $options as $key => $value ) { |
||||
if (array_key_exists ( $key, $this->default ['s'] )) { |
||||
$s [$key] = true; |
||||
} |
||||
if (array_key_exists ( $key, $this->default ['p'] )) { |
||||
$p [$key] = $value; |
||||
} |
||||
} |
||||
return array ( |
||||
's' => $s, |
||||
'p' => $p |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* reads an existing ioncube project |
||||
* file. |
||||
* |
||||
* @return array |
||||
*/ |
||||
private function getOptionsFromFile($fileName) { |
||||
$s = array (); |
||||
$p = array (); |
||||
$fileContents = file_get_contents ( $fileName ); |
||||
/* |
||||
* split the config file on every occurance of '--' at start of a line |
||||
* Adds a PHP_EOL at the start, so we can catch the first '--' |
||||
*/ |
||||
$entrys = explode ( PHP_EOL . '--', PHP_EOL . $fileContents ); |
||||
foreach ( $entrys as $line ) { |
||||
$line = trim ( $line ); |
||||
if ($line != '') { |
||||
/* |
||||
* get position of first space |
||||
* so we can split the options out |
||||
*/ |
||||
$str = strpos ( $line, ' ' ); |
||||
if ($str === false) { |
||||
/* |
||||
* Ok, no spaces found, so take this as a single line |
||||
*/ |
||||
$str = strlen ( $line ); |
||||
} |
||||
$key = substr ( $line, $str ); |
||||
$value = substr ( $line, $str + 1 ); |
||||
if ((array_key_exists ( $key, $this->default ['s'] ))) { |
||||
/* |
||||
* ok this key appears in the switch config |
||||
* so store it as a switch |
||||
*/ |
||||
$s [$key] = true; |
||||
} |
||||
if ((array_key_exists ( $key, $this->default ['p'] ))) { |
||||
/* |
||||
* Ok this key exists in the parameter section, |
||||
* So store it allong with its value |
||||
*/ |
||||
$p [$key] = $this->splitParam ( $value ); |
||||
} |
||||
} |
||||
} |
||||
return array ( |
||||
's' => $s, |
||||
'p' => $p |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Takes supplied line and splits it if required |
||||
* into an array |
||||
* returns ether the array, or a plain |
||||
* string. |
||||
* Allows options to be spread accross several lines |
||||
* |
||||
* @param $string String to split |
||||
* |
||||
* @return mixed |
||||
*/ |
||||
private function splitParam($string) { |
||||
$split = explode ( PHP_EOL, $string ); |
||||
if ($split === false) { |
||||
// nothing found, so return a blank string |
||||
return ''; |
||||
} |
||||
if (count ( $split ) == 1) { |
||||
return $split [0]; |
||||
} else { |
||||
return $split; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* returns an array of default ioncube options |
||||
* This is also used as a 'filter' for the YAML |
||||
* and Config files, if an option hasnt got an |
||||
* entry in this list, then it can not be set |
||||
* via the VAML or Config files |
||||
* |
||||
* @return array |
||||
*/ |
||||
private function getOptionsDefault() { |
||||
$s = array (); |
||||
$p = array (); |
||||
// Set the switches |
||||
$s ['allow-encoding-into-source'] = false; |
||||
|
||||
$s ['ascii'] = false; |
||||
$s ['binary'] = true; |
||||
|
||||
$s ['replace-target'] = true; |
||||
$s ['merge-target'] = false; |
||||
$s ['rename-target'] = false; |
||||
$s ['update-target'] = false; |
||||
|
||||
$s ['only-include-encoded-files'] = false; |
||||
|
||||
$s ['use-hard-links'] = false; |
||||
|
||||
$s ['without-keeping-file-perms'] = false; |
||||
$s ['without-keeping-file-times'] = false; |
||||
$s ['without-keeping-file-owner'] = false; |
||||
|
||||
$s ['no-short-open-tags'] = false; |
||||
|
||||
$s ['ignore-strict-warnings'] = false; |
||||
$s ['ignore-deprecated-warnings'] = false; |
||||
|
||||
$s ['without-runtime-loader-support'] = false; |
||||
$s ['without-loader-check'] = false; |
||||
|
||||
$s ['disable-auto-prepend-append'] = true; |
||||
|
||||
$s ['no-doc-comments'] = true; |
||||
|
||||
// Now set the params |
||||
$p ['encrypt'] [] = '*.tpl.html'; |
||||
$p ['encode'] = array (); |
||||
$p ['copy'] = array (); |
||||
$p ['ignore'] = array ( |
||||
'.git', |
||||
'.svn', |
||||
'.mage', |
||||
'.gitignore', |
||||
'.gitkeep', |
||||
'nohup.out' |
||||
); |
||||
$p ['keep'] = array (); |
||||
$p ['obfuscate'] = ''; |
||||
$p ['obfuscation-key'] = ''; |
||||
$p ['obfuscation-exclusion-file'] = ''; |
||||
$p ['expire-in'] = '7d'; |
||||
$p ['expire-on'] = ''; |
||||
$p ['allowed-server'] = ''; |
||||
$p ['with-license'] = 'license.txt'; |
||||
$p ['passphrase'] = ''; |
||||
$p ['license-check'] = ''; |
||||
$p ['apply-file-user'] = ''; |
||||
$p ['apply-file-group'] = ''; |
||||
$p ['register-autoglobal'] = array (); |
||||
$p ['message-if-no-loader'] = ''; |
||||
$p ['action-if-no-loader'] = ''; |
||||
$p ['loader-path'] = ''; |
||||
$p ['preamble-file'] = ''; |
||||
$p ['add-comment'] = array (); |
||||
$p ['add-comments'] = ''; |
||||
$p ['loader-event'] = array (); |
||||
$p ['callback-file'] = ''; |
||||
$p ['property'] = ''; |
||||
$p ['propertys'] = ''; |
||||
$p ['include-if-property'] = array (); |
||||
$p ['optimise'] = 'max'; |
||||
$p ['shell-script-line'] = ''; |
||||
$p ['min-loader-version'] = ''; |
||||
|
||||
return array ( |
||||
's' => $s, |
||||
'p' => $p |
||||
); |
||||
} |
||||
} |
||||
/** |
||||
* |
||||
* Example evirmonment YAML file : |
||||
* |
||||
#master |
||||
deployment: |
||||
user: marl |
||||
from: ./ |
||||
to: /var/www/test1 |
||||
source: |
||||
type: git |
||||
repository: git@bitbucket.org:myuser/myproject.git |
||||
from: master |
||||
ioncube: test |
||||
|
||||
releases: |
||||
enabled: true |
||||
symlink: current |
||||
directory: releases |
||||
hosts: |
||||
- localhost |
||||
tasks: |
||||
pre-deploy: |
||||
- ioncube/encrypt |
||||
on-deply: |
||||
post-deploy: |
||||
|
||||
ioncube: |
||||
override: dyf |
||||
keeptemp: |
||||
encoder: ioncube_encoder54 |
||||
projfile: project.prj |
||||
project: |
||||
replace-target: |
||||
binary: |
||||
ignore-deprecated-warnings: |
||||
ignore-strict-warnings: |
||||
ignore: |
||||
- _* |
||||
- templates_c/* |
||||
- *~ |
||||
- database.md |
||||
- specs/ |
||||
- composer.json |
||||
- README.md |
||||
- .git/ |
||||
- .project |
||||
- .settings/ |
||||
- .buildpath |
||||
message-if-no-loader: "System error No Loader" |
||||
passphrase: "My really secure passphrase" |
||||
encrypt: |
||||
- templates/* |
||||
add-comment: |
||||
- 'Comment 1' |
||||
- 'Comment 2' |
||||
- "(c) ACTweb 2013" |
||||
- "Draft Version" |
||||
|
||||
loader-event: |
||||
- corrupt-file=Corupted files |
||||
- expired-file=System needs updated |
||||
- no-permissions=Not allowed on this server |
||||
- clock-skew=Time incorect |
||||
- license-not-found=License not installed |
||||
- license-corrupt=Something wrong with your license |
||||
- license-expired=Out of time |
||||
- license-property-invalid=Invalid license data |
||||
- license-header-invalid=Files corupted |
||||
- license-server-invalid=Server problem |
||||
- unauth-including-file=Sorry these files can only be used within defined software |
||||
- unauth-included-file=Crtical Software Error |
||||
- unauth-append-prepend-file=System can not be used with PHP Prepend/Append set |
||||
|
||||
*/ |
Loading…
Reference in new issue