在CLI和node.js脚本中执行PHP脚本有不同的结果


Executing PHP script has different results when run in CLI and by node.js script

我完全失去了弄清楚为什么我的PHP脚本在通过CLI运行时产生不同的结果(产生正确的结果)与通过exec函数在Node.js中运行时。

这是我的PHP。注意fopen('blah.txt', 'w')行,这是我用来检查脚本是否到达该位置的。

calculator.php

class calculator{
    public static $_var = array();
    public function calculate($xml, $xsl, $frequency){
        $reader = new DOMDocument;
        if(!$reader->load($xsl)) throw new Exception('XSL Could not be loaded: ' . $xsl);
        $processor = new XSLTProcessor;
        $processor->importStyleSheet($reader);
        $processor->registerPHPFunctions();
        $processor->setParameter('', 'frequency', $frequency);
        $dictionary = new DOMDocument;
        if(!$dictionary->load($xml)) throw new Exception('XML Could not be loaded: ' . $xml);
        $processor->transformToXML($dictionary);
    }
    public static function connectNodes($name, $dataset, $processor, $destination, $frequency){
        $var = self::$_var;
        self::$_var = array();
        $test = fopen('blah.txt', 'w');
        fclose($test);
        ob_start();
        require 'templates/' . $processor . '.php';
        $xsltSheet = new DOMDocument;
        $xsltSheet->loadXML(ob_get_clean());
        $xsltProc = new XSLTProcessor;
        $xsltProc->importStyleSheet($xsltSheet);
        $dataSet = new DOMDocument;
        if(is_file('../dataFiles/xml/' . $dataset . '.xml') && calculator::makedirs('../dataFiles/json/' . $destination . '/' . $frequency)){
            //proceed only if the dataset exists and the folders are created correctly
            $dataSet->load('../dataFiles/xml/' . $dataset . '.xml');
            if(!is_file('../dataFiles/json/' . $destination . '/' . $frequency . '/' . $name . '.json')){
                $filemaker = fopen('../dataFiles/json/' . $destination . '/' . $frequency . '/' . $name . '.json', 'w');
                fclose($filemaker);
            }
            $xsltProc->transformToURI($dataSet, '../dataFiles/json/' . $destination . '/' . $frequency . '/' . $name . '.json');
        } else {
            throw new Exception('Either dataset does not exist('. $dataset .'), or directories could not be created (dataFiles/json/'. $destination . '/' . $frequency .')');
        }
    }
    public static function populateVarWithXPath($var){
        self::$_var[] = $var;
    }
    public static function makedirs($dirpath, $mode=0777) {
        return is_dir($dirpath) || mkdir($dirpath, $mode, true);
    }
}

当我通过CLI运行此命令时,blah.txt将在脚本运行的目录中创建。但是当我通过Node.js运行这个时,它不会创建blah.txt!

这是我的节点脚本:

脚本跑

var ipc = require('./ipc');
var exec = require('child_process').exec;
ipc.listen(function(frequency){
    if(frequency.toString().match(/integrator /)){
        var freq = frequency.toString().replace(/integrator /, '');
        console.log('Received message: ' + freq);
        var cmd = exec('php use_calculator.php metricsDictionary.xml metricsXmlReader.xsl ' + frequency);
        cmd.on('close', function(exitCode, stdout, stderr){
            if(exitCode === 0){
                console.log('exitcode: ' + exitCode + ' ; stdout: ' + stdout + ' ; stderr: ' + stderr);
            } else {
                console.log('Try again?');
            }
        });
        cmd.on('error', function(err){
            throw err;
        });
    }
});
有趣的是,如果我将blah.txt移动到calculate()函数中(它将首先运行),CLI和node都将创建该文件。

更多的上下文:

use_calculator.php文件将调用calculate()函数并将三个必需的参数传递给它。然后,在calculate()中,它将执行XML和XSL文件合并。

在XSL中是关于如何处理XML数据的规则,它所做的是调用connectNodes()函数——该函数将处理新的XML和XSL。它就像XML/XSL的开端。

关键是有一个XML文件列出了应该处理其他XML数据的内容和方式的所有细节。该文件在calculate()中读取。然后,当它计算每个数据块时,它以类似于初始化的方式调用connectNode()函数。

为了使事情更清楚(我希望),这里是metricsXmlReader。xsl调用connectNodes()

metricsXmlReader.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
    <xsl:output method="html" omit-xml-declaration="yes" />
    <xsl:template match="metrics">
        <xsl:for-each select="metric">
            <xsl:if test="frequency = $frequency">
                <xsl:for-each select="xpath/var">
                    <xsl:variable name="pusher" select="php:functionString('calculator::populateVarWithXPath', .)" />
                </xsl:for-each>
                <xsl:variable name="trigger" select="php:functionString('calculator::connectNodes', name, dataset, processor, destination, frequency)" />   
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

我的第一个猜测是,无论PHP试图将文件写入何处,它都不能。您可以尝试为每个人创建一个具有权限的绝对路径,例如/tmp。

你也应该确保你可以处理并行请求。因为这个不能按比例缩放。如前所述,管道是一种解决方案。

惠普

PS:你试过吗?