Files
wingedit.pl/wp-content/plugins/wp-all-import/libraries/XmlImportTemplateCodeGenerator.php
2024-11-04 20:48:19 +01:00

426 lines
12 KiB
PHP

<?php
/**
* @author Olexandr Zanichkovsky <olexandr.zanichkovsky@zophiatech.com>
* @package General
*/
require_once dirname(__FILE__) . '/XmlImportConfig.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstSequence.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstText.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstPrint.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstInteger.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstFloat.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstString.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstXPath.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstFunction.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstWith.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstForeach.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstIf.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstMath.php';
require_once dirname(__FILE__) . '/ast/XmlImportAstSpintax.php';
/**
* Is used to generate a PHP code from AST (Abstract Syntax Tree)
*/
class XmlImportTemplateCodeGenerator
{
/**
* Top level statement sequence
*
* @var XmlImportAstSequence
*/
private $sequence;
/**
* statement sequence stack
*
* @var array
*/
private $sequenceStack = array();
/**
* SimpleXmlElement variable number
*
* @var int
*/
private $xmlVariableNumber = 0;
/**
* Previous statement
*
* @var XmlImportAstStatement
*/
private $previousStatement = null;
/**
* Stack of SimpleXmlElement instances
*
* @var array
*/
private $xmlStack = array();
/**
* Whether PHP tag is open
*
* @var bool
*/
private $isPhpTagOpen = false;
/**
* Creates new instance
*
* @param XmlImportAstSequence $sequence
*/
public function __construct(XmlImportAstSequence $sequence)
{
$this->sequence = $sequence;
}
/**
* Generates the code and returns the filename under which it was stored in
* cache directory. If $filename is null then it is generated automatically
*
* @param string $filename
* @return string
*/
public function generate($filename = null)
{
$result = '';
if (count($this->sequence->getVariables()))
{
$var = '$x' . $this->xmlVariableNumber++;
array_push($this->xmlStack, $var);
$result .= $this->openPhpTag() . $var . ' = $this->xml;' ;
}
$result .= $this->generateForSequence($this->sequence);
if (count($this->sequence->getVariables()))
{
array_pop($this->xmlStack);
}
// grab import ID for manual and cron import runs
$input = new PMXI_Input();
$import_id = $input->get('id');
if (empty($import_id)){
$import_id = $input->get('import_id');
}
if ( ! $filename or ! @is_writable($filename)) {
$filename = @tempnam(XmlImportConfig::getInstance()->getCacheDirectory(), 'xim_id_'. $import_id);
}
if ( ! $filename or ! @is_writable($filename) ){
$uploads = wp_upload_dir();
$targetDir = $uploads['basedir'] . DIRECTORY_SEPARATOR . PMXI_Plugin::TEMP_DIRECTORY;
$filename = $targetDir . DIRECTORY_SEPARATOR . wp_unique_filename($targetDir, 'tmpfile_id_'. $import_id);
}
file_put_contents($filename, $result);
$sleep = apply_filters( 'wp_all_import_shard_delay', 0 );
usleep($sleep);
//@chmod($filename, 0666);
return $filename;
}
/**
* Generates code for a statement sequence
*
* @param XmlImportAstSequence $sequence
* @return string
*/
private function generateForSequence(XmlImportAstSequence $sequence)
{
array_push($this->sequenceStack, $sequence);
$result = '';
if (count($sequence->getVariableDefinitions()) > 0)
{
$result .= $this->openPhpTag();
foreach ($sequence->getVariableDefinitions() as $xpath)
{
$result .= PHP_EOL . str_replace('{{XML}}', $this->xmlStack[count($this->xmlStack) - 1], $xpath);
}
$result .= PHP_EOL;
}
foreach ($sequence->getStatements() as $statement)
{
$result .= $this->generateForStatement($statement);
}
array_pop($this->sequenceStack);
return $result;
}
/**
* Generates code for a statement
*
* @param XmlImportAstStatement $statement
* @return string
*/
private function generateForStatement(XmlImportAstStatement $statement)
{
$result = '';
if ($statement instanceof XmlImportAstText)
{
$result .= $this->closePhpTag();
$text = preg_replace('%<\?|\?>%', '<?php echo "$0"; ?>', $statement->getValue()); // escape php tags
if ($this->previousStatement instanceof XmlImportAstPrint && (strpos($text, "\n") === 0 || strpos($text, "\r\n") === 0))
{
$result .= PHP_EOL;
}
$result .= $text;
}
else
{
$result .= $this->openPhpTag();
if ($statement instanceof XmlImportAstPrint)
{
$result .= 'echo ';
$result .= $this->generateForExpression($statement->getValue(), true) . ';';
}
elseif ($statement instanceof XmlImportAstWith)
{
$var = '$x' . $this->xmlVariableNumber++;
$result .= PHP_EOL . $var . ' = ' ;
$result .= $this->generateForExpression($statement->getXpath()) . ';' . PHP_EOL;
array_push($this->xmlStack, $var);
$result .= 'if (' . $var . ' !== false && count(' . $var . ') > 0) :' . PHP_EOL . $var .
' = ' . $var . '[0];' . PHP_EOL;
$result .= $this->generateForSequence($statement->getBody());
array_pop($this->xmlStack);
$result .= $this->openPhpTag() . PHP_EOL . 'endif;' . PHP_EOL;
}
elseif ($statement instanceof XmlImportAstForeach)
{
$var = '$x' . $this->xmlVariableNumber++;
$result .= PHP_EOL . 'foreach (' . $this->generateForExpression($statement->getXPath(), false) .
' as ' . $var . ') :' . PHP_EOL;
array_push($this->xmlStack, $var);
$result .= $this->generateForSequence($statement->getBody());
$result .= $this->openPhpTag() . PHP_EOL . 'endforeach;' . PHP_EOL;
array_pop($this->xmlStack);
}
elseif ($statement instanceof XmlImportAstIf)
{
$result .= PHP_EOL . 'if (' . $this->generateForExpression($statement->getCondition()) . ') :' . PHP_EOL;
$result .= $this->generateForSequence($statement->getIfBody());
foreach ($statement->getElseIfs() as $elseif)
{
$result .= $this->openPhpTag() . PHP_EOL . 'elseif (' . $this->generateForExpression($elseif->getCondition()) . ') :' . PHP_EOL;
$result .= $this->generateForSequence($elseif->getBody());
}
if (!is_null($body = $statement->getElseBody()))
{
$result .= $this->openPhpTag() . PHP_EOL . 'else :' . PHP_EOL;
$result .= $this->generateForSequence($body);
}
$result .= $this->openPhpTag() . PHP_EOL . 'endif;' . PHP_EOL;
}
}
$this->previousStatement = $statement;
return $result;
}
/**
* Generates code for expression
*
* @param XmlImportAstExpression $expression
* @param bool $inPrint whether in print or in clause or function argument
* @return string
*/
private function generateForExpression(XmlImportAstExpression $expression, $inPrint = false)
{
switch (get_class($expression))
{
case 'XmlImportAstString':
$result = '"' . $this->getEscapedValue($expression->getValue()) . '"';
break;
case 'XmlImportAstInteger':
case 'XmlImportAstFloat':
$result = $expression->getValue();
break;
case 'XmlImportAstXPath':
if ($inPrint)
{
$variables = $this->sequenceStack[count($this->sequenceStack) - 1]->getVariables();
$result = '$this->getValue(' . $variables[$expression->getValue()] . ')';
}
else
{
$variables = $this->sequenceStack[count($this->sequenceStack) - 1]->getVariables();
$result = $variables[$expression->getValue()];
}
break;
case 'XmlImportAstFunction':
$result = $this->generateForFunction($expression);
break;
case 'XmlImportAstMath':
$result = $this->generateForMath($expression);
break;
case 'XmlImportAstSpintax':
$result = $this->generateForSpintax($expression);
break;
}
return $result;
}
/**
* Generates code for a function
*
* @param XmlImportAstFunction $function
* @return string
*/
private function generateForFunction(XmlImportAstFunction $function)
{
$result = $function->getName() . '(';
$arguments = $function->getArguments();
for($i = 0; $i < count($arguments); $i++)
{
$result .= $this->generateForExpression($arguments[$i], true);
if ($i < (count($arguments) - 1))
$result .= ', ';
}
$result .= ')';
return $result;
}
/**
* Generates code for a function
*
* @param XmlImportAstFunction $function
* @return string
*/
private function generateForMath(XmlImportAstMath $math)
{
$result = '';
$arguments = $math->getArguments();
for($i = 0; $i < count($arguments); $i++)
{
$result .= $this->generateForExpression($arguments[$i], true);
}
return 'number_format('.str_replace("\"", "", $result).',2)';
}
/**
* Generates code for a function
*
* @param XmlImportAstSpintax $expression
* @return string
*/
private function generateForSpintax(XmlImportAstSpintax $spintax)
{
$result = '';
$arguments = $spintax->getArguments();
$elements = array();
$buf = array();
for($i = 0; $i < count($arguments); $i++)
{
if ($arguments[$i]->getValue() != '|') array_push($buf, $this->generateForExpression($arguments[$i], true)); else { array_push($elements, $buf); $buf = array();}
}
array_push($elements, $buf);
if (!empty($elements) and is_array($elements)){
$spintax_arr = $this->generateVariation($elements);
foreach ($spintax_arr as $key => $value) {
$result .= "\"<p>\".".implode(".", $value).".\"</p>\""; if ($key != count($spintax_arr) - 1) $result .= ".";
}
}
return $result;
}
function generateVariation($A, $i = 0)
{
$result = array();
if ($i < count($A))
{
$variations = $this->generateVariation($A, $i + 1);
for ($j = 0; $j < count($A[$i]); $j++)
{
if ($variations)
{
foreach ($variations as $variation)
{
$result[] = array_merge(array($A[$i][$j]), $variation);
}
}
else
{
$result[] = array($A[$i][$j]);
}
}
}
return $result;
}
/**
* Add PHP open tag if needed
*
* @return string
*/
private function openPhpTag()
{
$result = '';
if (!$this->isPhpTagOpen)
{
$this->isPhpTagOpen = true;
$result = '<?php ';
}
return $result;
}
/**
* Adds PHP close tag if needed
*
* @return string
*/
private function closePhpTag()
{
$result = '';
if ($this->isPhpTagOpen)
{
$this->isPhpTagOpen = false;
$result = '?>';
}
return $result;
}
/**
* Gets escaped value
*
* @return string
*/
private function getEscapedValue($value)
{
$escapedValue = strtr($value, array(
"\n" => "\\n",
"\t" => "\\t",
"\r" => "\\r",
"$" => "\\$",
"\"" => "\\\"",
"\\" => "\\\\",
));
return $escapedValue;
}
}