2016-01-30 20:28:43 +00:00
< ? php
2017-12-14 23:10:47 +00:00
/* --------------------------------------------------------------------------------------------------------| www . vdm . io |------/
__ __ _ _____ _ _ __ __ _ _ _
\ \ / / | | | __ \ | | | | | \ / | | | | | | |
\ \ / / _ _ ___ | | _ | | | | _____ _____ | | ___ _ __ _ __ ___ ___ _ __ | | _ | \ / | ___ | | _ | | __ ___ __ | |
\ \ / / _ ` / __| __| | | | |/ _ \ \ / / _ \ |/ _ \| '_ \| '_ ` _ \ / _ \ '_ \| __| | |\/| |/ _ \ __| ' _ \ / _ \ / _ ` |
\ / ( _ | \__ \ | _ | | __ | | __ / \ V / __ / | ( _ ) | | _ ) | | | | | | __ / | | | | _ | | | | __ / | _ | | | | ( _ ) | ( _ | |
\ / \__ , _ | ___ / \__ | | _____ / \___ | \_ / \___ | _ | \___ /| . __ /| _ | | _ | | _ | \___ | _ | | _ | \__ | | _ | | _ | \___ | \__ | _ | | _ | \___ / \__ , _ |
| |
| _ |
/-------------------------------------------------------------------------------------------------------------------------------/
@ version 2.6 . x
@ created 30 th April , 2015
@ package Component Builder
@ subpackage compiler . php
@ author Llewellyn van der Merwe < http :// www . vdm . io >
@ my wife Roline van der Merwe < http :// www . vdm . io />
@ copyright Copyright ( C ) 2015. All Rights Reserved
@ license GNU / GPL Version 2 or later - http :// www . gnu . org / licenses / gpl - 2.0 . html
Builds Complex Joomla Components
/----------------------------------------------------------------------------------------------------------------------------- */
2016-01-30 20:28:43 +00:00
// No direct access to this file
defined ( '_JEXEC' ) or die ( 'Restricted access' );
2016-02-29 11:05:37 +00:00
// Use the component builder autoloader
2016-02-26 00:20:09 +00:00
ComponentbuilderHelper :: autoLoader ();
2016-01-30 20:28:43 +00:00
/**
* Compiler class
*/
2016-02-26 00:20:09 +00:00
class Compiler extends Infusion
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
/*
* The Temp path
*
* @ var string
*/
2017-12-14 23:10:47 +00:00
2016-02-26 00:20:09 +00:00
private $tempPath ;
2017-12-14 23:10:47 +00:00
2017-02-13 23:24:38 +00:00
/*
* The timer
*
* @ var string
*/
private $time_start ;
private $time_end ;
2017-12-14 23:10:47 +00:00
public $secondsCompiled ;
public $filepath = '' ;
2016-01-30 20:28:43 +00:00
// fixed pathes
2017-12-14 23:10:47 +00:00
protected $dynamicIntegration = false ;
protected $backupPath = false ;
protected $repoPath = false ;
protected $addCustomCodeAt = array ();
2016-01-30 20:28:43 +00:00
/**
* Constructor
*/
2017-12-14 23:10:47 +00:00
public function __construct ( $config = array ())
2016-01-30 20:28:43 +00:00
{
2017-02-13 23:24:38 +00:00
// to check the compiler speed
$this -> time_start = microtime ( true );
2018-01-19 10:27:47 +00:00
// first we run the perent constructors
2016-02-26 00:20:09 +00:00
if ( parent :: __construct ( $config ))
2016-01-30 20:28:43 +00:00
{
// set temp directory
2017-12-14 23:10:47 +00:00
$comConfig = JFactory :: getConfig ();
$this -> tempPath = $comConfig -> get ( 'tmp_path' );
2016-01-30 20:28:43 +00:00
// set some folder paths in relation to distribution
if ( $config [ 'addBackup' ])
{
2017-12-14 23:10:47 +00:00
$this -> backupPath = $this -> params -> get ( 'backup_folder_path' , $this -> tempPath ) . '/' . $this -> componentBackupName . '.zip' ;
$this -> dynamicIntegration = true ;
2016-01-30 20:28:43 +00:00
}
2017-09-18 00:18:23 +00:00
if ( $config [ 'addRepo' ])
2016-01-30 20:28:43 +00:00
{
2017-12-14 23:10:47 +00:00
$this -> repoPath = $this -> params -> get ( 'git_folder_path' , null );
2016-01-30 20:28:43 +00:00
}
2017-02-01 13:17:04 +00:00
// remove site folder if not needed (TODO add check if custom script was moved to site folder then we must do a more complex cleanup here)
2017-01-20 00:16:50 +00:00
if ( $this -> removeSiteFolder )
{
// first remove the files and folders
$this -> removeFolder ( $this -> componentPath . '/site' );
// clear form component xml
2017-12-14 23:10:47 +00:00
$xmlPath = $this -> componentPath . '/' . $this -> fileContentStatic [ '###component###' ] . '.xml' ;
2017-11-16 04:37:32 +00:00
$componentXML = ComponentbuilderHelper :: getFileContents ( $xmlPath );
2017-12-14 23:10:47 +00:00
$textToSite = ComponentbuilderHelper :: getBetween ( $componentXML , '<files folder="site">' , '</files>' );
$textToSiteLang = ComponentbuilderHelper :: getBetween ( $componentXML , '<languages folder="site">' , '</languages>' );
$componentXML = str_replace ( array ( '<files folder="site">' . $textToSite . " </files> " , '<languages folder="site">' . $textToSiteLang . " </languages> " ), array ( '' , '' ), $componentXML );
$this -> writeFile ( $xmlPath , $componentXML );
2017-01-20 00:16:50 +00:00
}
2016-02-26 00:20:09 +00:00
// now update the files
2017-02-01 13:17:04 +00:00
if ( ! $this -> updateFiles ())
2016-01-30 20:28:43 +00:00
{
2017-02-01 13:17:04 +00:00
return false ;
}
// now insert into the new files
2017-02-13 23:24:38 +00:00
if ( $this -> getCustomCode ())
2017-12-14 23:10:47 +00:00
{
2017-02-13 23:24:38 +00:00
$this -> addCustomCode ();
2017-02-01 13:17:04 +00:00
}
2017-02-13 23:24:38 +00:00
// set the lang data now
$this -> setLangFileData ();
2017-10-26 16:43:51 +00:00
// set the language notice if it was set
if ( ComponentbuilderHelper :: checkArray ( $this -> langNot ) || ComponentbuilderHelper :: checkArray ( $this -> langSet ))
{
if ( ComponentbuilderHelper :: checkArray ( $this -> langNot ))
{
foreach ( $this -> langNot as $tag => $percentage )
{
2017-12-14 23:10:47 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'The <b>%s</b> language has %s% translated, you will need to translate %s% of the language strings before it will be added.' , $tag , $percentage , $this -> percentageLanguageAdd ), 'Warning' );
2017-10-26 16:43:51 +00:00
}
2017-12-14 23:10:47 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( '<b>You can change this percentage of translated strings required in the global options of JCB.</b><br />Please watch this <a href=%s>tutorial for more help surrounding the JCB translations manager</a>.' , '"https://youtu.be/zzAcVkn_cWU?list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE" target="_blank" title="JCB Tutorial surrounding Translation Manager"' ), 'Notice' );
2017-10-26 16:43:51 +00:00
}
// set why the strings were added
$whyAddedLang = JText :: sprintf ( 'because more then %s% of the strings have been translated.' , $this -> percentageLanguageAdd );
if ( $this -> debugLinenr )
{
$whyAddedLang = JText :: _ ( 'because the debugging mode is on. (debug line numbers)' );
}
// show languages that were added
if ( ComponentbuilderHelper :: checkArray ( $this -> langSet ))
{
foreach ( $this -> langSet as $tag => $percentage )
{
2017-12-14 23:10:47 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'The <b>%s</b> language has %s% translated. Was addeded %s' , $tag , $percentage , $whyAddedLang ), 'Notice' );
2017-10-26 16:43:51 +00:00
}
}
}
2017-02-01 13:17:04 +00:00
// move the update server into place
$this -> setUpdateServer ();
2017-03-08 04:49:54 +00:00
// set the global counters
$this -> setCountingStuff ();
2017-02-13 23:24:38 +00:00
// build read me
$this -> buildReadMe ();
2017-02-01 13:17:04 +00:00
// zip the component
if ( ! $this -> zipComponent ())
{
2017-02-13 23:24:38 +00:00
// done with error
2017-02-01 13:17:04 +00:00
return false ;
2016-01-30 20:28:43 +00:00
}
2017-12-14 13:30:21 +00:00
// do lang mismatch check
if ( ComponentbuilderHelper :: checkArray ( $this -> langMismatch ))
{
if ( ComponentbuilderHelper :: checkArray ( $this -> langMatch ))
{
$mismatch = array_diff ( array_unique ( $this -> langMismatch ), array_unique ( $this -> langMatch ));
}
else
{
$mismatch = array_unique ( $this -> langMismatch );
}
// set a notice if we have a mismatch
2017-12-14 23:10:47 +00:00
if ( isset ( $mismatch ) && ComponentbuilderHelper :: checkArray ( $mismatch ))
2017-12-14 13:30:21 +00:00
{
if ( count ( $mismatch ) > 1 )
{
$this -> app -> enqueueMessage ( JText :: _ ( '<h3>Please check the following mismatching Joomla.JText language constants.</h3>' ), 'Warning' );
}
else
{
$this -> app -> enqueueMessage ( JText :: _ ( '<h3>Please check the following mismatch Joomla.JText language constant.</h3>' ), 'Warning' );
}
// add the mismatching issues
foreach ( $mismatch as $string )
{
2017-12-14 23:10:47 +00:00
$constant = $this -> langPrefix . '_' . ComponentbuilderHelper :: safeString ( $string , 'U' );
$this -> app -> enqueueMessage ( JText :: sprintf ( 'The <b>Joomla.JText._(\'%s\')</b> language constant for (%s) does not have a corresponding JText::Script() decalaration.' , $constant , $string ), 'Warning' );
2017-12-14 13:30:21 +00:00
}
$this -> app -> enqueueMessage ( '<hr />' , 'Warning' );
}
}
2018-02-06 10:55:46 +00:00
// check if we should add a EXTERNALCODE notice
if ( ComponentbuilderHelper :: checkArray ( $this -> externalCodeString ))
{
// number of external code strings
$externalCount = count ( $this -> externalCodeString );
// the correct string
$externalCodeString = ( $externalCount == 1 ) ? JText :: _ ( 'code/string' ) : JText :: _ ( 'code/strings' );
// the notice
$this -> app -> enqueueMessage ( JText :: sprintf ( 'There has been <b>%s - %s</b> added to this component as EXTERNALCODE. To avoid shipping your component with malicious %s always make sure that the correct <b>code/string values</b> were used.' , $externalCount , $externalCodeString , $externalCodeString ), 'Notice' );
}
2017-02-13 23:24:38 +00:00
// end the timer here
$this -> time_end = microtime ( true );
$this -> secondsCompiled = $this -> time_end - $this -> time_start ;
// completed the compilation
2017-02-01 13:17:04 +00:00
return true ;
2016-01-30 20:28:43 +00:00
}
return false ;
}
2017-12-14 23:10:47 +00:00
2016-09-03 21:44:47 +00:00
/**
* Set the line number in comments
*
* @ param int $nr The line number
*
* @ return void
*
*/
private function setLine ( $nr )
{
2017-04-06 08:47:51 +00:00
if ( $this -> debugLinenr )
2016-09-03 21:44:47 +00:00
{
2017-12-14 23:10:47 +00:00
return ' [Compiler ' . $nr . ']' ;
2016-09-03 21:44:47 +00:00
}
return '' ;
}
2017-12-14 23:10:47 +00:00
2017-02-01 13:17:04 +00:00
/**
* Set the dynamic data to the created fils
*
* @ return bool true on success
*
*/
2016-02-26 00:20:09 +00:00
protected function updateFiles ()
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
if ( isset ( $this -> newFiles [ 'static' ]) && ComponentbuilderHelper :: checkArray ( $this -> newFiles [ 'static' ]) && isset ( $this -> newFiles [ 'dynamic' ]) && ComponentbuilderHelper :: checkArray ( $this -> newFiles [ 'dynamic' ]))
2017-04-05 13:21:10 +00:00
{
2016-02-26 00:20:09 +00:00
// get the bom file
2017-11-16 04:37:32 +00:00
$bom = ComponentbuilderHelper :: getFileContents ( $this -> bomPath );
2016-02-26 00:20:09 +00:00
// first we do the static files
foreach ( $this -> newFiles [ 'static' ] as $static )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
if ( JFile :: exists ( $static [ 'path' ]))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
$this -> fileContentStatic [ '###FILENAME###' ] = $static [ 'name' ];
$php = '' ;
2017-12-14 23:10:47 +00:00
if ( ComponentbuilderHelper :: checkFileType ( $static [ 'name' ], 'php' ))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
$php = " <?php \n " ;
2016-01-30 20:28:43 +00:00
}
2017-11-16 04:37:32 +00:00
$string = ComponentbuilderHelper :: getFileContents ( $static [ 'path' ]);
2017-12-14 23:10:47 +00:00
if ( strpos ( $string , '###BOM###' ) !== false )
2016-01-30 20:28:43 +00:00
{
2017-12-14 23:10:47 +00:00
list ( $wast , $code ) = explode ( '###BOM###' , $string );
$string = $php . $bom . $code ;
2017-02-11 02:24:26 +00:00
$answer = $this -> setPlaceholders ( $string , $this -> fileContentStatic , 3 );
2016-02-26 00:20:09 +00:00
// add to zip array
2017-12-14 23:10:47 +00:00
$this -> writeFile ( $static [ 'path' ], $answer );
2016-01-30 20:28:43 +00:00
}
else
{
2017-02-11 02:24:26 +00:00
$answer = $this -> setPlaceholders ( $string , $this -> fileContentStatic , 3 );
2016-02-26 00:20:09 +00:00
// add to zip array
2017-12-14 23:10:47 +00:00
$this -> writeFile ( $static [ 'path' ], $answer );
2016-01-30 20:28:43 +00:00
}
2017-12-14 23:10:47 +00:00
$this -> lineCount = $this -> lineCount + substr_count ( $answer , PHP_EOL );
2016-01-30 20:28:43 +00:00
}
2016-02-26 00:20:09 +00:00
}
// now we do the dynamic files
foreach ( $this -> newFiles [ 'dynamic' ] as $view => $files )
{
if ( isset ( $this -> fileContentDynamic [ $view ]) && ComponentbuilderHelper :: checkArray ( $this -> fileContentDynamic [ $view ]))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
foreach ( $files as $file )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
if ( $file [ 'view' ] == $view )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
if ( JFile :: exists ( $file [ 'path' ]))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
$this -> fileContentStatic [ '###FILENAME###' ] = $file [ 'name' ];
2017-02-01 13:17:04 +00:00
// do some weird stuff to improve the verion and dates being added to the license
$this -> fixLicenseValues ( $file );
2016-02-26 00:20:09 +00:00
$php = '' ;
2017-12-14 23:10:47 +00:00
if ( ComponentbuilderHelper :: checkFileType ( $file [ 'name' ], 'php' ))
2016-02-26 00:20:09 +00:00
{
$php = " <?php \n " ;
}
2017-11-16 04:37:32 +00:00
$string = ComponentbuilderHelper :: getFileContents ( $file [ 'path' ]);
2017-12-14 23:10:47 +00:00
if ( strpos ( $string , '###BOM###' ) !== false )
2016-02-26 00:20:09 +00:00
{
2017-12-14 23:10:47 +00:00
list ( $bin , $code ) = explode ( '###BOM###' , $string );
$string = $php . $bom . $code ;
2017-02-11 02:24:26 +00:00
$answer = $this -> setPlaceholders ( $string , $this -> fileContentStatic , 3 );
$answer = $this -> setPlaceholders ( $answer , $this -> fileContentDynamic [ $view ], 3 );
2016-02-26 00:20:09 +00:00
// add to zip array
2017-12-14 23:10:47 +00:00
$this -> writeFile ( $file [ 'path' ], $answer );
2016-02-26 00:20:09 +00:00
}
else
{
2017-02-11 02:24:26 +00:00
$answer = $this -> setPlaceholders ( $string , $this -> fileContentStatic , 3 );
$answer = $this -> setPlaceholders ( $answer , $this -> fileContentDynamic [ $view ], 3 );
2016-02-26 00:20:09 +00:00
// add to zip array
2017-12-14 23:10:47 +00:00
$this -> writeFile ( $file [ 'path' ], $answer );
2016-02-26 00:20:09 +00:00
}
2017-12-14 23:10:47 +00:00
$this -> lineCount = $this -> lineCount + substr_count ( $answer , PHP_EOL );
2016-01-30 20:28:43 +00:00
}
}
}
}
2017-02-01 13:17:04 +00:00
// free up some memory
unset ( $this -> fileContentDynamic [ $view ]);
2016-01-30 20:28:43 +00:00
}
2017-02-01 13:17:04 +00:00
// free up some memory
unset ( $this -> newFiles [ 'dynamic' ]);
return true ;
}
return false ;
}
2017-12-14 23:10:47 +00:00
2017-02-01 13:17:04 +00:00
/**
* move the local update server xml file to a remote ftp server
*
* @ return void
*
*/
protected function setUpdateServer ()
{
// move the update server to host
2017-08-25 01:46:12 +00:00
if ( $this -> componentData -> add_update_server == 1 && $this -> componentData -> update_server_target == 1 && isset ( $this -> updateServerFileName ) && $this -> dynamicIntegration )
2017-02-01 13:17:04 +00:00
{
2017-12-14 23:10:47 +00:00
$xml_update_server_path = $this -> componentPath . '/' . $this -> updateServerFileName . '.xml' ;
2017-02-01 13:17:04 +00:00
// make sure we have the correct file
2018-02-15 00:42:39 +00:00
if ( JFile :: exists ( $xml_update_server_path ) && isset ( $this -> componentData -> update_server ))
2017-02-01 13:17:04 +00:00
{
2018-02-17 22:47:01 +00:00
// use FTP
if ( $this -> componentData -> update_server_protocol == 1 )
2017-02-01 13:17:04 +00:00
{
2018-02-17 22:47:01 +00:00
// Get the basic encription.
$basickey = ComponentbuilderHelper :: getCryptKey ( 'basic' );
// Get the encription object.
$basic = new FOFEncryptAes ( $basickey , 128 );
if ( ! empty ( $this -> componentData -> update_server ) && $basickey && ! is_numeric ( $this -> componentData -> update_server ) && $this -> componentData -> update_server === base64_encode ( base64_decode ( $this -> componentData -> update_server , true )))
{
// basic decript data update_server.
$this -> componentData -> update_server = rtrim ( $basic -> decryptString ( $this -> componentData -> update_server ), " \0 " );
}
// now move the file
$this -> moveFileToFtpServer ( $xml_update_server_path , $this -> componentData -> update_server );
}
// use SFTP
elseif ( $this -> componentData -> update_server_protocol == 2 )
{
if ( $sftp = ComponentbuilderHelper :: getSftp (( int ) $this -> componentData -> update_server ))
{
// now move the file
if ( ! $sftp -> put ( $sftp -> remote_server_path . $this -> updateServerFileName . '.xml' , ComponentbuilderHelper :: getFileContents ( $xml_update_server_path , null )))
{
$this -> app -> enqueueMessage ( JText :: sprintf ( 'The <b>%s</b> file could not be moved to <b>%s</b> path on <b>%s</b> server.' , $this -> updateServerFileName . '.xml' , $sftp -> remote_server_path , $sftp -> remote_server_name ), 'Error' );
}
// remove the local file
JFile :: delete ( $xml_update_server_path );
}
2017-02-01 13:17:04 +00:00
}
}
}
}
// link canges made to views into the file license
protected function fixLicenseValues ( $data )
{
2017-02-02 12:17:31 +00:00
// check if these files have its own config data)
2017-11-06 14:04:23 +00:00
if ( isset ( $data [ 'config' ]) && ComponentbuilderHelper :: checkArray ( $data [ 'config' ]) && $this -> componentData -> mvc_versiondate == 1 )
2017-02-01 13:17:04 +00:00
{
foreach ( $data [ 'config' ] as $key => $value )
2016-02-26 00:20:09 +00:00
{
2017-02-02 11:54:07 +00:00
if ( '###VERSION###' === $key )
2016-01-30 20:28:43 +00:00
{
2017-02-01 13:17:04 +00:00
// hmm we sould in some way make it known that this version number
// is not in relation the the project but to the file only... any ideas?
// this is the best for now...
if ( 1 == $value )
2016-01-30 20:28:43 +00:00
{
2017-02-01 13:17:04 +00:00
$value = '@first version of this MVC' ;
}
else
{
2017-12-14 23:10:47 +00:00
$value = '@update number ' . $value . ' of this MVC' ;
2016-01-30 20:28:43 +00:00
}
}
2017-02-01 13:17:04 +00:00
$this -> fileContentStatic [ $key ] = $value ;
2016-01-30 20:28:43 +00:00
}
2016-02-26 00:20:09 +00:00
return true ;
2016-01-30 20:28:43 +00:00
}
2017-02-01 13:17:04 +00:00
// else insure to reset to global
$this -> fileContentStatic [ '###CREATIONDATE###' ] = $this -> fileContentStatic [ '###CREATIONDATE###GLOBAL' ];
$this -> fileContentStatic [ '###BUILDDATE###' ] = $this -> fileContentStatic [ '###BUILDDATE###GLOBAL' ];
$this -> fileContentStatic [ '###VERSION###' ] = $this -> fileContentStatic [ '###VERSION###GLOBAL' ];
2016-01-30 20:28:43 +00:00
}
2017-03-08 04:49:54 +00:00
// set all global numbers
protected function setCountingStuff ()
{
// what is the size in terms of an A4 book
2017-12-14 23:10:47 +00:00
$this -> pageCount = round ( $this -> lineCount / 56 );
2017-03-08 04:49:54 +00:00
// setup the unrealistic numbers
2017-12-14 23:10:47 +00:00
$this -> folderSeconds = $this -> folderCount * 5 ;
$this -> fileSeconds = $this -> fileCount * 5 ;
$this -> lineSeconds = $this -> lineCount * 10 ;
$this -> seconds = $this -> folderSeconds + $this -> fileSeconds + $this -> lineSeconds ;
$this -> totalHours = round ( $this -> seconds / 3600 );
$this -> totalDays = round ( $this -> totalHours / 8 );
2017-03-08 04:49:54 +00:00
// setup the more realistic numbers
2017-12-14 23:10:47 +00:00
$this -> secondsDebugging = $this -> seconds / 4 ;
$this -> secondsPlanning = $this -> seconds / 7 ;
$this -> secondsMapping = $this -> seconds / 10 ;
$this -> secondsOffice = $this -> seconds / 6 ;
$this -> actualSeconds = $this -> folderSeconds + $this -> fileSeconds + $this -> lineSeconds + $this -> secondsDebugging + $this -> secondsPlanning + $this -> secondsMapping + $this -> secondsOffice ;
$this -> actualTotalHours = round ( $this -> actualSeconds / 3600 );
$this -> actualTotalDays = round ( $this -> actualTotalHours / 8 );
$this -> debuggingHours = round ( $this -> secondsDebugging / 3600 );
$this -> planningHours = round ( $this -> secondsPlanning / 3600 );
$this -> mappingHours = round ( $this -> secondsMapping / 3600 );
$this -> officeHours = round ( $this -> secondsOffice / 3600 );
2017-03-08 04:49:54 +00:00
// the actual time spent
2017-12-14 23:10:47 +00:00
$this -> actualHoursSpent = $this -> actualTotalHours - $this -> totalHours ;
$this -> actualDaysSpent = $this -> actualTotalDays - $this -> totalDays ;
2017-03-08 04:49:54 +00:00
// calculate the projects actual time frame of completion
2017-12-14 23:10:47 +00:00
$this -> projectWeekTime = round ( $this -> actualTotalDays / 5 , 1 );
$this -> projectMonthTime = round ( $this -> actualTotalDays / 24 , 1 );
2017-03-08 04:49:54 +00:00
}
2017-12-14 23:10:47 +00:00
2017-02-13 23:24:38 +00:00
private function buildReadMe ()
{
// do a final run to update the readme file
$two = 0 ;
foreach ( $this -> newFiles [ 'static' ] as $static )
{
if (( 'README.md' === $static [ 'name' ] || 'README.txt' === $static [ 'name' ]) && $this -> componentData -> addreadme && JFile :: exists ( $static [ 'path' ]))
{
$this -> setReadMe ( $static [ 'path' ]);
$two ++ ;
}
if ( $two == 2 )
{
break ;
}
}
unset ( $this -> newFiles [ 'static' ]);
}
2017-12-14 23:10:47 +00:00
2017-02-13 23:24:38 +00:00
private function setReadMe ( $path )
2016-10-23 22:48:26 +00:00
{
// set readme data if not set already
if ( ! isset ( $this -> fileContentStatic [ '###LINE_COUNT###' ]) || $this -> fileContentStatic [ '###LINE_COUNT###' ] != $this -> lineCount )
{
$this -> buildReadMeData ();
}
// get the file
2017-11-16 04:37:32 +00:00
$string = ComponentbuilderHelper :: getFileContents ( $path );
2016-10-23 22:48:26 +00:00
// update the file
2017-02-11 02:24:26 +00:00
$answer = $this -> setPlaceholders ( $string , $this -> fileContentStatic );
2016-10-23 22:48:26 +00:00
// add to zip array
2017-12-14 23:10:47 +00:00
$this -> writeFile ( $path , $answer );
}
2016-10-23 22:48:26 +00:00
private function buildReadMeData ()
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// set some defaults
2017-12-14 23:10:47 +00:00
$this -> fileContentStatic [ '###LINE_COUNT###' ] = $this -> lineCount ;
$this -> fileContentStatic [ '###FIELD_COUNT###' ] = $this -> fieldCount ;
$this -> fileContentStatic [ '###FILE_COUNT###' ] = $this -> fileCount ;
$this -> fileContentStatic [ '###FOLDER_COUNT###' ] = $this -> folderCount ;
$this -> fileContentStatic [ '###PAGE_COUNT###' ] = $this -> pageCount ;
$this -> fileContentStatic [ '###folders###' ] = $this -> folderSeconds ;
$this -> fileContentStatic [ '###foldersSeconds###' ] = $this -> folderSeconds ;
$this -> fileContentStatic [ '###files###' ] = $this -> fileSeconds ;
$this -> fileContentStatic [ '###filesSeconds###' ] = $this -> fileSeconds ;
$this -> fileContentStatic [ '###lines###' ] = $this -> lineSeconds ;
$this -> fileContentStatic [ '###linesSeconds###' ] = $this -> lineSeconds ;
$this -> fileContentStatic [ '###seconds###' ] = $this -> actualSeconds ;
$this -> fileContentStatic [ '###actualSeconds###' ] = $this -> actualSeconds ;
$this -> fileContentStatic [ '###totalHours###' ] = $this -> totalHours ;
$this -> fileContentStatic [ '###totalDays###' ] = $this -> totalDays ;
$this -> fileContentStatic [ '###debugging###' ] = $this -> secondsDebugging ;
$this -> fileContentStatic [ '###secondsDebugging###' ] = $this -> secondsDebugging ;
$this -> fileContentStatic [ '###planning###' ] = $this -> secondsPlanning ;
$this -> fileContentStatic [ '###secondsPlanning###' ] = $this -> secondsPlanning ;
$this -> fileContentStatic [ '###mapping###' ] = $this -> secondsMapping ;
$this -> fileContentStatic [ '###secondsMapping###' ] = $this -> secondsMapping ;
$this -> fileContentStatic [ '###office###' ] = $this -> secondsOffice ;
$this -> fileContentStatic [ '###secondsOffice###' ] = $this -> secondsOffice ;
$this -> fileContentStatic [ '###actualTotalHours###' ] = $this -> actualTotalHours ;
$this -> fileContentStatic [ '###actualTotalDays###' ] = $this -> actualTotalDays ;
$this -> fileContentStatic [ '###debuggingHours###' ] = $this -> debuggingHours ;
$this -> fileContentStatic [ '###planningHours###' ] = $this -> planningHours ;
$this -> fileContentStatic [ '###mappingHours###' ] = $this -> mappingHours ;
$this -> fileContentStatic [ '###officeHours###' ] = $this -> officeHours ;
$this -> fileContentStatic [ '###actualHoursSpent###' ] = $this -> actualHoursSpent ;
$this -> fileContentStatic [ '###actualDaysSpent###' ] = $this -> actualDaysSpent ;
$this -> fileContentStatic [ '###projectWeekTime###' ] = $this -> projectWeekTime ;
$this -> fileContentStatic [ '###projectMonthTime###' ] = $this -> projectMonthTime ;
2016-01-30 20:28:43 +00:00
}
2016-02-26 00:20:09 +00:00
private function zipComponent ()
2016-01-30 20:28:43 +00:00
{
2017-09-18 00:18:23 +00:00
// before we zip the component we first need to move it to the repo folder if set
if ( ComponentbuilderHelper :: checkString ( $this -> repoPath ))
2016-02-26 00:20:09 +00:00
{
2017-09-18 00:18:23 +00:00
// set the repo path
2017-12-14 23:10:47 +00:00
$repoFullPath = $this -> repoPath . '/com_' . $this -> componentData -> sales_name . '__joomla_' . $this -> joomlaVersion ;
2016-02-26 00:20:09 +00:00
// remove old data
2017-09-18 00:18:23 +00:00
$this -> removeFolder ( $repoFullPath , $this -> componentData -> toignore );
2016-02-26 00:20:09 +00:00
// set the new data
2017-09-18 00:18:23 +00:00
JFolder :: copy ( $this -> componentPath , $repoFullPath , '' , true );
2016-02-26 00:20:09 +00:00
}
// the name of the zip file to create
2017-12-14 23:10:47 +00:00
$this -> filepath = $this -> tempPath . '/' . $this -> componentFolderName . '.zip' ;
2016-02-26 00:20:09 +00:00
//create the zip file
2017-03-20 22:07:14 +00:00
if ( ComponentbuilderHelper :: zip ( $this -> componentPath , $this -> filepath ))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// now move to backup if zip was made and backup is requered
2016-11-22 05:48:55 +00:00
if ( $this -> backupPath && $this -> dynamicIntegration )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
JFile :: copy ( $this -> filepath , $this -> backupPath );
2016-01-30 20:28:43 +00:00
}
2017-12-14 23:10:47 +00:00
2016-02-26 00:20:09 +00:00
// move to sales server host
2017-08-25 01:46:12 +00:00
if ( $this -> componentData -> add_sales_server == 1 && $this -> dynamicIntegration )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// make sure we have the correct file
2018-02-15 00:42:39 +00:00
if ( isset ( $this -> componentData -> sales_server ))
2016-01-30 20:28:43 +00:00
{
2018-02-17 22:47:01 +00:00
// use FTP
if ( $this -> componentData -> sales_server_protocol == 1 )
2016-01-30 20:28:43 +00:00
{
2018-02-17 22:47:01 +00:00
// Get the basic encription.
$basickey = ComponentbuilderHelper :: getCryptKey ( 'basic' );
// Get the encription object.
$basic = new FOFEncryptAes ( $basickey , 128 );
if ( ! empty ( $this -> componentData -> sales_server ) && $basickey && ! is_numeric ( $this -> componentData -> sales_server ) && $this -> componentData -> sales_server === base64_encode ( base64_decode ( $this -> componentData -> sales_server , true )))
{
// basic decript data sales_server.
$this -> componentData -> sales_server = rtrim ( $basic -> decryptString ( $this -> componentData -> sales_server ), " \0 " );
}
// now move the file
$this -> moveFileToFtpServer ( $this -> filepath , $this -> componentData -> sales_server , $this -> componentSalesName . '.zip' , false );
}
// use SFTP
elseif ( $this -> componentData -> sales_server_protocol == 2 )
{
if ( $sftp = ComponentbuilderHelper :: getSftp (( int ) $this -> componentData -> sales_server ))
{
// now move the file
if ( ! $sftp -> put ( $sftp -> remote_server_path . $this -> componentFolderName . '.zip' , ComponentbuilderHelper :: getFileContents ( $this -> filepath , null )))
{
$this -> app -> enqueueMessage ( JText :: sprintf ( 'The <b>%s</b> file could not be moved to <b>%s</b> path on <b>%s</b> server.' , $this -> componentFolderName . '.zip' , $sftp -> remote_server_path , $sftp -> remote_server_name ), 'Error' );
}
}
2016-01-30 20:28:43 +00:00
}
}
}
2016-02-26 00:20:09 +00:00
// remove the component folder since we are done
if ( $this -> removeFolder ( $this -> componentPath ))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
return true ;
2016-01-30 20:28:43 +00:00
}
}
2016-02-26 00:20:09 +00:00
return false ;
}
2017-12-14 23:10:47 +00:00
2016-02-26 00:20:09 +00:00
private function moveFileToFtpServer ( $localPath , $clientInput , $remote = null , $removeLocal = true )
{
// get the ftp opbject
$ftp = $this -> getFTP ( $clientInput );
// chack if we are conected
if ( $ftp instanceof JClientFtp && $ftp -> isConnected ())
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// move the file
2017-12-14 23:10:47 +00:00
if ( $ftp -> store ( $localPath , $remote ))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// if moved then remove the file from repository
if ( $removeLocal )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
JFile :: delete ( $localPath );
2016-01-30 20:28:43 +00:00
}
}
2016-02-26 00:20:09 +00:00
// at the end close the conection
$ftp -> quit ();
2016-01-30 20:28:43 +00:00
}
}
2017-12-14 23:10:47 +00:00
2016-02-26 00:20:09 +00:00
private function getFTP ( $clientInput )
2016-01-30 20:28:43 +00:00
{
2017-08-25 01:46:12 +00:00
$s1GnAtnr3 = md5 ( $clientInput );
if ( isset ( $this -> FTP [ $s1GnAtnr3 ]) && $this -> FTP [ $s1GnAtnr3 ] instanceof JClientFtp )
2016-01-30 20:28:43 +00:00
{
2017-08-25 01:46:12 +00:00
// return the FTP instance
return $this -> FTP [ $s1GnAtnr3 ];
2016-01-30 20:28:43 +00:00
}
2016-02-26 00:20:09 +00:00
else
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// make sure we have a string and it is not default or empty
if ( ComponentbuilderHelper :: checkString ( $clientInput ))
2016-01-30 20:28:43 +00:00
{
2017-08-25 01:46:12 +00:00
// turn into variables
parse_str ( $clientInput ); // because of this I am using strand variable naming to avoid any collisions.
2016-02-26 00:20:09 +00:00
// set options
if ( isset ( $options ) && ComponentbuilderHelper :: checkArray ( $options ))
2016-01-30 20:28:43 +00:00
{
2017-08-25 01:46:12 +00:00
foreach ( $options as $o__p0t1on => $vAln3 )
2016-01-30 20:28:43 +00:00
{
2017-08-25 01:46:12 +00:00
if ( 'timeout' === $o__p0t1on )
2016-01-30 20:28:43 +00:00
{
2017-08-25 01:46:12 +00:00
$options [ $o__p0t1on ] = ( int ) $vAln3 ;
2016-01-30 20:28:43 +00:00
}
2017-08-25 01:46:12 +00:00
if ( 'type' === $o__p0t1on )
2016-01-30 20:28:43 +00:00
{
2017-08-25 01:46:12 +00:00
$options [ $o__p0t1on ] = ( string ) $vAln3 ;
2016-01-30 20:28:43 +00:00
}
}
}
2016-02-26 00:20:09 +00:00
else
{
$options = array ();
}
// get ftp object
if ( isset ( $host ) && $host != 'HOSTNAME' && isset ( $port ) && $port != 'PORT_INT' && isset ( $username ) && $username != 'user@name.com' && isset ( $password ) && $password != 'password' )
{
// load for reuse
2017-08-25 01:46:12 +00:00
$this -> FTP [ $s1GnAtnr3 ] = JClientFtp :: getInstance ( $host , $port , $options , $username , $password );
// return the FTP instance
return $this -> FTP [ $s1GnAtnr3 ];
2016-02-26 00:20:09 +00:00
}
2016-01-30 20:28:43 +00:00
}
}
return false ;
}
2017-12-14 23:10:47 +00:00
2017-02-13 23:24:38 +00:00
protected function addCustomCode ()
2017-02-01 13:17:04 +00:00
{
2017-02-11 02:24:26 +00:00
// reset all these
$this -> clearFromPlaceHolders ( 'view' );
$this -> clearFromPlaceHolders ( 'arg' );
2017-12-14 23:10:47 +00:00
foreach ( $this -> customCode as $nr => $target )
2017-02-01 13:17:04 +00:00
{
// reset each time per custom code
$fingerPrint = array ();
2017-12-14 23:10:47 +00:00
if ( isset ( $target [ 'hashtarget' ][ 0 ]) && $target [ 'hashtarget' ][ 0 ] > 3 && isset ( $target [ 'path' ]) && ComponentbuilderHelper :: checkString ( $target [ 'path' ]) && isset ( $target [ 'hashtarget' ][ 1 ]) && ComponentbuilderHelper :: checkString ( $target [ 'hashtarget' ][ 1 ]))
2017-02-01 13:17:04 +00:00
{
2017-12-14 23:10:47 +00:00
$file = $this -> componentPath . '/' . $target [ 'path' ];
$size = ( int ) $target [ 'hashtarget' ][ 0 ];
$hash = $target [ 'hashtarget' ][ 1 ];
$cut = $size - 1 ;
$found = false ;
$bites = 0 ;
$lineBites = array ();
$replace = array ();
2017-02-01 13:17:04 +00:00
if ( $target [ 'type' ] == 1 && isset ( $target [ 'hashendtarget' ][ 0 ]) && $target [ 'hashendtarget' ][ 0 ] > 0 )
{
2017-12-14 23:10:47 +00:00
$foundEnd = false ;
$sizeEnd = ( int ) $target [ 'hashendtarget' ][ 0 ];
$hashEnd = $target [ 'hashendtarget' ][ 1 ];
$cutEnd = $sizeEnd - 1 ;
2017-02-01 13:17:04 +00:00
}
else
{
// replace to the end of the file
2017-12-14 23:10:47 +00:00
$foundEnd = true ;
2017-02-01 13:17:04 +00:00
}
2017-12-14 23:10:47 +00:00
$counter = 0 ;
2017-02-11 02:24:26 +00:00
// check if file exist
2017-02-01 13:17:04 +00:00
if ( JFile :: exists ( $file ))
{
foreach ( new SplFileObject ( $file ) as $lineNumber => $lineContent )
{
2017-02-04 00:22:17 +00:00
// if not found we need to load line bites per line
$lineBites [ $lineNumber ] = ( int ) mb_strlen ( $lineContent , '8bit' );
2017-02-01 13:17:04 +00:00
if ( ! $found )
{
2017-02-04 00:22:17 +00:00
$bites = ( int ) bcadd ( $lineBites [ $lineNumber ], $bites );
2017-02-01 13:17:04 +00:00
}
if ( $found && ! $foundEnd )
{
2017-02-04 00:22:17 +00:00
$replace [] = ( int ) $lineBites [ $lineNumber ];
2017-02-01 13:17:04 +00:00
// we musk keep last three lines to dynamic find target entry
$fingerPrint [ $lineNumber ] = trim ( $lineContent );
// check lines each time if it fits our target
if ( count ( $fingerPrint ) === $sizeEnd && ! $foundEnd )
{
2017-12-14 23:10:47 +00:00
$fingerTest = md5 ( implode ( '' , $fingerPrint ));
2017-02-01 13:17:04 +00:00
if ( $fingerTest === $hashEnd )
{
// we are done here
$foundEnd = true ;
2017-12-14 23:10:47 +00:00
$replace = array_slice ( $replace , 0 , count ( $replace ) - $sizeEnd );
2017-02-01 13:17:04 +00:00
break ;
}
else
{
$fingerPrint = array_slice ( $fingerPrint , - $cutEnd , $cutEnd , true );
}
}
2017-02-04 00:22:17 +00:00
continue ;
2017-02-01 13:17:04 +00:00
}
if ( $found && $foundEnd )
{
2017-02-04 00:22:17 +00:00
$replace [] = ( int ) $lineBites [ $lineNumber ];
2017-02-01 13:17:04 +00:00
}
// we musk keep last three lines to dynamic find target entry
$fingerPrint [ $lineNumber ] = trim ( $lineContent );
// check lines each time if it fits our target
if ( count ( $fingerPrint ) === $size && ! $found )
{
2017-12-14 23:10:47 +00:00
$fingerTest = md5 ( implode ( '' , $fingerPrint ));
2017-02-01 13:17:04 +00:00
if ( $fingerTest === $hash )
{
// we are done here
$found = true ;
// reset in case
$fingerPrint = array ();
// break if it is insertion
if ( $target [ 'type' ] == 2 )
{
break ;
}
}
else
{
$fingerPrint = array_slice ( $fingerPrint , - $cut , $cut , true );
}
}
}
if ( $found )
{
2017-12-14 23:10:47 +00:00
$placeholder = $this -> getPlaceHolder (( int ) $target [ 'comment_type' ] . $target [ 'type' ], $target [ 'id' ]);
$data = $placeholder [ 'start' ] . PHP_EOL . $this -> setPlaceholders ( $target [ 'code' ], $this -> placeholders ) . $placeholder [ 'end' ] . PHP_EOL ;
2017-02-01 13:17:04 +00:00
if ( $target [ 'type' ] == 2 )
{
// found it now add code from the next line
$this -> addDataToFile ( $file , $data , $bites );
}
elseif ( $target [ 'type' ] == 1 && $foundEnd )
{
// found it now add code from the next line
2017-02-13 23:24:38 +00:00
$this -> addDataToFile ( $file , $data , $bites , ( int ) array_sum ( $replace ));
2017-02-01 13:17:04 +00:00
}
else
{
2017-02-04 00:22:17 +00:00
// Load escaped code since the target endhash has changed
$this -> loadEscapedCode ( $file , $target , $lineBites );
2018-02-06 10:55:46 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'Custom code could not be added to <b>%s</b> please review the file at <b>line %s</b>. This could be due to a change to lines below the custom code.' , $target [ 'path' ], $target [ 'from_line' ]), 'Warning' );
2017-02-01 13:17:04 +00:00
}
}
else
{
2017-02-04 00:22:17 +00:00
// Load escaped code since the target hash has changed
$this -> loadEscapedCode ( $file , $target , $lineBites );
2018-02-06 10:55:46 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'Custom code could not be added to <b>%s</b> please review the file at <b>line %s</b>. This could be due to a change to lines above the custom code.' , $target [ 'path' ], $target [ 'from_line' ]), 'Warning' );
2017-02-01 13:17:04 +00:00
}
}
else
{
2017-02-04 00:22:17 +00:00
// Give developer a notice that file is not found.
2018-02-06 10:55:46 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'File <b>%s</b> could not be found, so the custom code for this file could not be addded.' , $target [ 'path' ]), 'Warning' );
2017-02-01 13:17:04 +00:00
}
}
}
}
2017-02-04 00:22:17 +00:00
protected function loadEscapedCode ( $file , $target , $lineBites )
{
2017-10-30 18:50:56 +00:00
// get comment type
if ( $target [ 'comment_type' ] == 1 )
{
$commentType = " // " ;
$_commentType = " " ;
}
else
{
$commentType = " <!-- " ;
$_commentType = " --> " ;
}
2017-02-04 00:22:17 +00:00
// escape the code
2017-02-09 16:11:10 +00:00
$code = explode ( PHP_EOL , $target [ 'code' ]);
2017-10-30 18:50:56 +00:00
$code = PHP_EOL . $commentType . implode ( $_commentType . PHP_EOL . $commentType , $code ) . $_commentType . PHP_EOL ;
2017-02-04 00:22:17 +00:00
// get place holders
2017-12-14 23:10:47 +00:00
$placeholder = $this -> getPlaceHolder (( int ) $target [ 'comment_type' ] . $target [ 'type' ], $target [ 'id' ]);
2017-02-04 00:22:17 +00:00
// build the data
2017-12-14 23:10:47 +00:00
$data = $placeholder [ 'start' ] . $code . $placeholder [ 'end' ] . PHP_EOL ;
2017-02-04 00:22:17 +00:00
// get the bites before insertion
2017-12-14 23:10:47 +00:00
$bitBucket = array ();
foreach ( $lineBites as $line => $value )
2017-02-04 00:22:17 +00:00
{
if ( $line < $target [ 'from_line' ])
{
$bitBucket [] = $value ;
}
}
// add to the file
$this -> addDataToFile ( $file , $data , ( int ) array_sum ( $bitBucket ));
}
2017-02-01 13:17:04 +00:00
// Thanks to http://stackoverflow.com/a/16813550/1429677
protected function addDataToFile ( $file , $data , $position , $replace = null )
{
2017-02-11 02:24:26 +00:00
// start the process
2017-02-01 13:17:04 +00:00
$fpFile = fopen ( $file , " rw+ " );
$fpTemp = fopen ( 'php://temp' , " rw+ " );
2017-02-11 02:24:26 +00:00
// make a copy of the file
stream_copy_to_stream ( $fpFile , $fpTemp );
// move to the position where we should add the data
fseek ( $fpFile , $position );
// Add the data
fwrite ( $fpFile , $data );
// truncate file at the end of the data that was added
$remove = bcadd ( $position , mb_strlen ( $data , '8bit' ));
ftruncate ( $fpFile , $remove );
// check if this was a replacement of data
2017-02-01 13:17:04 +00:00
if ( $replace )
{
$position = bcadd ( $position , $replace );
}
2017-02-11 02:24:26 +00:00
// move to the position of the data that should remain below the new data
fseek ( $fpTemp , $position );
// copy that remaining data to the file
2017-02-01 13:17:04 +00:00
stream_copy_to_stream ( $fpTemp , $fpFile ); // @Jack
2017-02-11 02:24:26 +00:00
// done close both files
fclose ( $fpFile );
fclose ( $fpTemp );
2017-12-14 23:10:47 +00:00
2017-02-11 02:24:26 +00:00
// any help to improve this is welcome...
2017-02-01 13:17:04 +00:00
}
2017-12-14 23:10:47 +00:00
2016-01-30 20:28:43 +00:00
}