get_parms(
'host', 'port', 'base', 'user', 'password', 'socket', 'nolog', 'clng', 'winsvc_run', 'charset', 'debugmask', 'stem', 'sortempty'
);
$dom = new DOMDocument();
$dom->formatOutput = true;
if ($dom->loadXML($oldxml)) {
$xmlchanged = false;
foreach (array("str:host", "str:port", "str:base", "str:user", "str:password", "str:socket", "boo:nolog", "str:clng", "boo:winsvc_run", "str:charset", 'str:debugmask', 'str:stem', 'str:sortempty') as $pname) {
$ptype = substr($pname, 0, 3);
$pname = substr($pname, 4);
$pvalue = $parm2[$pname];
if (($ns = $dom->getElementsByTagName($pname)->item(0)) != NULL) {
// le champ existait dans le xml, on supprime son ancienne valeur (tout le contenu)
while (($n = $ns->firstChild)) {
$ns->removeChild($n);
}
} else {
// le champ n'existait pas dans le xml, on le cree
$ns = $dom->documentElement->appendChild($dom->createElement($pname));
}
// on fixe sa valeur
switch ($ptype) {
case "str":
$ns->appendChild($dom->createTextNode($pvalue));
break;
case "boo":
$ns->appendChild($dom->createTextNode($pvalue ? '1' : '0'));
break;
}
$xmlchanged = true;
}
}
return($dom->saveXML());
}
/**
*
* @return void
*/
public function printInterfaceJS()
{
?>
cmd
host = trim($sx_task_settings->host);
$this->port = trim($sx_task_settings->port);
$this->base = trim($sx_task_settings->base);
$this->user = trim($sx_task_settings->user);
$this->password = trim($sx_task_settings->password);
$this->socket = trim($sx_task_settings->socket);
$this->charset = trim($sx_task_settings->charset);
$this->stem = trim($sx_task_settings->stem);
$this->sortempty = trim($sx_task_settings->sortempty);
$this->debugmask = (int) (trim($sx_task_settings->debugmask));
$this->nolog = p4field::isyes(trim($sx_task_settings->nolog));
$this->winsvc_run = p4field::isyes(trim($sx_task_settings->winsvc_run));
parent::loadSettings($sx_task_settings);
}
private function getIndexer()
{
$binaries = $this->dependencyContainer['phraseanet.configuration']['binaries'];
if (isset($binaries['phraseanet_indexer'])) {
$cmd = $binaries['phraseanet_indexer'];
} else {
$finder = new ExecutableFinder();
$cmd = $finder->find('phraseanet_indexer');
}
return $cmd;
}
/**
*
* @return void
*/
protected function run2()
{
$cmd = $this->getIndexer();
$nullfile = '/dev/null';
$this->method = self::METHOD_PROC_OPEN;
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$nullfile = '/dev/null';
}
if ( ! file_exists($cmd) || ! is_executable($cmd)) {
$this->setState(self::STATE_STOPPED);
$this->log(sprintf('File \'%s\' does not exists', $cmd));
throw new Exception('cindexer executable not found', self::ERR_EXECUTABLE_NOT_FOUND);
return;
}
$args = array();
$args_nopwd = array();
if ($this->host) {
$args[] = '-h=' . $this->host;
$args_nopwd[] = '-h=' . $this->host;
}
if ($this->port) {
$args[] = '-P=' . $this->port;
$args_nopwd[] = '-P=' . $this->port;
}
if ($this->base) {
$args[] = '-b=' . $this->base;
$args_nopwd[] = '-b=' . $this->base;
}
if ($this->user) {
$args[] = '-u=' . $this->user;
$args_nopwd[] = '-u=' . $this->user;
}
if ($this->password) {
$args[] = '-p=' . $this->password;
$args_nopwd[] = '-p=xxxxxxx';
}
if ($this->socket) {
$args[] = '--socket=' . $this->socket;
$args_nopwd[] = '--socket=' . $this->socket;
}
$args[] = '-o';
$args_nopwd[] = '-o';
if ($this->charset) {
$args[] = '--default-character-set=' . $this->charset;
$args_nopwd[] = '--default-character-set=' . $this->charset;
}
if ($this->stem) {
$args[] = '--stem=' . $this->stem;
$args_nopwd[] = '--stem=' . $this->stem;
}
if ($this->sortempty) {
$args[] = '--sort-empty=' . $this->sortempty;
$args_nopwd[] = '--sort-empty=' . $this->sortempty;
}
if ($this->debugmask > 0) {
$args[] = '-d=' . $this->debugmask;
$args_nopwd[] = '-d=' . $this->debugmask;
}
if ($this->nolog) {
$args[] = '-n';
$args_nopwd[] = '-n';
}
if ($this->winsvc_run) {
$args[] = '--run';
$args_nopwd[] = '--run';
}
$logdir = $this->dependencyContainer['root.path'] . '/logs/';
$this->new_status = NULL; // new status to set at the end
$this->exception = NULL; // exception to throw at the end
$this->log(sprintf("running cindexer with method %s", $this->method));
switch ($this->method) {
case self::METHOD_PROC_OPEN:
$this->run_with_proc_open($cmd, $args, $args_nopwd);
break;
case self::METHOD_FORK:
$this->run_with_fork($cmd, $args, $args_nopwd);
break;
case self::METHOD_EXEC:
$this->run_with_exec($cmd, $args, $args_nopwd);
break;
}
if ($this->new_status !== NULL) {
$this->setState($this->new_status);
}
if ($this->exception) {
throw $this->exception;
}
}
private function run_with_proc_open($cmd, $args, $args_nopwd)
{
$nullfile = defined('PHP_WINDOWS_VERSION_BUILD') ? 'NUL' : '/dev/null';
$descriptors = array();
$descriptors[1] = array("file", $nullfile, "a+");
$descriptors[2] = array("file", $nullfile, "a+");
$pipes = array();
$logcmd = escapeshellarg($cmd).' '.implode(' ', array_map('escapeshellarg', $args_nopwd));
$execmd = escapeshellarg($cmd).' '.implode(' ', array_map('escapeshellarg', $args));
$this->log(sprintf('cmd=\'%s\'', $logcmd));
$process = proc_open($execmd, $descriptors, $pipes, dirname($cmd), null, array('bypass_shell' => true));
$pid = NULL;
if (is_resource($process)) {
$proc_status = proc_get_status($process);
if ($proc_status['running']) {
$pid = $proc_status['pid'];
}
}
$qsent = '';
$timetokill = NULL;
$sock = NULL;
$this->running = true;
while ($this->running) {
if ($this->getState() == self::STATE_TOSTOP && $this->socket > 0) {
// must quit task, so send 'Q' to port 127.0.0.1:XXXX to cindexer
if ( ! $qsent && (($sock = socket_create(AF_INET, SOCK_STREAM, 0)) !== false)) {
if (socket_connect($sock, '127.0.0.1', $this->socket) === true) {
socket_write($sock, 'Q', 1);
socket_write($sock, "\r\n", strlen("\r\n"));
for ($i = 0; $this->running && $i < 5; $i ++) {
sleep(1);
}
$qsent = 'Q';
$timetokill = time() + 10;
} else {
socket_close($sock);
$sock = NULL;
}
}
}
$proc_status = proc_get_status($process);
if (! $proc_status['running']) {
// the cindexer died
if ($qsent == 'Q') {
$this->log('Phrasea indexer stopped');
$this->new_status = self::STATE_STOPPED;
} elseif ($qsent == 'K') {
$this->log('Phrasea indexer has been killed');
$this->new_status = self::STATE_STOPPED;
} else {
$this->log('Phrasea indexer crashed');
$this->exception = new Exception('cindexer crashed', self::ERR_CRASHED);
// do not change the status so scheduler may restart it
}
$this->running = false;
} else {
// the cindexer is still alive
if ($qsent == 'Q') {
if (time() > $timetokill) {
// must kill cindexer
$this->log('Sending kill signal to Phrasea indexer');
$qsent = 'K';
proc_terminate($process); // sigint
}
}
}
for ($i = 0; $this->running && $i < 5; $i ++) {
sleep(1);
}
}
if ($sock) {
socket_close($sock);
$sock = NULL;
}
foreach (array_keys($pipes) as $offset) {
if (is_resource($pipes[$offset])) {
fclose($pipes[$offset]);
}
}
proc_terminate($process); // sigint
proc_close($process);
}
private function run_with_fork($cmd, $args, $args_nopwd)
{
$pid = pcntl_fork();
if ($pid == -1) {
$this->exception = new Exception('cindexer can\'t fork', self::ERR_CANT_FORK);
} elseif ($pid == 0) {
// child
umask(0);
if (($err = posix_setsid()) < 0) {
$this->exception = new Exception('cindexer can\'t detach from terminal', $err);
} else {
chdir(dirname(__FILE__));
pcntl_exec($cmd, $args);
sleep(2);
}
} else {
// parent
$this->running = true;
$sigsent = NULL;
while ($this->running) {
// is the cindexer alive ?
if ( ! posix_kill($pid, 0)) {
// dead...
if ($sigsent === NULL) {
// but it's not my fault
$this->log('Phrasea indexer crashed');
$this->exception = new Exception('cindexer crashed', self::ERR_CRASHED);
// do not change the status so scheduler may restart it
break;
}
}
if ($this->getState() == self::STATE_TOSTOP) {
posix_kill($pid, ($sigsent = SIGINT));
$timetokill = time() + 10;
sleep(2);
}
$status = NULL;
if (pcntl_wait($status, WNOHANG) == $pid) {
// child (indexer) has exited
if ($sigsent == SIGINT) {
$this->log('Phrasea indexer stopped');
$this->new_status = self::STATE_STOPPED;
} elseif ($sigsent == SIGKILL) {
$this->log('Phrasea indexer has been killed');
$this->new_status = self::STATE_STOPPED;
} else {
$this->log('Phrasea indexer crashed');
$this->exception = new Exception('cindexer crashed', self::ERR_CRASHED);
// do not change the status so scheduler may restart it
}
$this->running = false;
} else {
if ($sigsent == SIGINT && time() > $timetokill) {
// must kill cindexer
$this->log('Kill signal sent to Phrasea indexer');
posix_kill($pid, ($sigsent = SIGKILL));
}
sleep(2);
}
} // while running
}
}
private function run_with_exec($cmd, $args, $args_nopwd)
{
pcntl_exec($cmd, $args);
sleep(2);
}
/**
* @param array $params
*/
public static function getDefaultSettings(Configuration $config, array $params = array())
{
$database = $config['main']['database'];
return "\n\n"
."" . $database['host'] . ""
. $database['port'] . ""
. $database['dbname'] . ""
. $database['user'] . ""
. $database['password'] . "25200"
. "10"
. "0utf8";
}
}