Я работаю в системе, которая получает push-уведомления и обрабатывает их, анализируя их с помощью шаблона XSL и создавая (если он не существует) или добавляя данные, проанализированные в XML, в файл.Иногда он получает несколько уведомлений в одно и то же время, поэтому первое уведомление создает файл, а второе создает его снова, потому что в тот момент я думаю, что файл записывается, но еще не существует в файловой системе.Таким образом, результатом является то, что первые XML-данные теряются из-за того, что они перезаписываются при втором вызове скрипта.
Я думаю, что основная проблема заключается в попытке scan_dir проверить, существует ли файл.Первый вызов не находит файл (правильный), но второй вызов не может найти файл, потому что первый вызов записывает файл в этот момент.У меня нет способа определить имя файла, поэтому я должен применить шаблон регулярных выражений, потому что не знаю, когда был создан файл, если он был.Изначально я использовал glob с теми же результатами, поэтому изменил на scan_dir, потому что я думаю, что scan_dir быстрее.
/**
* Main method
* @return string XML resulting
*/
public function run()
{
$xml = simplexml_load_string($this->xml);
$xsl = new \DOMDocument();
$xsl->load(self::XSLPATH);
// Transformer config
$proc = new \XSLTProcessor;
$proc->registerPHPFunctions();
$proc->importStyleSheet($xsl);
$xmlResult = $proc->transformToXML($xml);
// Obtain path to destination folder
$path = self::PATH."/{$this->folder}/";
// Get the file with pattern
$file_list = glob($path."fileoutput*.xml");
// If there exists files matching the pattern, get the first one
if (sizeof($file_list) > 0) {
$this->append($xmlResult, $file_list[0]);
} else {
// ERROR! concurrent calls end here beceause file is not
// in filesystem so scan_dir can't detect it!
$filename = "fileoutput_".date("d-m-Y_H-i-s").".xml";
$this->writeFile(
__DIR__."/../../../output/{$this->folder}/{$filename}",
$xmlResult
);
}
// return the xml string
return $xmlResult;
}
/**
* This method uses flock to gain exclusive acces to resource.
*
* @param string $filepath file path
* @param string $data dat ato be written
* @return void
*/
private function writeFile($filepath, $data)
{
$fh = fopen($filepath, "w");
$tries = 5;
while ($tries > 0) {
$locked = flock($fh, LOCK_EX);
if (! $locked) {
sleep(5);
$tries--;
} else {
$tries = 0;
}
}
if ($locked) {
fwrite($fh, $data);
flock($fh, LOCK_UN);
}
fclose($fh);
}
/**
* Append xml data to existing xml
* @param $xml string xml to append
* @param $file string file where xml will be append
*/
private function append($xml, $filename)
{
$xmlFromFile = simplexml_load_file($filename);
$xmlToAppend = simplexml_load_string($xml);
$nodeToAppend = $xmlToAppend->reserva;
$this->sxml_append($xmlFromFile, $nodeToAppend);
$this->writeFile($filename, $xmlFromFile->asXML());
}
/**
* This method adds a childnode to xml with deep copy
* @param $to SimpleXMLElement xml where childnode is copied
* @param $from SimpleXMLElement xml childnode to copy to
* @return void
*/
private function sxml_append(\SimpleXMLElement $to, \SimpleXMLElement $from)
{
$toDom = dom_import_simplexml($to);
$fromDom = dom_import_simplexml($from);
$toDom->formatOutput = true;
//$toDom->preserveWhiteSpace = false;
$toDom->appendChild($toDom->ownerDocument->createTextNode("\n"));
$toDom->appendChild($toDom->ownerDocument->importNode($fromDom, true));
}
Я пытаюсь обработать все данные уведомлений в файл, даже когда они достигают моего сценария в одно и то же время.,Если я получаю 2 уведомления в одно и то же время, мне нужны все данные без перезаписи.