У меня есть простой скрипт PHP, который вызывает файл sqlplus sqlldr и сбрасывает данные в таблицу в Oracle. Я сузил проблему до того, что, по моему мнению, является причиной зависания моего php-скрипта … который:
Когда я запускаю из php CLI, системная команда не возвращается к php, скорее она зависает в sqlplus land. При запуске из браузера скрипт работает должным образом, и я получаю последнюю команду echo, которая печатает в браузере: Я закончила бегать сейчас.
<?PHP
system('sqlplus username/password@tnsNameOfDatabase',$out);
echo $out;
system('exit',$out);
echo $out;
echo 'I am done running now';
запуск этого скрипта из командной строки с загруженным sqlplus правильно соединится с базой данных, и мой вывод из этого соединения выглядит следующим образом:
SQL*Plus: Release 12.1.0.2.0 Production on Wed Mar 8 15:37:34 2017
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Last Successful login time: Wed Mar 08 2017 15:37:18 -05:00
Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning and Oracle Label Security options
сейчас … проблема в том, что моя php-программа зависает, и я больше не могу вернуться к php-скрипту. Как выйти из CLI sqlplus, чтобы вернуться к работающему php-скрипту?
Типичная команда выхода в SQLPLUS — просто ‘exit’, и я попробовал это (как вы можете видеть выше) … что при запуске вручную приводит к следующему:
Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning and Oracle Label Security options
Как мне выйти из sqlplus и вернуться в сценарий, который должен продолжаться? Любая помощь очень ценится!
Фактический метод, который вызывает этот скрипт sqlplus и снова — прекрасно работает при вызове из браузера, но при вызове из CLI он зависает прямо здесь, в этом методе, прежде чем он возвращается.
private function loadTempData($object) {
$this->getLog()->appendLogFile('Constructed Control File: '.$object->getTempData()->getQaveLoadControl()->getFullPathFileName());
$this->getLog()->appendLogFile('Result saved in: '.$object->getTempData()->getExportFile()->getFullPathFileName());
$object->getInsertCommandFile()->appendContent('$ sqlldr '.$this->getPersistEnv()->getUserSlid().'/'.$this->getPersistEnv()->getPassword().'@'.$this->getPersistEnv()->getDatabase().' control='.$object->getTempData()->getQaveLoadControl()->getFullPathFileName().' log='.$object->getTempData()->getQaveLoadControl()->getFullPathFileName().'.log');
$this->getLog()->appendLogFile('Loading data to Temp Table');
$command = 'sqlplus '.$this->getPersistEnv()->getUserSlid().'/'.$this->getPersistEnv()->getPassword().'@'.$this->getPersistEnv()->getDatabase().' @'.$object->insertCommandFile->getFullPathFileName();
$this->getLog()->appendLogFile($command);
system($command,$output);
// this line does not make it into the log...
$this->getLog()->appendLogFile($output);
// this method does not return when run from CLI
return true;
}
Во-первых, вы всегда должны экранировать динамический вывод команды оболочки. Во-вторых, system()
не вернет вывод программы, вместо этого он отобразит его напрямую. Второй параметр заполняется возвращаемым значением из программы, обычно 0 в случае успешного выполнения. Собрать полный вывод для использования в файле журнала а также получить возвращаемое значение, использовать exec()
,
<?php
$credentials = escapeshellarg("username/password@tnsNameOfDatabase");
$scriptfile = escapeshellarg("@/my/sqlldr/file");
exec("sqlplus $credentials $scriptfile", $output, $return);
// $output contains every line of output from the program, as an array
// $return contains the numeric exit code from the program
echo 'I am done running now';
Наконец, убедитесь, что вы даете команду программе выйти с действительным оператором «EXIT» в вашем файле SQL, как вы обнаружили!
Других решений пока нет …