#!/bin/env php PHK Manager - File: /src/PHK/Build/Creator.php
Package Home

PHK Manager

PHK Home

File: /src/PHK/Build/Creator.php

Size:10409
Storage flags:

<?php
//=============================================================================
//
// Copyright Francois Laupretre <phk@tekwire.net>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
//=============================================================================
/**
* @copyright Francois Laupretre <phk@tekwire.net>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, V 2.0
* @category PHK
* @package PHK
*///==========================================================================

namespace PHK\Build {

if (!
class_exists('PHK\Build\Creator',false))
{
//============================================================================
/**
* The package creator class
*
* Note: If this file is part of a PHK package (usual case), it is
* absolutely mandatory that Automap and PHK classes as package's files
* are the same as the Automap and PHK classes included in the prolog. Which
* means that the package must be generated from its files. If it is not the
* case, packages generated from this creator package will display wrong version
* information.
*
* API status: Public
* Included in the PHK PHP runtime: No
* Implemented in the extension: No
*///==========================================================================

class Creator extends \PHK\Base
{
const 
MIN_RUNTIME_VERSION='3.0.0'// The minimum version of PHK runtime able to
    // understand the packages I produce. Checked against PHK\Base::RUNTIME_VERSION
    // or, if PECL, PHP_PHK_VERSION.

//-----

public $prolog=null;
public 
$code=null;
private 
$interp='';

//-----
// init a new empty package.

public function __construct($mnt,$path,$flags)
{
parent::__construct(null,$mnt,$path,$flags,time());

$this->options=array();
$this->buildInfo=array('build_timestamp' => time());
}

//---------

public function ftree()
{
return 
$this->proxy()->ftree();
}

//---------

public function setOptions($opt)
{
$this->options=$opt;
}

//---------

public function updateOption($name,$a)
{
$this->options[$name]=$a;
}

//---------

public function updateBuildInfo($name,$a)
{
$this->buildInfo[$name]=$a;
}

//---------
// Allows to use an alternate prolog

public function setProlog($data)
{
$this->prolog=$data;
}

//---------

private function processPhpCode(&$buffer)
{
$buffer=str_replace('?><?php','',$buffer);
$buffer=str_replace("?>\n<?php",'',$buffer);

foreach (array(
'creator','plain_file') as $pcode)
    {
    if (!
$this->option("prolog_code_$pcode"))
        {
        
$token=strtoupper($pcode);
        while ((
$pos=strpos($buffer,'<'.$token.'>'))!==false)
            {
            if ((
$pos2=strpos($buffer,'</'.$token.'>',$pos))===false)
                throw new \
Exception('Cannot find end of <'.$token.'> section');
            
$buffer=substr_replace($buffer,'',$pos,$pos2-$pos+15);
            }
        }
    }

// Strip whitespaces from the prolog

if (!$this->option('plain_prolog'))
    {
    
$buffer=\PHK\Virtual\File::stripWhitespaces($buffer);
    }
}

//---------
// Build runtime PHP code
//-- $dir= base dir where files are stored. In a package, it is the package's
//-- base URI, otherwise, it is the base of the source tree.

public function buildPhpCode($dir)
{
\
Phool\Display::trace('Building PHP runtime');

$this->code='';

$automap_base=$dir;
if (! \
PHK\Mgr::isPhkUri(__FILE__)) $automap_base .= '/external/automap';
$this->code .= \PHK\Tools\Util::readFile($automap_base.'/src/Automap/Mgr.php');
$this->code .= \PHK\Tools\Util::readFile($automap_base.'/src/Automap/Tools/Display.php');
$this->code .= \PHK\Tools\Util::readFile($automap_base.'/src/Automap/Map.php');
$this->code .= \PHK\Tools\Util::readFile($automap_base.'/src/Automap/Tools/Check.php');

$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Tools/Util.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/PkgFile.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Cache.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Proxy.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Mgr.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Base.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Backend.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Stream/Wrapper.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Stream/Backend.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Virtual/DC.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Virtual/Tree.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Virtual/Node.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Virtual/Dir.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Virtual/File.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/Web/Info.php');
$this->code .= \PHK\Tools\Util::readFile($dir.'/src/PHK/UnitTest/PHPUnit.php');

$this->processPhpCode($this->code);

$this->code=str_replace('<?php','',$this->code);
$this->code=str_replace('?>','',$this->code);
}

//---------
//-- Build prolog code
//-- $dir= base dir where files are stored

public function buildProlog($dir)
{
\
Phool\Display::trace('Building prolog');

$this->prolog = \PHK\Tools\Util::readFile($dir.'/scripts/prolog.php');

//-- The four FF chars turn unicode detection off (see PHP bug #42396)

$this->prolog .= '<?php __halt_compiler(); ?>'.str_repeat(chr(255),4);

$this->processPhpCode($this->prolog);
}

//---------
// Create a new section and fill it with some data

public function addSection($name,$data,$modifiers=array())
{
\
Phool\Display::trace("Adding section <$name>");

$this->proxy()->stree()->mkfile($name,$data,$modifiers);
}

//---------

public function dump($path=null)
{
if (
is_null($path)) $path=$this->path();
\
Phool\Display::trace("Writing package to disk ($path)");

$base_dir=dirname(dirname(dirname(__DIR__)));
$this->buildPhpCode($base_dir);

//-- Get creator version

if (\PHK\Mgr::isPhkUri(__FILE__))
    {
    
$pkg=\PHK\Mgr::instance(\PHK\Mgr::uriToMnt(__FILE__));
    
$creatorVersion=$pkg->option('version');
    }
else
    {
    
$creatorVersion=getenv('SOFTWARE_VERSION');
    }
if (!
is_string($creatorVersion))
    throw new \
Exception('Cannot determine creator version');

//-- Build prolog if not already set

if (is_null($this->prolog)) $this->buildProlog($base_dir);

//-- Build FILES part and FTREE section
// Build map, strip sources, etc...

$needed_extensions=new \PHK\Tools\ItemLister;
$this->proxy()->ftree()->walk('getNeededExtensions',$this,$needed_extensions);

$map=new \Automap\Build\Creator();
list(
$files_structure,$files_data)=$this->proxy()->ftree()->export($this,$map);

$this->addSection('FTREE',$files_structure);
unset(
$files_structure);

//-- Build Automap section

if ($map->symbolCount())
    
$this->addSection(\PHK\Proxy::AUTOMAP_SECTION,$map->serialize());

$this->updateBuildInfo('map_defined',($map->symbolCount()!=0));

//-- Tabs sections / PHK icon

foreach(array('tabs/left.gif','tabs/right.gif','tabs/bottom.gif'
    
,'tabs/tabs.css.php','phk_logo.png') as $f)
    {
    
$source=$base_dir.'/etc/'.$f;
    
$this->addSection('STATIC/'.$f,\PHK\Tools\Util::readFile($source));
    }

//-- Build info

$this->updateBuildInfo('phk_creator_version',$creatorVersion);
$this->updateBuildInfo('automap_creator_version',\Automap\Build\Creator::VERSION);
$this->updateBuildInfo('automap_minVersion',\Automap\Build\Creator::MIN_RUNTIME_VERSION);

//-- Record the user-specified needed extensions

foreach(\PHK\Tools\Util::mkArray($this->option('required_extensions')) as $ext)
    {
    if (
$ext!==''$needed_extensions->add($ext,true);
    }

//-- Flush sections
//-- Add the uncompress needed extensions to the user required extensions

$this->proxy()->stree()->walk('getNeededExtensions',$this,$needed_extensions);

$ext=array_keys($needed_extensions->get());
if (
count($ext)) $this->updateOption('required_extensions',$ext);

//-- Ensure mime_types, if present, is an array

if (!is_null($this->option('mime_types')))
    
$this->updateOption('mime_types'
        
,\PHK\Tools\Util::mkArray($this->option('mime_types')));

$this->addSection('OPTIONS',serialize($this->options()));

// Add build info section

$this->addSection('BUILD_INFO',serialize($this->buildInfo()));

// Now, dump the section tree

\PHK\Tools\Util::trace('--- Sections');

list(
$sections_structure,$sections_data)=$this->proxy()->stree()->export($this);

//---

$prolog_offset=\PHK\Proxy::INTERP_LEN+\PHK\Proxy::MAGIC_LINE_LEN;
$code_offset=$prolog_offset+strlen($this->prolog);
$sections_structure_offset=$code_offset+strlen($this->code);
$sections_offset=$sections_structure_offset+strlen($sections_structure);
$files_offset=$sections_offset+strlen($sections_data);
$sig_offset=$files_offset+strlen($files_data);
$file_size=$sig_offset;

$buf=\PHK\Proxy::fixCrc(\PHK\Proxy::interpBlock($this->interp)
    .
'<?php '.\PHK\Proxy::MAGIC_STRING
    
.' M'  .str_pad(self::MIN_RUNTIME_VERSION,\PHK\Proxy::VERSION_SIZE)
    .
' V'  .str_pad($creatorVersion,\PHK\Proxy::VERSION_SIZE)
    .
' FS' .str_pad($file_size,\PHK\Proxy::OFFSET_SIZE)
    .
' PO' .str_pad($prolog_offset,\PHK\Proxy::OFFSET_SIZE)
    .
' SSO'.str_pad($sections_structure_offset,\PHK\Proxy::OFFSET_SIZE)
    .
' STO'.str_pad($sections_offset,\PHK\Proxy::OFFSET_SIZE)
    .
' FTO'.str_pad($files_offset,\PHK\Proxy::OFFSET_SIZE)
    .
' SIO'.str_pad($sig_offset,\PHK\Proxy::OFFSET_SIZE)
    .
' CRC00000000'
    
.' PCO'.str_pad($code_offset,\PHK\Proxy::OFFSET_SIZE)
    .
' PCS'.str_pad(strlen($this->code),\PHK\Proxy::OFFSET_SIZE)
    .
' ?>'
    
.$this->prolog.$this->code.$sections_structure.$sections_data.$files_data);

\
PHK\Tools\Util::trace('Writing PHK file to '.$path);
\
PHK\Tools\Util::atomicWrite($path,$buf);
}

//---
// End of class
//===========================================================================
// End of class_exists
//===========================================================================
// End of namespace
//===========================================================================
?>

For more information about the PHK package format: http://phk.tekwire.net