mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-17 15:03:25 +00:00
Remove old files
This commit is contained in:
@@ -1,630 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Monolog\Logger;
|
||||
use Symfony\Component\Process\PhpExecutableFinder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
|
||||
* @link www.phraseanet.com
|
||||
*/
|
||||
class task_Scheduler
|
||||
{
|
||||
const TASKDELAYTOQUIT = 60;
|
||||
// how to schedule tasks (choose in 'run' method)
|
||||
const METHOD_FORK = 'METHOD_FORK';
|
||||
const METHOD_PROC_OPEN = 'METHOD_PROC_OPEN';
|
||||
const ERR_ALREADY_RUNNING = 114; // aka EALREADY (Operation already in progress)
|
||||
|
||||
/**
|
||||
*
|
||||
* @var \Monolog\Logger
|
||||
*/
|
||||
private $logger;
|
||||
private $method;
|
||||
private $dependencyContainer;
|
||||
|
||||
private $schedstatus;
|
||||
|
||||
public function __construct(Application $application, Logger $logger)
|
||||
{
|
||||
declare(ticks = 1);
|
||||
$this->dependencyContainer = $application;
|
||||
$this->logger = $logger;
|
||||
$this->schedstatus = '';
|
||||
}
|
||||
|
||||
protected function log($message)
|
||||
{
|
||||
$this->logger->addInfo($message);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function sleep($nsec)
|
||||
{
|
||||
$nsec = (integer) $nsec;
|
||||
if ($nsec < 0) {
|
||||
throw new \InvalidArgumentException(sprintf("(%s) is not > 0"));
|
||||
}
|
||||
|
||||
$end = microtime(true) + $nsec;
|
||||
while (microtime(true) < $end) {
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception if scheduler is already running
|
||||
* @todo doc all possible exception
|
||||
*/
|
||||
public function sigHandler($signal)
|
||||
{
|
||||
switch ($signal) {
|
||||
case SIGCHLD:
|
||||
$status = null;
|
||||
$pid = pcntl_wait($status);
|
||||
$exitstatus = pcntl_wexitstatus($status);
|
||||
$this->log(sprintf("SIGCHLD (%s) received from pid=%s, status=%s, exitstatus=%s", $signal, $pid, var_export($status, true), $exitstatus));
|
||||
break;
|
||||
case SIGINT: // ctrl C
|
||||
$this->log(sprintf("SIGINT (%s) Ctrl-C received, schedstatus='tostop'", $signal));
|
||||
$this->schedstatus = 'tostop';
|
||||
break;
|
||||
case SIGTERM:
|
||||
$this->log(sprintf("SIGTERM (%s) received but ignored, http timeout ?", $signal));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
//prevent scheduler to fail if GV_cli is not provided
|
||||
if (isset($this->dependencyContainer['phraseanet.configuration']['binaries']['php_binary'])) {
|
||||
$php = $this->dependencyContainer['phraseanet.configuration']['binaries']['php_binary'];
|
||||
} else {
|
||||
$finder = new PhpExecutableFinder();
|
||||
$php = $finder->find();
|
||||
}
|
||||
|
||||
if ( ! is_executable($php)) {
|
||||
throw new \RuntimeException('PHP cli is not provided in binary configuration');
|
||||
}
|
||||
|
||||
$this->method = self::METHOD_PROC_OPEN;
|
||||
|
||||
$nullfile = '/dev/null';
|
||||
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$nullfile = 'NUL';
|
||||
}
|
||||
|
||||
if (\task_manager::isPosixPcntlSupported()) {
|
||||
// avoid <defunct> php when a task ends
|
||||
// pcntl_signal(SIGCHLD, SIG_IGN); // no zombies but no returnValue
|
||||
// pcntl_signal(SIGCHLD, SIG_DFL); // with "declare(ticks=1)" returnValue ok but zombies
|
||||
pcntl_signal(SIGCHLD, array($this, 'sigHandler')); // ok
|
||||
pcntl_signal(SIGINT, array($this, 'sigHandler'));
|
||||
pcntl_signal(SIGTERM, array($this, 'sigHandler'));
|
||||
|
||||
$this->method = self::METHOD_FORK;
|
||||
}
|
||||
|
||||
$lockdir = $this->dependencyContainer['root.path'] . '/tmp/locks/';
|
||||
|
||||
for ($try = 1; true; $try ++) {
|
||||
$lockfile = ($lockdir . 'scheduler.lock');
|
||||
if (($schedlock = fopen($lockfile, 'a+')) != FALSE) {
|
||||
if (flock($schedlock, LOCK_EX | LOCK_NB) === FALSE) {
|
||||
$this->log(sprintf("failed to lock '%s' (try=%s/4)", $lockfile, $try));
|
||||
if ($try == 4) {
|
||||
$this->log("scheduler already running.");
|
||||
fclose($schedlock);
|
||||
|
||||
throw new Exception('scheduler already running.', self::ERR_ALREADY_RUNNING);
|
||||
|
||||
return;
|
||||
} else {
|
||||
$this->sleep(2);
|
||||
}
|
||||
} else {
|
||||
// locked
|
||||
ftruncate($schedlock, 0);
|
||||
fwrite($schedlock, '' . getmypid());
|
||||
fflush($schedlock);
|
||||
|
||||
// for windows : unlock then lock shared to allow OTHER processes to read the file
|
||||
// too bad : no critical section nor atomicity
|
||||
flock($schedlock, LOCK_UN);
|
||||
flock($schedlock, LOCK_SH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->log(sprintf("running scheduler with method %s", $this->method));
|
||||
|
||||
$conn = $this->dependencyContainer['phraseanet.appbox']->get_connection();
|
||||
|
||||
$taskPoll = array(); // the poll of tasks
|
||||
|
||||
$sleeptime = 3;
|
||||
|
||||
$sql = "UPDATE sitepreff SET schedstatus='started'";
|
||||
$conn->exec($sql);
|
||||
|
||||
$task_manager = $this->dependencyContainer['task-manager'];
|
||||
|
||||
// set every 'auto-start' task to start
|
||||
foreach ($task_manager->getTasks() as $task) {
|
||||
if ($task->isActive()) {
|
||||
if ( ! $task->getPID()) {
|
||||
/* @var $task task_abstract */
|
||||
$task->resetCrashCounter();
|
||||
$task->setState(task_abstract::STATE_TOSTART);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->schedstatus = 'started';
|
||||
$runningtask = 0;
|
||||
$connwaslost = false;
|
||||
|
||||
while ($this->schedstatus == 'started' || $runningtask > 0) {
|
||||
while (1) {
|
||||
try {
|
||||
assert(is_object($conn));
|
||||
$ping = @$conn->ping();
|
||||
} catch (ErrorException $e) {
|
||||
$ping = false;
|
||||
}
|
||||
if ($ping) {
|
||||
break;
|
||||
}
|
||||
|
||||
unset($conn);
|
||||
if (! $connwaslost) {
|
||||
$this->log(sprintf("Warning : abox connection lost, restarting in 10 min."));
|
||||
}
|
||||
$this->sleep(60 * 10);
|
||||
try {
|
||||
$conn = $this->dependencyContainer['phraseanet.appbox']->get_connection();
|
||||
} catch (ErrorException $e) {
|
||||
$ping = false;
|
||||
}
|
||||
|
||||
$connwaslost = true;
|
||||
}
|
||||
if ($connwaslost) {
|
||||
$this->log("abox connection restored");
|
||||
|
||||
$sql = 'UPDATE task SET crashed=0';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute();
|
||||
$stmt->closeCursor();
|
||||
|
||||
$connwaslost = false;
|
||||
}
|
||||
|
||||
if ($this->schedstatus == "started") {
|
||||
$this->schedstatus = '';
|
||||
$row = NULL;
|
||||
try {
|
||||
$sql = "SELECT schedstatus FROM sitepreff";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute();
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
} catch (ErrorException $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($row) {
|
||||
$this->schedstatus = $row["schedstatus"];
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->schedstatus == 'tostop') {
|
||||
$sql = 'UPDATE sitepreff SET schedstatus = "stopping"';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute();
|
||||
$stmt->closeCursor();
|
||||
|
||||
// if scheduler is stopped, stop the tasks
|
||||
$sql = 'UPDATE task2 SET status="tostop" WHERE status != "stopped" and status != "manual"';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute();
|
||||
$stmt->closeCursor();
|
||||
$this->log("schedstatus == 'stopping', waiting tasks to end");
|
||||
}
|
||||
|
||||
// initialy, all tasks are supposed to be removed from the poll
|
||||
foreach ($taskPoll as $tkey => $task) {
|
||||
$taskPoll[$tkey]["todel"] = true;
|
||||
}
|
||||
|
||||
foreach ($task_manager->getTasks(true) as $task) {
|
||||
$tkey = "t_" . $task->getID();
|
||||
$status = $task->getState();
|
||||
|
||||
if ( ! isset($taskPoll[$tkey])) {
|
||||
// the task is not in the poll, add it
|
||||
|
||||
$arguments = array();
|
||||
if ($this->dependencyContainer['phraseanet.registry']->get('GV_PHP_INI')) {
|
||||
$arguments[] = '-c';
|
||||
$arguments[] = $this->dependencyContainer['phraseanet.registry']->get('GV_PHP_INI');
|
||||
}
|
||||
|
||||
$arguments = array_merge($arguments, array(
|
||||
'-f',
|
||||
$this->dependencyContainer['root.path'] . '/bin/console',
|
||||
'--',
|
||||
'-q',
|
||||
'task:run',
|
||||
$task->getID(), '--runner=scheduler'
|
||||
));
|
||||
|
||||
$taskPoll[$tkey] = array(
|
||||
"task" => $task,
|
||||
"current_status" => $status,
|
||||
"cmd" => $php,
|
||||
"args" => $arguments,
|
||||
"killat" => null,
|
||||
"sigterm_sent" => false,
|
||||
"pid" => false
|
||||
);
|
||||
if ($this->method == self::METHOD_PROC_OPEN) {
|
||||
$taskPoll[$tkey]['process'] = NULL;
|
||||
$taskPoll[$tkey]['pipes'] = NULL;
|
||||
}
|
||||
|
||||
$this->log(
|
||||
sprintf(
|
||||
"new Task %s, status=%s"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
, $status
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// the task is already in the poll, update its status
|
||||
if ($taskPoll[$tkey]["current_status"] != $status) {
|
||||
$this->log(
|
||||
sprintf(
|
||||
"Task %s, oldstatus=%s, newstatus=%s"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
, $taskPoll[$tkey]["current_status"]
|
||||
, $status
|
||||
)
|
||||
);
|
||||
$taskPoll[$tkey]["current_status"] = $status;
|
||||
}
|
||||
// update the whole task object
|
||||
unset($taskPoll[$tkey]["task"]);
|
||||
$taskPoll[$tkey]["task"] = $task;
|
||||
}
|
||||
|
||||
unset($task);
|
||||
|
||||
$taskPoll[$tkey]["todel"] = false; // this task exists, do not remove from poll
|
||||
}
|
||||
|
||||
// remove not-existing task from poll
|
||||
foreach ($taskPoll as $tkey => $task) {
|
||||
if ($task["todel"]) {
|
||||
$this->log(sprintf("Task %s deleted", $taskPoll[$tkey]["task"]->getID()));
|
||||
unset($taskPoll[$tkey]);
|
||||
}
|
||||
}
|
||||
|
||||
// Launch task that are not yet launched
|
||||
$runningtask = 0;
|
||||
|
||||
foreach ($taskPoll as $tkey => $tv) {
|
||||
$status = $tv['task']->getState();
|
||||
switch ($status) {
|
||||
default:
|
||||
$this->log(sprintf('Unknow status `%s`', $status));
|
||||
break;
|
||||
|
||||
case task_abstract::STATE_TORESTART:
|
||||
if ( ! $taskPoll[$tkey]['task']->getPID()) {
|
||||
if ($this->method == self::METHOD_PROC_OPEN) {
|
||||
@fclose($taskPoll[$tkey]["pipes"][1]);
|
||||
@fclose($taskPoll[$tkey]["pipes"][2]);
|
||||
@proc_close($taskPoll[$tkey]["process"]);
|
||||
|
||||
$taskPoll[$tkey]["process"] = null;
|
||||
} elseif ($this->method == self::METHOD_FORK) {
|
||||
$pid = $taskPoll[$tkey]['pid'];
|
||||
if ($pid) {
|
||||
$status = NULL;
|
||||
if (pcntl_waitpid($pid, $status, WNOHANG) === $pid) {
|
||||
// pid has quit
|
||||
$taskPoll[$tkey]['pid'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->schedstatus == 'started') {
|
||||
$taskPoll[$tkey]["task"]->setState(task_abstract::STATE_TOSTART);
|
||||
}
|
||||
// trick to start the task immediatly : DON'T break if ending with 'tostart'
|
||||
// so it will continue with 'tostart' case !
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
case task_abstract::STATE_TOSTART:
|
||||
// if scheduler is 'tostop', don't launch a new task !
|
||||
if ($this->schedstatus != 'started') {
|
||||
break;
|
||||
}
|
||||
|
||||
$taskPoll[$tkey]["killat"] = NULL;
|
||||
|
||||
if ($this->method == self::METHOD_PROC_OPEN) {
|
||||
if (! $taskPoll[$tkey]["process"]) {
|
||||
|
||||
$nullfile = defined('PHP_WINDOWS_VERSION_BUILD') ? 'NUL' : '/dev/null';
|
||||
|
||||
$descriptors[1] = array('file', $nullfile, 'a+');
|
||||
$descriptors[2] = array('file', $nullfile, 'a+');
|
||||
|
||||
$taskPoll[$tkey]["process"] = proc_open(
|
||||
escapeshellarg($taskPoll[$tkey]["cmd"]) . ' ' . implode(' ', array_map('escapeshellarg', $taskPoll[$tkey]["args"]))
|
||||
, $descriptors
|
||||
, $taskPoll[$tkey]["pipes"]
|
||||
, $this->dependencyContainer['root.path'] . "/bin/"
|
||||
, null
|
||||
, array('bypass_shell' => true)
|
||||
);
|
||||
|
||||
if (is_resource($taskPoll[$tkey]["process"])) {
|
||||
// let the process lock and write it's pid
|
||||
$sleepTimeout = microtime(true) + 10;
|
||||
do {
|
||||
usleep(500000);
|
||||
if (null !== $taskPoll[$tkey]['task']->getPID()) {
|
||||
break;
|
||||
}
|
||||
} while (microtime(true) < $sleepTimeout);
|
||||
}
|
||||
|
||||
if (is_resource($taskPoll[$tkey]["process"]) && ($pid = $taskPoll[$tkey]['task']->getPID()) !== null) {
|
||||
$taskPoll[$tkey]['pid'] = $pid;
|
||||
$this->log(
|
||||
sprintf(
|
||||
"Task %s '%s' started (pid=%s)"
|
||||
, $taskPoll[$tkey]['task']->getID()
|
||||
, $taskPoll[$tkey]["cmd"] . ' ' . implode(' ', $taskPoll[$tkey]["args"])
|
||||
, $pid
|
||||
)
|
||||
);
|
||||
$runningtask ++;
|
||||
} else {
|
||||
$taskPoll[$tkey]["task"]->incrementCrashCounter();
|
||||
|
||||
@fclose($taskPoll[$tkey]["pipes"][1]);
|
||||
@fclose($taskPoll[$tkey]["pipes"][2]);
|
||||
@proc_close($taskPoll[$tkey]["process"]);
|
||||
$taskPoll[$tkey]["process"] = null;
|
||||
|
||||
$this->log(
|
||||
sprintf(
|
||||
"Task %s '%s' failed to start %d times"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
, $taskPoll[$tkey]["cmd"]
|
||||
, $taskPoll[$tkey]["task"]->getCrashCounter()
|
||||
)
|
||||
);
|
||||
|
||||
if ($taskPoll[$tkey]["task"]->getCrashCounter() > 5) {
|
||||
$taskPoll[$tkey]["task"]->setState(task_abstract::STATE_STOPPED);
|
||||
} else {
|
||||
$taskPoll[$tkey]["task"]->setState(task_abstract::STATE_TOSTART);
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($this->method == self::METHOD_FORK) {
|
||||
$pid = pcntl_fork();
|
||||
if ($pid == -1) {
|
||||
die("failed to fork");
|
||||
} elseif ($pid == 0) {
|
||||
umask(0);
|
||||
if (posix_setsid() < 0) {
|
||||
die("Forked process could not detach from terminal\n");
|
||||
}
|
||||
|
||||
// todo (if possible) : redirecting stdin, stdout to log files ?
|
||||
|
||||
$this->log(sprintf("exec('%s %s')", $taskPoll[$tkey]["cmd"], implode(' ', $taskPoll[$tkey]["args"])));
|
||||
pcntl_exec($taskPoll[$tkey]["cmd"], $taskPoll[$tkey]["args"]);
|
||||
} else {
|
||||
// parent (scheduler)
|
||||
$taskPoll[$tkey]['pid'] = $pid;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case task_abstract::STATE_STARTED:
|
||||
$crashed = false;
|
||||
// If no process, the task is probably manually ran
|
||||
|
||||
if ($this->method == self::METHOD_PROC_OPEN) {
|
||||
if ($taskPoll[$tkey]["process"]) {
|
||||
$taskPoll[$tkey]["killat"] = NULL;
|
||||
|
||||
if (is_resource($taskPoll[$tkey]["process"])) {
|
||||
$proc_status = proc_get_status($taskPoll[$tkey]["process"]);
|
||||
if ($proc_status['running']) {
|
||||
$runningtask ++;
|
||||
} else {
|
||||
$crashed = true;
|
||||
}
|
||||
} else {
|
||||
$crashed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $crashed && ! $taskPoll[$tkey]['task']->getPID()) {
|
||||
$crashed = true;
|
||||
}
|
||||
|
||||
if (! $crashed) {
|
||||
$taskPoll[$tkey]["killat"] = NULL;
|
||||
$runningtask ++;
|
||||
} else {
|
||||
// crashed !
|
||||
$taskPoll[$tkey]["task"]->incrementCrashCounter();
|
||||
|
||||
if ($this->method == self::METHOD_PROC_OPEN) {
|
||||
@fclose($taskPoll[$tkey]["pipes"][1]);
|
||||
@fclose($taskPoll[$tkey]["pipes"][2]);
|
||||
@proc_close($taskPoll[$tkey]["process"]);
|
||||
$taskPoll[$tkey]["process"] = null;
|
||||
}
|
||||
$this->log(
|
||||
sprintf(
|
||||
"Task %s crashed %d times"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
, $taskPoll[$tkey]["task"]->getCrashCounter()
|
||||
)
|
||||
);
|
||||
|
||||
if ($taskPoll[$tkey]["task"]->getCrashCounter() > 5) {
|
||||
$taskPoll[$tkey]["task"]->setState(task_abstract::STATE_STOPPED);
|
||||
} else {
|
||||
$taskPoll[$tkey]["task"]->setState(task_abstract::STATE_TOSTART);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case task_abstract::STATE_TOSTOP:
|
||||
|
||||
if ($taskPoll[$tkey]["killat"] === NULL) {
|
||||
$taskPoll[$tkey]["killat"] = time() + self::TASKDELAYTOQUIT;
|
||||
}
|
||||
|
||||
$pid = $taskPoll[$tkey]['task']->getPID();
|
||||
if ($pid) {
|
||||
// send ctrl-c to tell the task to CLEAN quit
|
||||
// (just in case the task doesn't pool his status 'tostop' fast enough)
|
||||
if (function_exists('posix_kill')) {
|
||||
if (! $taskPoll[$tkey]['sigterm_sent']) {
|
||||
posix_kill($pid, SIGTERM);
|
||||
$this->log(
|
||||
sprintf(
|
||||
"SIGTERM sent to task %s (pid=%s)"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
, $pid
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (($dt = $taskPoll[$tkey]["killat"] - time()) < 0) {
|
||||
// task still alive, time to kill
|
||||
if ($this->method == self::METHOD_PROC_OPEN) {
|
||||
proc_terminate($taskPoll[$tkey]["process"], 9);
|
||||
@fclose($taskPoll[$tkey]["pipes"][1]);
|
||||
@fclose($taskPoll[$tkey]["pipes"][2]);
|
||||
proc_close($taskPoll[$tkey]["process"]);
|
||||
$this->log(
|
||||
sprintf(
|
||||
"proc_terminate(...) done on task %s (pid=%s)"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
, $pid
|
||||
)
|
||||
);
|
||||
} else { // METHOD_FORK, I guess we have posix
|
||||
posix_kill($pid, 9);
|
||||
$this->log(
|
||||
sprintf(
|
||||
"SIGKILL sent to task %s (pid=%s)"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
, $pid
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$this->log(
|
||||
sprintf(
|
||||
"waiting task %s to quit (kill in %d seconds)"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
, $dt
|
||||
)
|
||||
);
|
||||
$runningtask ++;
|
||||
}
|
||||
} else {
|
||||
$this->log(
|
||||
sprintf(
|
||||
"task %s has quit"
|
||||
, $taskPoll[$tkey]["task"]->getID()
|
||||
)
|
||||
);
|
||||
$taskPoll[$tkey]["task"]->setState(task_abstract::STATE_STOPPED);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case task_abstract::STATE_STOPPED:
|
||||
case task_abstract::STATE_TODELETE:
|
||||
if ($this->method == self::METHOD_PROC_OPEN) {
|
||||
if ($taskPoll[$tkey]["process"]) {
|
||||
@fclose($taskPoll[$tkey]["pipes"][1]);
|
||||
@fclose($taskPoll[$tkey]["pipes"][2]);
|
||||
@proc_close($taskPoll[$tkey]["process"]);
|
||||
|
||||
$taskPoll[$tkey]["process"] = null;
|
||||
}
|
||||
} elseif ($this->method == self::METHOD_FORK) {
|
||||
$pid = $taskPoll[$tkey]['pid'];
|
||||
if ($pid) {
|
||||
$status = NULL;
|
||||
if (pcntl_waitpid($pid, $status, WNOHANG) === $pid) {
|
||||
// pid has quit
|
||||
$taskPoll[$tkey]['pid'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(function_exists('pcntl_sigprocmask')) {
|
||||
@pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD));
|
||||
}
|
||||
$this->sleep(1);
|
||||
for ($i = 0; $this->schedstatus=='started' && $i < $sleeptime; $i++) {
|
||||
$this->sleep(1);
|
||||
}
|
||||
if(function_exists('pcntl_sigprocmask')) {
|
||||
@pcntl_sigprocmask(SIG_UNBLOCK, array(SIGCHLD));
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "UPDATE sitepreff SET schedstatus='stopped', schedpid='0'";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute();
|
||||
$stmt->closeCursor();
|
||||
|
||||
$this->log("Scheduler2 is quitting.");
|
||||
|
||||
ftruncate($schedlock, 0);
|
||||
fclose($schedlock);
|
||||
|
||||
$this->log("Scheduler2 has quit.\n");
|
||||
}
|
||||
}
|
@@ -1,909 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Alchemy\Phrasea\Core\Configuration\Configuration;
|
||||
|
||||
abstract class task_abstract
|
||||
{
|
||||
const LAUCHED_BY_BROWSER = 1;
|
||||
const LAUCHED_BY_COMMANDLINE = 2;
|
||||
const STATE_TOSTOP = 'tostop';
|
||||
const STATE_STARTED = 'started';
|
||||
const STATE_TOSTART = 'tostart';
|
||||
const STATE_TORESTART = 'torestart';
|
||||
const STATE_STOPPED = 'stopped';
|
||||
const STATE_TODELETE = 'todelete';
|
||||
const RUNNER_MANUAL = 'manual';
|
||||
const RUNNER_SCHEDULER = 'scheduler';
|
||||
const STATE_OK = 'STATE_OK';
|
||||
const STATE_MAXMEGSREACHED = 'STATE_MAXMEGS';
|
||||
const STATE_MAXRECSDONE = 'STATE_MAXRECS';
|
||||
const STATE_FINISHED = 'STATE_FINISHED';
|
||||
const SIGNAL_SCHEDULER_DIED = 'SIGNAL_SCHEDULER_DIED';
|
||||
const ERR_ALREADY_RUNNING = 114; // aka EALREADY (Operation already in progress)
|
||||
|
||||
// default min/max values for the 'restart task every n records' setting on tasks
|
||||
const MINRECS = 10;
|
||||
const MAXRECS = 100;
|
||||
// default min/max values for the 'overflow memory (Mo)' setting on tasks
|
||||
const MINMEGS = 64;
|
||||
const MAXMEGS = 256;
|
||||
// default memory value
|
||||
const DEFMEGS = 92;
|
||||
// default min/max values for the 'period (seconds)' setting on tasks
|
||||
const MINPERIOD = 10;
|
||||
const MAXPERIOD = 3600;
|
||||
// default min/max values for the 'flush every n records' setting on tasks
|
||||
const MINFLUSH = 1;
|
||||
const MAXFLUSH = 100;
|
||||
|
||||
const LOG_DEBUG = Logger::DEBUG;
|
||||
const LOG_INFO = Logger::INFO;
|
||||
const LOG_WARNING = Logger::WARNING;
|
||||
const LOG_ERROR = Logger::ERROR;
|
||||
const LOG_CRITICAL = Logger::CRITICAL;
|
||||
const LOG_ALERT = Logger::ALERT;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Logger
|
||||
*/
|
||||
protected $logger;
|
||||
protected $suicidable = false;
|
||||
protected $launched_by = 0;
|
||||
|
||||
/**
|
||||
* Number of records done
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $records_done = 0;
|
||||
|
||||
/**
|
||||
* Maximum number of records before we restart the task
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $maxrecs;
|
||||
|
||||
/**
|
||||
* Boolean switch to stop the task
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $running = false;
|
||||
|
||||
/**
|
||||
* current number of loops done
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $loop = 0;
|
||||
|
||||
/**
|
||||
* max number of loops before the task is restarted
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $maxloops = 5;
|
||||
|
||||
/**
|
||||
* task state, either ok, maxmemory or maxrecords reached
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $current_state;
|
||||
|
||||
/**
|
||||
* maximum memory allowed
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $maxmegs;
|
||||
protected $runner;
|
||||
|
||||
/**
|
||||
* delay between two loops
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $title;
|
||||
protected $settings;
|
||||
protected $crash_counter;
|
||||
protected $status;
|
||||
protected $active;
|
||||
protected $debug = false;
|
||||
protected $completed_percentage;
|
||||
protected $period = 60;
|
||||
protected $taskid = NULL;
|
||||
protected $system = '';
|
||||
protected $dependencyContainer;
|
||||
|
||||
public function __construct($taskid, Pimple $dependencyContainer, Logger $logger)
|
||||
{
|
||||
$this->dependencyContainer = $dependencyContainer;
|
||||
|
||||
$this->logger = $logger;
|
||||
|
||||
$this->taskid = (integer) $taskid;
|
||||
|
||||
phrasea::use_i18n($this->dependencyContainer['locale']);
|
||||
|
||||
$this->launched_by = array_key_exists("REQUEST_URI", $_SERVER) ? self::LAUCHED_BY_BROWSER : self::LAUCHED_BY_COMMANDLINE;
|
||||
|
||||
try {
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
} catch (Exception $e) {
|
||||
$this->log($e->getMessage());
|
||||
$this->log(("Warning : abox connection lost, restarting in 10 min."));
|
||||
|
||||
$this->sleep(60 * 10);
|
||||
|
||||
$this->running = false;
|
||||
|
||||
return '';
|
||||
}
|
||||
$sql = 'SELECT crashed, pid, status, active, settings, name, completed, runner
|
||||
FROM task2 WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':taskid' => $this->getID()));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
if (! $row) {
|
||||
throw new Exception('Unknown task id');
|
||||
}
|
||||
$this->title = $row['name'];
|
||||
$this->crash_counter = (integer) $row['crashed'];
|
||||
$this->active = ! ! $row['active'];
|
||||
$this->settings = $row['settings'];
|
||||
$this->runner = $row['runner'];
|
||||
$this->completed_percentage = (int) $row['completed'];
|
||||
$this->settings = $row['settings'];
|
||||
|
||||
if (false !== $sx = @simplexml_load_string($this->settings)) {
|
||||
$this->loadSettings($sx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClass()
|
||||
{
|
||||
return get_class($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the state of the task (task_abstract::STATE_*)
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
static $stmt = NULL;
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
if (! $stmt) {
|
||||
$sql = 'SELECT status FROM task2 WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
}
|
||||
$stmt->execute(array(':taskid' => $this->taskid));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
if (! $row) {
|
||||
throw new Exception('Unknown task id');
|
||||
}
|
||||
unset($conn);
|
||||
|
||||
return $row['status'];
|
||||
}
|
||||
|
||||
/**
|
||||
* to be overwritten by tasks : ECHO text to be included in <head> in task interface
|
||||
*/
|
||||
public function printInterfaceHEAD()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* to be overwritten by tasks : ECHO javascript to be included in <head> in task interface
|
||||
*/
|
||||
public function printInterfaceJS()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasInterfaceHTML()
|
||||
{
|
||||
return method_exists($this, "getInterfaceHTML");
|
||||
}
|
||||
|
||||
/**
|
||||
* set the state of the task (task_abstract::STATE_*)
|
||||
*
|
||||
* @param String $status
|
||||
* @throws Exception_InvalidArgument
|
||||
*/
|
||||
public function setState($status)
|
||||
{
|
||||
$av_status = array(
|
||||
self::STATE_STARTED,
|
||||
self::STATE_TOSTOP,
|
||||
self::STATE_STOPPED,
|
||||
self::STATE_TORESTART,
|
||||
self::STATE_TOSTART,
|
||||
self::STATE_TODELETE
|
||||
);
|
||||
|
||||
if ( ! in_array($status, $av_status)) {
|
||||
throw new Exception_InvalidArgument(sprintf('unknown status `%s`', $status));
|
||||
}
|
||||
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
|
||||
$sql = 'UPDATE task2 SET status = :status WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':status' => $status, ':taskid' => $this->getID()));
|
||||
$stmt->closeCursor();
|
||||
$this->log(sprintf("task %d <- %s", $this->getID(), $status));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param boolean $active 'active' means 'auto-start when scheduler starts'
|
||||
* @return \task_abstract
|
||||
*/
|
||||
public function setActive($active)
|
||||
{
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
|
||||
$sql = 'UPDATE task2 SET active = :active WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':active' => ($active ? '1' : '0'), ':taskid' => $this->getID()));
|
||||
$stmt->closeCursor();
|
||||
|
||||
$this->active = ! ! $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $title
|
||||
* @return \task_abstract
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$title = strip_tags($title);
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
|
||||
$sql = 'UPDATE task2 SET name = :title WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':title' => $title, ':taskid' => $this->getID()));
|
||||
$stmt->closeCursor();
|
||||
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $settings xml settings as STRING
|
||||
* @throws Exception_InvalidArgument if not proper xml
|
||||
* @return \task_abstract
|
||||
*/
|
||||
public function setSettings($settings)
|
||||
{
|
||||
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
if (!@$dom->loadXML($settings)) {
|
||||
throw new Exception_InvalidArgument('Bad XML');
|
||||
}
|
||||
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
|
||||
$sql = 'UPDATE task2 SET settings = :settings WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':settings' => $dom->saveXML(), ':taskid' => $this->getID()));
|
||||
$stmt->closeCursor();
|
||||
|
||||
$this->settings = $settings;
|
||||
|
||||
$this->loadSettings(simplexml_load_string($dom->saveXML()));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return \task_abstract
|
||||
*/
|
||||
public function resetCrashCounter()
|
||||
{
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
|
||||
$sql = 'UPDATE task2 SET crashed = 0 WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':taskid' => $this->getID()));
|
||||
$stmt->closeCursor();
|
||||
|
||||
$this->crash_counter = 0;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCrashCounter()
|
||||
{
|
||||
return $this->crash_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function incrementCrashCounter()
|
||||
{
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
|
||||
$sql = 'UPDATE task2 SET crashed = crashed + 1 WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':taskid' => $this->getID()));
|
||||
$stmt->closeCursor();
|
||||
|
||||
return ++ $this->crash_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSettings()
|
||||
{
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'active' means 'auto-start when scheduler starts'
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
*/
|
||||
public function isActive()
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCompletedPercentage()
|
||||
{
|
||||
return $this->completed_percentage;
|
||||
}
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
throw new \LogicException('This method must be implemented');
|
||||
}
|
||||
|
||||
public static function help()
|
||||
{
|
||||
throw new \LogicException('This method must be implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return enum (self::RUNNER_MANUAL or self::RUNNER_SCHEDULER)
|
||||
*/
|
||||
public function getRunner()
|
||||
{
|
||||
return $this->runner;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param enum $runner (self::RUNNER_MANUAL or self::RUNNER_SCHEDULER)
|
||||
* @throws Exception_InvalidArgument
|
||||
* @return \task_abstract
|
||||
*/
|
||||
public function setRunner($runner)
|
||||
{
|
||||
if ($runner != self::RUNNER_MANUAL && $runner != self::RUNNER_SCHEDULER) {
|
||||
throw new Exception_InvalidArgument(sprintf('unknown runner `%s`', $runner));
|
||||
}
|
||||
|
||||
$this->runner = $runner;
|
||||
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
$sql = 'UPDATE task2 SET runner = :runner WHERE task_id = :taskid';
|
||||
|
||||
$params = array(
|
||||
':taskid' => $this->getID()
|
||||
, ':runner' => $this->runner
|
||||
);
|
||||
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$stmt->closeCursor();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
if ( ! $this->getPID()) { // do not delete a running task
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
$sql = "DELETE FROM task2 WHERE task_id = :task_id";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':task_id' => $this->getID()));
|
||||
$stmt->closeCursor();
|
||||
|
||||
$lock_file = $this->dependencyContainer['root.path'] . '/tmp/locks/task_' . $this->getID() . '.lock';
|
||||
@unlink($lock_file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set last execution time to now()
|
||||
*/
|
||||
public function setLastExecTime()
|
||||
{
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
$sql = 'UPDATE task2 SET last_exec_time=NOW() WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':taskid' => $this->getID()));
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last time the task was executed
|
||||
*
|
||||
* @return null|\DateTime
|
||||
*/
|
||||
public function getLastExecTime()
|
||||
{
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
|
||||
$sql = 'SELECT last_exec_time FROM task2 WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':taskid' => $this->getID()));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
$time = null;
|
||||
if ($row['last_exec_time'] != '0000-00-00 00:00:00') {
|
||||
$time = new \DateTime($row['last_exec_time']);
|
||||
}
|
||||
|
||||
return $time;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return null|integer
|
||||
* pid (int) of the task
|
||||
* NULL : the pid file is not locked (task no running)
|
||||
*/
|
||||
public function getPID()
|
||||
{
|
||||
$pid = NULL;
|
||||
|
||||
$lockfile = $this->getLockfilePath();
|
||||
|
||||
if (($fd = fopen($lockfile, 'a+')) != FALSE) {
|
||||
if (flock($fd, LOCK_EX | LOCK_NB) === FALSE) {
|
||||
// already locked ? : task running
|
||||
$pid = (integer) fgets($fd);
|
||||
} else {
|
||||
// can lock : not running
|
||||
flock($fd, LOCK_UN);
|
||||
}
|
||||
fclose($fd);
|
||||
}
|
||||
|
||||
return $pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* set to false to ask the task to quit its loop
|
||||
* @param boolean $stat
|
||||
*
|
||||
*/
|
||||
public function setRunning($stat)
|
||||
{
|
||||
$this->running = $stat;
|
||||
}
|
||||
|
||||
protected function pause($when_started = 0)
|
||||
{
|
||||
$this->log($this->records_done . ' records done');
|
||||
if ($this->running) { // && $this->records_done == 0)
|
||||
$when_started = time() - $when_started;
|
||||
if ($when_started < $this->period) {
|
||||
for ($t = $this->period - $when_started; $this->running && $t > 0; $t --) {
|
||||
// DON'T do sleep($this->period - $when_started) because it prevents ticks !
|
||||
$s = $this->getState();
|
||||
if ($s == self::STATE_TOSTOP) {
|
||||
$this->setState(self::STATE_STOPPED);
|
||||
$this->running = FALSE;
|
||||
} else {
|
||||
$this->sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sleep n seconds
|
||||
*
|
||||
* @param int $nsec
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function sleep($nsec)
|
||||
{
|
||||
$nsec = (integer) $nsec;
|
||||
if ($nsec < 0) {
|
||||
throw new \InvalidArgumentException(sprintf("(%s) is not > 0"));
|
||||
}
|
||||
|
||||
$end = microtime(true) + $nsec;
|
||||
while ($this->running && microtime(true) < $end) {
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string fullpath to the pid file for the task
|
||||
*/
|
||||
private function getLockfilePath()
|
||||
{
|
||||
$lockdir = $this->dependencyContainer['root.path'] . '/tmp/locks/';
|
||||
$lockfilePath = ($lockdir . 'task_' . $this->getID() . '.lock');
|
||||
|
||||
return $lockfilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return resource file descriptor of the OPENED pid file
|
||||
* @throws Exception if file is already locked (task running)
|
||||
*/
|
||||
private function lockTask()
|
||||
{
|
||||
$lockfile = $this->getLockfilePath();
|
||||
|
||||
$lockFD = fopen($lockfile, 'a+');
|
||||
|
||||
$locker = true;
|
||||
if (flock($lockFD, LOCK_EX | LOCK_NB, $locker) === FALSE) {
|
||||
$this->log("runtask::ERROR : task already running.");
|
||||
fclose($lockFD);
|
||||
|
||||
throw new Exception('task already running.', self::ERR_ALREADY_RUNNING);
|
||||
}
|
||||
|
||||
// here we run the task
|
||||
ftruncate($lockFD, 0);
|
||||
fwrite($lockFD, '' . getmypid());
|
||||
fflush($lockFD);
|
||||
|
||||
// for windows : unlock then lock shared to allow OTHER processes to read the file
|
||||
// too bad : no critical section nor atomicity
|
||||
flock($lockFD, LOCK_UN);
|
||||
flock($lockFD, LOCK_SH);
|
||||
|
||||
return $lockFD;
|
||||
}
|
||||
|
||||
final public function run($runner)
|
||||
{
|
||||
$lockFD = $this->lockTask();
|
||||
|
||||
$this->setRunner($runner);
|
||||
$this->setState(self::STATE_STARTED);
|
||||
|
||||
// run the real code of the task -into the task's class- (may throw an exception)
|
||||
$exception = NULL;
|
||||
try {
|
||||
$this->run2();
|
||||
} catch (\Exception $exception) {
|
||||
|
||||
}
|
||||
|
||||
if ($this->getState() === self::STATE_STARTED && $this->runner === self::RUNNER_MANUAL) {
|
||||
$this->setState(self::STATE_STOPPED);
|
||||
}
|
||||
|
||||
// in any case, exception or not, the task is ending so unlock the pid file
|
||||
$this->unlockTask($lockFD);
|
||||
|
||||
// if something went wrong, report
|
||||
if ($exception) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param resource $lockFD file descriptor of the OPENED lock file
|
||||
*/
|
||||
private function unlockTask($lockFD)
|
||||
{
|
||||
flock($lockFD, LOCK_UN | LOCK_NB);
|
||||
ftruncate($lockFD, 0);
|
||||
fclose($lockFD);
|
||||
|
||||
$lockfile = $this->getLockfilePath();
|
||||
@unlink($lockfile);
|
||||
|
||||
switch ($this->getState()) {
|
||||
case self::STATE_TODELETE:
|
||||
$this->delete();
|
||||
break;
|
||||
case self::STATE_TOSTOP:
|
||||
$this->setState(self::STATE_STOPPED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function run2();
|
||||
|
||||
protected function processLoop(&$box, &$rs)
|
||||
{
|
||||
$ret = self::STATE_OK;
|
||||
|
||||
$rowstodo = count($rs);
|
||||
$rowsdone = 0;
|
||||
|
||||
if ($rowstodo > 0) {
|
||||
$this->setProgress(0, $rowstodo);
|
||||
}
|
||||
|
||||
foreach ($rs as $row) {
|
||||
|
||||
try {
|
||||
// process one record
|
||||
$this->processOneContent($box, $row);
|
||||
} catch (Exception $e) {
|
||||
$this->log("Exception : " . $e->getMessage() . " " . basename($e->getFile()) . " " . $e->getLine());
|
||||
}
|
||||
|
||||
$this->records_done ++;
|
||||
$this->setProgress($rowsdone, $rowstodo);
|
||||
|
||||
// post-process
|
||||
$this->postProcessOneContent($box, $row);
|
||||
|
||||
$rowsdone ++;
|
||||
|
||||
$current_memory = memory_get_usage();
|
||||
if ($current_memory >> 20 >= $this->maxmegs) {
|
||||
$this->log(sprintf("Max memory (%s M) reached (actual is %.02f M)", $this->maxmegs, ($current_memory >> 10) / 1024), self::LOG_ERROR);
|
||||
$this->running = FALSE;
|
||||
$ret = self::STATE_MAXMEGSREACHED;
|
||||
}
|
||||
|
||||
if ($this->records_done >= (integer) ($this->maxrecs)) {
|
||||
$this->log(sprintf("Max records done (%s) reached (actual is %s)", $this->maxrecs, $this->records_done));
|
||||
$this->running = FALSE;
|
||||
$ret = self::STATE_MAXRECSDONE;
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->getState() == self::STATE_TOSTOP) {
|
||||
$this->running = FALSE;
|
||||
$ret = self::STATE_TOSTOP;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->running = FALSE;
|
||||
}
|
||||
|
||||
if (! $this->running) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
// if nothing was done, at least check the status
|
||||
if ($rowsdone == 0 && $this->running) {
|
||||
|
||||
$current_memory = memory_get_usage();
|
||||
if ($current_memory >> 20 >= $this->maxmegs) {
|
||||
$this->log(sprintf("Max memory (%s M) reached (current is %.02f M)", $this->maxmegs, ($current_memory >> 10) / 1024), self::LOG_ERROR);
|
||||
$this->running = FALSE;
|
||||
$ret = self::STATE_MAXMEGSREACHED;
|
||||
}
|
||||
|
||||
if ($this->records_done >= (integer) ($this->maxrecs)) {
|
||||
$this->log(sprintf("Max records done (%s) reached (actual is %s)", $this->maxrecs, $this->records_done));
|
||||
$this->running = FALSE;
|
||||
$ret = self::STATE_MAXRECSDONE;
|
||||
}
|
||||
|
||||
try {
|
||||
$status = $this->getState();
|
||||
if ($status == self::STATE_TOSTOP) {
|
||||
$this->running = FALSE;
|
||||
$ret = self::STATE_TOSTOP;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->running = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($rowstodo > 0) {
|
||||
$this->setProgress(0, 0);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
protected function loadSettings(SimpleXMLElement $sx_task_settings)
|
||||
{
|
||||
$this->period = (integer) $sx_task_settings->period;
|
||||
if ($this->period < self::MINPERIOD || $this->period > self::MAXPERIOD) {
|
||||
$this->period = self::MINPERIOD;
|
||||
}
|
||||
|
||||
$this->maxrecs = (integer) $sx_task_settings->maxrecs;
|
||||
if ($sx_task_settings->maxrecs < self::MINRECS || $sx_task_settings->maxrecs > self::MAXRECS) {
|
||||
$this->maxrecs = self::MINRECS;
|
||||
}
|
||||
|
||||
$this->maxmegs = (integer) $sx_task_settings->maxmegs;
|
||||
if ($sx_task_settings->maxmegs < self::MINMEGS || $sx_task_settings->maxmegs > self::MAXMEGS) {
|
||||
$this->maxmegs = self::DEFMEGS;
|
||||
}
|
||||
|
||||
$this->record_buffer_size = (integer) $sx_task_settings->flush;
|
||||
if ($sx_task_settings->flush < self::MINFLUSH || $sx_task_settings->flush > self::MAXFLUSH) {
|
||||
$this->record_buffer_size = self::MINFLUSH;
|
||||
}
|
||||
}
|
||||
|
||||
protected function incrementLoops()
|
||||
{
|
||||
if ($this->getRunner() == self::RUNNER_SCHEDULER && ++ $this->loop >= $this->maxloops) {
|
||||
$this->log(sprintf(('%d loops done, restarting'), $this->loop));
|
||||
$this->setState(self::STATE_TORESTART);
|
||||
|
||||
$this->running = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function log($message, $level=self::LOG_INFO)
|
||||
{
|
||||
// nb : self::log_levels ARE standard log levels, ok with monolog
|
||||
$this->logger->addRecord($level, $message);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function interfaceAvailable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getInterfaceHTML()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function graphic2xml($oldxml)
|
||||
{
|
||||
return $oldxml;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \Pimple $dependencyContainer
|
||||
* @param string $class_name
|
||||
* @param string $settings
|
||||
* @return task_abstract
|
||||
*/
|
||||
public static function create(\Pimple $dependencyContainer, $settings = null)
|
||||
{
|
||||
$sql = 'INSERT INTO task2
|
||||
(task_id, usr_id_owner, status, crashed, active,
|
||||
name, last_exec_time, class, settings)
|
||||
VALUES
|
||||
(null, 0, "stopped", 0, :active,
|
||||
:name, "0000/00/00 00:00:00", :class, :settings)';
|
||||
|
||||
$domdoc = new DOMDocument();
|
||||
if ($settings && ! $domdoc->loadXML($settings)) {
|
||||
throw new Exception('Invalid settings');
|
||||
} elseif (! $settings) {
|
||||
$settings = static::getDefaultSettings($dependencyContainer['phraseanet.configuration']);
|
||||
}
|
||||
|
||||
$params = array(
|
||||
':active' => 1
|
||||
, ':name' => ''
|
||||
, ':class' => get_called_class()
|
||||
, ':settings' => $settings
|
||||
);
|
||||
|
||||
$stmt = $dependencyContainer['phraseanet.appbox']->get_connection()->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$stmt->closeCursor();
|
||||
|
||||
$tid = $dependencyContainer['phraseanet.appbox']->get_connection()->lastInsertId();
|
||||
|
||||
$task = new static($tid, $dependencyContainer, $dependencyContainer['task-manager.logger']);
|
||||
$task->setTitle($task->getName());
|
||||
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int id of the task
|
||||
*/
|
||||
public function getID()
|
||||
{
|
||||
return $this->taskid;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $done
|
||||
* @param int $todo
|
||||
* @return \task_abstract
|
||||
*/
|
||||
public function setProgress($done, $todo)
|
||||
{
|
||||
$p = ($todo > 0) ? ((100 * $done) / $todo) : -1;
|
||||
|
||||
try {
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
$sql = 'UPDATE task2 SET completed = :p WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(
|
||||
':p' => $p,
|
||||
':taskid' => $this->getID()
|
||||
));
|
||||
$stmt->closeCursor();
|
||||
$this->completed_percentage = $p;
|
||||
} catch (Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Configuration $config
|
||||
* @param array $params
|
||||
* @return string
|
||||
*/
|
||||
public static function getDefaultSettings(Configuration $config, array $params = array())
|
||||
{
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<tasksettings>\n</tasksettings>";
|
||||
}
|
||||
}
|
@@ -1,131 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
|
||||
* @link www.phraseanet.com
|
||||
*/
|
||||
abstract class task_appboxAbstract extends task_abstract
|
||||
{
|
||||
|
||||
abstract protected function retrieveContent(appbox $appbox);
|
||||
|
||||
abstract protected function processOneContent(appbox $appbox, $row);
|
||||
|
||||
abstract protected function postProcessOneContent(appbox $appbox, $row);
|
||||
|
||||
protected function run2()
|
||||
{
|
||||
$this->running = TRUE;
|
||||
while ($this->running) {
|
||||
try {
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
} catch (Exception $e) {
|
||||
$this->log($e->getMessage());
|
||||
if ($this->getRunner() == self::RUNNER_SCHEDULER) {
|
||||
$this->log(("Warning : abox connection lost, restarting in 10 min."));
|
||||
|
||||
$this->sleep(60 * 10);
|
||||
// because connection is lost we cannot change status to 'torestart'
|
||||
// anyway the current status 'running' with no pid
|
||||
// will enforce the scheduler to restart the task
|
||||
} else {
|
||||
// runner = manual : can't restart so simply quit
|
||||
}
|
||||
$this->running = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLastExecTime();
|
||||
|
||||
try {
|
||||
$sql = 'SELECT settings FROM task2 WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':taskid' => $this->getID()));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
$this->records_done = 0;
|
||||
$duration = time();
|
||||
} catch (Exception $e) {
|
||||
// failed sql, simply return
|
||||
$this->running = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($row) {
|
||||
if (! $this->running) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->loadSettings(simplexml_load_string($row['settings']));
|
||||
} catch (Exception $e) {
|
||||
$this->log($e->getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
$process_ret = $this->process($this->dependencyContainer['phraseanet.appbox']);
|
||||
|
||||
switch ($process_ret) {
|
||||
case self::STATE_MAXMEGSREACHED:
|
||||
case self::STATE_MAXRECSDONE:
|
||||
if ($this->getRunner() == self::RUNNER_SCHEDULER) {
|
||||
$this->setState(self::STATE_TORESTART);
|
||||
$this->running = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case self::STATE_TOSTOP:
|
||||
$this->setState(self::STATE_TOSTOP);
|
||||
$this->running = FALSE;
|
||||
break;
|
||||
|
||||
case self::STATE_TODELETE: // formal 'suicidable'
|
||||
$this->setState(self::STATE_TODELETE);
|
||||
$this->running = FALSE;
|
||||
break;
|
||||
}
|
||||
} // if(row)
|
||||
|
||||
$this->incrementLoops();
|
||||
|
||||
if ($this->running) {
|
||||
$this->pause($duration);
|
||||
}
|
||||
} // while running
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <type>
|
||||
*/
|
||||
protected function process(appbox $appbox)
|
||||
{
|
||||
$ret = self::STATE_OK;
|
||||
|
||||
try {
|
||||
// get the records to process
|
||||
$rs = $this->retrieveContent($appbox);
|
||||
|
||||
// process the records
|
||||
$ret = $this->processLoop($appbox, $rs);
|
||||
} catch (Exception $e) {
|
||||
$this->log('Error : ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -1,173 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
|
||||
* @link www.phraseanet.com
|
||||
*/
|
||||
abstract class task_databoxAbstract extends task_abstract
|
||||
{
|
||||
protected $mono_sbas_id;
|
||||
|
||||
abstract protected function retrieveSbasContent(databox $databox);
|
||||
|
||||
abstract protected function processOneContent(databox $databox, $row);
|
||||
|
||||
abstract protected function flushRecordsSbas();
|
||||
|
||||
abstract protected function postProcessOneContent(databox $databox, $row);
|
||||
|
||||
protected function run2()
|
||||
{
|
||||
$task_must_delete = FALSE; // if the task must be deleted (suicide) after run
|
||||
$this->running = TRUE;
|
||||
while ($this->running) {
|
||||
try {
|
||||
$conn = connection::getPDOConnection($this->dependencyContainer);
|
||||
} catch (PDOException $e) {
|
||||
$this->log($e->getMessage(), self::LOG_ERROR );
|
||||
if ($this->getRunner() == self::RUNNER_SCHEDULER) {
|
||||
$this->log("appbox connection lost, restarting in 10 min.", self::LOG_ERROR);
|
||||
|
||||
$this->sleep(60 * 10);
|
||||
// because connection is lost we cannot change status to 'torestart'
|
||||
// anyway the current status 'running' with no pid
|
||||
// will enforce the scheduler to restart the task
|
||||
} else {
|
||||
// runner = manual : can't restart so simply quit
|
||||
$this->log("appbox connection lost, quit.", self::LOG_ERROR);
|
||||
}
|
||||
$this->running = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLastExecTime();
|
||||
try {
|
||||
if ($this->mono_sbas_id) {
|
||||
$sql = 'SELECT sbas_id, task2.* FROM sbas, task2 WHERE task_id=:taskid AND sbas_id=:sbas_id';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':taskid' => $this->getID(), ':sbas_id' => $this->mono_sbas_id));
|
||||
} else {
|
||||
$sql = 'SELECT sbas_id, task2.* FROM sbas, task2 WHERE task_id = :taskid';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(array(':taskid' => $this->getID()));
|
||||
}
|
||||
$rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
$this->records_done = 0;
|
||||
$duration = time();
|
||||
} catch (Exception $e) {
|
||||
// failed sql, simply return
|
||||
$this->running = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($rs as $row) { // every sbas
|
||||
if (! $this->running) {
|
||||
break;
|
||||
}
|
||||
|
||||
$this->sbas_id = (int) $row['sbas_id'];
|
||||
$this->log(sprintf('This task works now on sbasid=%s ', $this->sbas_id), self::LOG_INFO);
|
||||
|
||||
try {
|
||||
// get the records to process
|
||||
$databox = $this->dependencyContainer['phraseanet.appbox']->get_databox((int) $row['sbas_id']);
|
||||
} catch (Exception $e) {
|
||||
$this->log(sprintf('can\'t connect to sbas(%s) because "%s"',
|
||||
$row['sbas_id'],
|
||||
$e->getMessage()),
|
||||
self::LOG_WARNING
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->loadSettings(simplexml_load_string($row['settings']));
|
||||
} catch (Exception $e) {
|
||||
$this->log(sprintf('can\'t get get settings of task because "%s"',
|
||||
$e->getMessage()),
|
||||
self::LOG_WARNING
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$process_ret = $this->processSbas($databox);
|
||||
|
||||
// close the cnx to the dbox
|
||||
$connbas = $databox->get_connection();
|
||||
if ($connbas instanceof PDO) {
|
||||
$connbas->close();
|
||||
unset($connbas);
|
||||
}
|
||||
|
||||
switch ($process_ret) {
|
||||
case self::STATE_MAXMEGSREACHED:
|
||||
case self::STATE_MAXRECSDONE:
|
||||
if ($this->getRunner() == self::RUNNER_SCHEDULER) {
|
||||
$this->setState(self::STATE_TORESTART);
|
||||
$this->running = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case self::STATE_TOSTOP:
|
||||
$this->setState(self::STATE_TOSTOP);
|
||||
$this->running = FALSE;
|
||||
break;
|
||||
|
||||
case self::STATE_TODELETE: // formal 'suicidable'
|
||||
// DO NOT SUICIDE IN THE LOOP, may have to work on other sbas !!!
|
||||
$task_must_delete = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
$this->flushRecordsSbas();
|
||||
}
|
||||
|
||||
$this->incrementLoops();
|
||||
|
||||
if ($this->running) {
|
||||
$this->pause($duration);
|
||||
}
|
||||
}
|
||||
|
||||
if ($task_must_delete) {
|
||||
$this->setState(self::STATE_TODELETE);
|
||||
$this->log('task will self delete', self::LOG_INFO);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <type>
|
||||
*/
|
||||
protected function processSbas(databox $databox)
|
||||
{
|
||||
$ret = self::STATE_OK;
|
||||
|
||||
try {
|
||||
// get the records to process
|
||||
$rs = $this->retrieveSbasContent($databox);
|
||||
|
||||
// process the records
|
||||
$ret = $this->processLoop($databox, $rs);
|
||||
} catch (Exception $e) {
|
||||
$this->log($e->getMessage(), self::LOG_ERROR);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -1,267 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Monolog\Logger;
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
use Symfony\Component\Process\PhpExecutableFinder;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
|
||||
* @link www.phraseanet.com
|
||||
*/
|
||||
class task_manager
|
||||
{
|
||||
const STATE_STOPPED = 'stopped';
|
||||
const STATE_STOPPING = 'stopping';
|
||||
const STATE_STARTED = 'started';
|
||||
const STATE_TOSTOP = 'tostop';
|
||||
|
||||
protected $app;
|
||||
protected $logger;
|
||||
protected $tasks;
|
||||
|
||||
public function __construct(Application $app, Logger $logger)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->logger = $logger;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLogger()
|
||||
{
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* status of scheduler and tasks
|
||||
* used do refresh the taskmanager page
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$ret = array(
|
||||
'time' => date("H:i:s"),
|
||||
'scheduler' => $this->getSchedulerState(),
|
||||
'tasks' => array()
|
||||
);
|
||||
|
||||
foreach ($this->getTasks(true) as $task) {
|
||||
if ($task->getState() == self::STATE_TOSTOP && $task->getPID() === NULL) {
|
||||
// fix
|
||||
$task->setState(self::STATE_STOPPED);
|
||||
}
|
||||
$id = $task->getID();
|
||||
$ret['tasks'][$id] = array(
|
||||
'id' => $id,
|
||||
'pid' => $task->getPID(),
|
||||
'crashed' => $task->getCrashCounter(),
|
||||
'completed' => $task->getCompletedPercentage(),
|
||||
'status' => $task->getState()
|
||||
);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function getTasks($refresh = false)
|
||||
{
|
||||
if ($this->tasks && !$refresh) {
|
||||
return $this->tasks;
|
||||
}
|
||||
|
||||
$sql = "SELECT task2.* FROM task2 ORDER BY task_id ASC";
|
||||
$stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
|
||||
$stmt->execute();
|
||||
$rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
$tasks = array();
|
||||
|
||||
foreach ($rs as $row) {
|
||||
$row['pid'] = NULL;
|
||||
|
||||
$classname = $row['class'];
|
||||
if (!class_exists($classname)) {
|
||||
if(substr($classname, 0, 12) == "task_period_") {
|
||||
$classfile = substr($classname, 12) . ".php";
|
||||
@require_once(__DIR__ . "/../../../config/classes/task/period/" . $classfile);
|
||||
}
|
||||
}
|
||||
if (!class_exists($classname)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$tasks[$row['task_id']] = new $classname($row['task_id'], $this->app, $this->logger);
|
||||
} catch (Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$this->tasks = $tasks;
|
||||
|
||||
return $this->tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $task_id
|
||||
* @return task_abstract
|
||||
*/
|
||||
public function getTask($task_id)
|
||||
{
|
||||
$tasks = $this->getTasks(false);
|
||||
|
||||
if (!isset($tasks[$task_id])) {
|
||||
throw new NotFoundHttpException('Unknown task_id ' . $task_id);
|
||||
}
|
||||
|
||||
return $tasks[$task_id];
|
||||
}
|
||||
|
||||
public function getSchedulerProcess()
|
||||
{
|
||||
//prevent scheduler to fail if GV_cli is not provided
|
||||
if (isset($this->app['phraseanet.configuration']['binaries']['php_binary'])) {
|
||||
$php = $this->app['phraseanet.configuration']['binaries']['php_binary'];
|
||||
} else {
|
||||
$finder = new PhpExecutableFinder();
|
||||
$php = $finder->find();
|
||||
}
|
||||
|
||||
$builder = ProcessBuilder::create(array($php));
|
||||
|
||||
if ($this->app['phraseanet.registry']->get('GV_PHP_INI')) {
|
||||
$builder->add('-c')->add($this->app['phraseanet.registry']->get('GV_PHP_INI'));
|
||||
}
|
||||
|
||||
return $builder
|
||||
->add('-f')
|
||||
->add($this->app['root.path'] . "/bin/console")
|
||||
->add('scheduler:start')
|
||||
->getProcess();
|
||||
}
|
||||
|
||||
public function setSchedulerState($status)
|
||||
{
|
||||
$av_status = array(
|
||||
self::STATE_STARTED,
|
||||
self::STATE_STOPPED,
|
||||
self::STATE_STOPPING,
|
||||
self::STATE_TOSTOP
|
||||
);
|
||||
|
||||
if (!in_array($status, $av_status))
|
||||
throw new Exception(sprintf('unknown status `%s` ', $status));
|
||||
|
||||
if ($status == self::STATE_TOSTOP && function_exists('posix_kill')) {
|
||||
$gs = $this->getSchedulerState();
|
||||
if ($gs['pid'] !== NULL) {
|
||||
@posix_kill($gs['pid'], 2); // 2 = SIGINT
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "UPDATE sitepreff SET schedstatus = :schedstatus, schedqtime=NOW()";
|
||||
$stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
|
||||
$stmt->execute(array(':schedstatus' => $status));
|
||||
$stmt->closeCursor();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSchedulerState()
|
||||
{
|
||||
$sql = "SELECT UNIX_TIMESTAMP()-UNIX_TIMESTAMP(schedqtime) AS qdelay
|
||||
, schedqtime AS updated_on
|
||||
, schedstatus AS status FROM sitepreff";
|
||||
$stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
|
||||
$stmt->execute();
|
||||
$ret = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
$pid = NULL;
|
||||
|
||||
$lockdir = $this->app['root.path'] . '/tmp/locks/';
|
||||
if (($schedlock = fopen($lockdir . 'scheduler.lock', 'a+')) != FALSE) {
|
||||
if (flock($schedlock, LOCK_EX | LOCK_NB) === FALSE) {
|
||||
// already locked : running !
|
||||
$pid = trim(fgets($schedlock, 512));
|
||||
} else {
|
||||
// can lock : not running
|
||||
flock($schedlock, LOCK_UN);
|
||||
}
|
||||
fclose($schedlock);
|
||||
}
|
||||
|
||||
if ($ret['updated_on'] == '0000-00-00 00:00:00') {
|
||||
$ret['updated_on'] = null;
|
||||
} else {
|
||||
$ret['updated_on'] = new \DateTime($ret['updated_on']);
|
||||
}
|
||||
|
||||
if ($pid === NULL && $ret['status'] !== 'stopped') {
|
||||
// auto fix
|
||||
$this->app['phraseanet.appbox']->get_connection()->exec('UPDATE sitepreff SET schedstatus=\'stopped\'');
|
||||
$ret['status'] = 'stopped';
|
||||
}
|
||||
$ret['pid'] = $pid;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Pcntl posix supported is enabled, false otherwise
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public static function isPosixPcntlSupported()
|
||||
{
|
||||
return extension_loaded('pcntl') && extension_loaded('posix');
|
||||
}
|
||||
|
||||
public static function getAvailableTasks()
|
||||
{
|
||||
$dirs = array(__DIR__ . "/period");
|
||||
|
||||
if (is_dir($configDir = __DIR__ . "/../../../config/classes/task/period")) {
|
||||
$dirs[] = $configDir;
|
||||
}
|
||||
|
||||
$tasks = array();
|
||||
$finder = new Finder();
|
||||
|
||||
foreach ($finder->files()->in($dirs)->name("*.php") as $file) {
|
||||
$classname = 'task_period_' . $file->getBasename('.php');
|
||||
|
||||
try {
|
||||
if (!class_exists($classname)) {
|
||||
@require_once($file->getRealPath());
|
||||
}
|
||||
if (class_exists($classname) && $classname::interfaceAvailable()) {
|
||||
$tasks[] = array(
|
||||
"class" => $classname,
|
||||
"name" => $classname::getName(),
|
||||
"err" => null
|
||||
);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
}
|
@@ -1,878 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Core\Configuration\Configuration;
|
||||
|
||||
class task_period_RecordMover extends task_appboxAbstract
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return _("Record Mover");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function help()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* return the xml (text) version of the form filled by the gui
|
||||
*
|
||||
* @param string $oldxml
|
||||
* @return string
|
||||
*/
|
||||
public function graphic2xml($oldxml)
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm2 = $request->get_parms('period', 'logsql');
|
||||
$dom = new DOMDocument();
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
|
||||
if ($dom->loadXML($oldxml)) {
|
||||
foreach (array(
|
||||
'str:period'
|
||||
, 'boo:logsql'
|
||||
) as $pname) {
|
||||
$ptype = substr($pname, 0, 3);
|
||||
$pname = substr($pname, 4);
|
||||
$pvalue = $parm2[$pname];
|
||||
if (($ns = $dom->getElementsByTagName($pname)->item(0))) {
|
||||
// field did exists, remove thevalue
|
||||
while (($n = $ns->firstChild))
|
||||
$ns->removeChild($n);
|
||||
} else {
|
||||
// field did not exists, create it
|
||||
$ns = $dom->documentElement->appendChild($dom->createElement($pname));
|
||||
}
|
||||
// set the value
|
||||
switch ($ptype) {
|
||||
case "str":
|
||||
case "pop":
|
||||
$ns->appendChild($dom->createTextNode($pvalue));
|
||||
break;
|
||||
case "boo":
|
||||
$ns->appendChild($dom->createTextNode($pvalue ? '1' : '0'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* PRINT head for the gui
|
||||
*/
|
||||
public function printInterfaceHEAD()
|
||||
{
|
||||
?>
|
||||
<style>
|
||||
OPTION.jsFilled
|
||||
{
|
||||
padding-left:10px;
|
||||
padding-right:20px;
|
||||
}
|
||||
#OUTOFDATETAB TD
|
||||
{
|
||||
text-align:center;
|
||||
}
|
||||
DIV.terminal
|
||||
{
|
||||
margin:5px;
|
||||
border:1px #000000 solid;
|
||||
font-family:monospace;
|
||||
font-size:13px;
|
||||
text-align:left;
|
||||
color:#00FF00;
|
||||
background-color:#182018
|
||||
}
|
||||
DIV.terminal DIV.title
|
||||
{
|
||||
color:#303830;
|
||||
background-color:#00C000;
|
||||
padding:2px;
|
||||
}
|
||||
DIV.terminal DIV.sql
|
||||
{
|
||||
padding:5px;
|
||||
}
|
||||
DIV.terminal DIV.sqltest
|
||||
{
|
||||
padding-left:45px;
|
||||
padding-right:25px;
|
||||
}
|
||||
SPAN.active
|
||||
{
|
||||
font-weight: bold;
|
||||
background-color: #000000;
|
||||
color:#00FF00;
|
||||
}
|
||||
SPAN.notactive
|
||||
{
|
||||
font-weight: bold;
|
||||
background-color: #000000;
|
||||
color:#FF0000;
|
||||
}
|
||||
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* PRINT js of the gui
|
||||
*/
|
||||
public function printInterfaceJS()
|
||||
{
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
function taskFillGraphic_<?php echo(get_class($this));?>(xml)
|
||||
{
|
||||
$("#sqlu").text("");
|
||||
$("#sqls").text("");
|
||||
if (xml) {
|
||||
xml2 = $.parseXML(xml);
|
||||
xml2 = $(xml2);
|
||||
|
||||
with(document.forms['graphicForm'])
|
||||
{
|
||||
period.value = xml2.find("period").text();
|
||||
logsql.checked = Number(xml2.find("logsql").text()) > 0;
|
||||
}
|
||||
|
||||
var data = {};
|
||||
data["ACT"] = "CALCTEST";
|
||||
data["taskid"]=<?php echo $this->getID(); ?>;
|
||||
data["cls"]="RecordMover";
|
||||
data["xml"] = xml;
|
||||
$.ajax({ url: "/admin/task-manager/task/<?php echo $this->getID(); ?>/facility/"
|
||||
, data: data
|
||||
, dataType:'json'
|
||||
, type:"POST"
|
||||
, async:true
|
||||
, success:function(data) {
|
||||
t = "";
|
||||
for (i in data.tasks) {
|
||||
t += "<div class=\"title\"> ";
|
||||
if(data.tasks[i].active)
|
||||
t += "<span class=\"active\"> X </span> ";
|
||||
else
|
||||
t += "<span class=\"notactive\"> X </span> ";
|
||||
if(data.tasks[i].name_htmlencoded)
|
||||
t += "<b>" + data.tasks[i].name_htmlencoded + "</b>";
|
||||
else
|
||||
t += "<b><i>sans nom</i></b>";
|
||||
|
||||
if(data.tasks[i].basename_htmlencoded)
|
||||
t += " (action=" + data.tasks[i].action + ' on ' + data.tasks[i].basename_htmlencoded + ')';
|
||||
else
|
||||
t += " (action=" + data.tasks[i].action + ' on <i>Unknown</i>)';
|
||||
t += "</div>";
|
||||
|
||||
if(data.tasks[i].err_htmlencoded) ;
|
||||
t += "<div class=\"err\">" + data.tasks[i].err_htmlencoded + "</div>";
|
||||
|
||||
t += "<div class=\"sql\">";
|
||||
|
||||
if(data.tasks[i].sql && data.tasks[i].sql.test.sql_htmlencoded)
|
||||
t += "<div class=\"sqltest\">" + data.tasks[i].sql.test.sql_htmlencoded + "</div>";
|
||||
t += "--> <span id=\"SQLRET"+i+"\"><i>wait...</i></span><br/>";
|
||||
|
||||
t += "</div>";
|
||||
}
|
||||
$("#sqla").html(t);
|
||||
|
||||
var data = {};
|
||||
data["ACT"] = "PLAYTEST";
|
||||
data["taskid"]=<?php echo $this->getID(); ?>;
|
||||
data["cls"]="RecordMover";
|
||||
data["xml"] = xml;
|
||||
$.ajax({ url: "/admin/task-manager/task/<?php echo $this->getID(); ?>/facility/"
|
||||
, data: data
|
||||
, dataType:'json'
|
||||
, type:"POST"
|
||||
, async:true
|
||||
, success:function(data) {
|
||||
for (i in data.tasks) {
|
||||
if (data.tasks[i].sql) {
|
||||
if (data.tasks[i].sql.test.err) {
|
||||
$("#SQLRET"+i).html("err: " + data.tasks[i].sql.test.err);
|
||||
} else {
|
||||
t = '';
|
||||
for(j in data.tasks[i].sql.test.result.rids)
|
||||
t += (t?', ':'') + data.tasks[i].sql.test.result.rids[j];
|
||||
if(data.tasks[i].sql.test.result.rids.length < data.tasks[i].sql.test.result.n)
|
||||
t += ', ...';
|
||||
$("#SQLRET"+i).html("n=" + data.tasks[i].sql.test.result.n + ", rids:(" + t + ")");
|
||||
}
|
||||
} else {
|
||||
$("#SQLRET"+i).html("");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(
|
||||
function(){
|
||||
(function( $ ){
|
||||
$.fn.serializeJSON=function() {
|
||||
var json = {};
|
||||
jQuery.map($(this).serializeArray(), function(n, i){
|
||||
json[n['name']] = n['value'];
|
||||
});
|
||||
|
||||
return json;
|
||||
};
|
||||
})( jQuery );
|
||||
|
||||
var limits = {
|
||||
'period':{'min':<?php echo self::MINPERIOD; ?>, 'max':<?php echo self::MAXPERIOD; ?>},
|
||||
'delay':{min:0}
|
||||
} ;
|
||||
$(".formElem").change(function(){
|
||||
fieldname = $(this).attr("name");
|
||||
switch ((this.nodeName+$(this).attr("type")).toLowerCase()) {
|
||||
case "inputtext":
|
||||
if (typeof(limits[fieldname])!='undefined') {
|
||||
var v = 0|this.value;
|
||||
if(v < limits[fieldname].min)
|
||||
v = limits[fieldname].min;
|
||||
else if(v > limits[fieldname].max)
|
||||
v = limits[fieldname].max;
|
||||
this.value = v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
setDirty();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* RETURN the html gui
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInterfaceHTML()
|
||||
{
|
||||
ob_start();
|
||||
?>
|
||||
<form class="form-horizontal" name="graphicForm" onsubmit="return(false);" method="post">
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::_common_:periodicite de la tache') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-small" type="text" name="period" value="" />
|
||||
<span class="help-inline"><?php echo _('task::_common_:secondes (unite temporelle)') ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input class="formElem" type="checkbox" name="logsql" /><?php echo _('Log changes') ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<center>
|
||||
<div class="terminal" id="sqla"></div>
|
||||
</center>
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* retrieveContent & processOneContent : work done by the task
|
||||
*/
|
||||
private $sxTaskSettings = null; // settings in simplexml
|
||||
|
||||
/**
|
||||
* return array of records to work on, from sql generated by 'from' clause
|
||||
*
|
||||
* @param appbox $appbox
|
||||
* @return array()
|
||||
*/
|
||||
|
||||
protected function retrieveContent(appbox $appbox)
|
||||
{
|
||||
$this->maxrecs = 1000;
|
||||
$this->sxTaskSettings = simplexml_load_string($this->getSettings());
|
||||
if (false === $this->sxTaskSettings || !$this->sxTaskSettings->tasks) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
|
||||
$logsql = (int) ($this->sxTaskSettings->logsql) > 0;
|
||||
|
||||
foreach ($this->sxTaskSettings->tasks->task as $sxtask) {
|
||||
|
||||
if (!$this->running) {
|
||||
break;
|
||||
}
|
||||
|
||||
$task = $this->calcSQL($sxtask);
|
||||
|
||||
if (!$task['active']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($logsql) {
|
||||
$this->log(sprintf("playing task '%s' on base '%s'"
|
||||
, $task['name']
|
||||
, $task['basename'] ? $task['basename'] : '<unknown>'), self::LOG_INFO);
|
||||
}
|
||||
|
||||
try {
|
||||
$connbas = connection::getPDOConnection($this->dependencyContainer, $task['sbas_id']);
|
||||
} catch (Exception $e) {
|
||||
$this->log(sprintf("can't connect sbas %s", $task['sbas_id']), self::LOG_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
$stmt = $connbas->prepare($task['sql']['real']['sql']);
|
||||
if ($stmt->execute(array())) {
|
||||
while ($this->running && ($row = $stmt->fetch(PDO::FETCH_ASSOC)) !== FALSE) {
|
||||
|
||||
$tmp = array('sbas_id' => $task['sbas_id'], 'record_id' => $row['record_id'], 'action' => $task['action']);
|
||||
|
||||
$rec = new record_adapter($this->dependencyContainer, $task['sbas_id'], $row['record_id']);
|
||||
switch ($task['action']) {
|
||||
|
||||
case 'UPDATE':
|
||||
|
||||
// change collection ?
|
||||
if (($x = (int) ($sxtask->to->coll['id'])) > 0) {
|
||||
$tmp['coll'] = $x;
|
||||
}
|
||||
|
||||
// change sb ?
|
||||
if (($x = $sxtask->to->status['mask'])) {
|
||||
$tmp['sb'] = $x;
|
||||
}
|
||||
$ret[] = $tmp;
|
||||
break;
|
||||
|
||||
case 'DELETE':
|
||||
$tmp['deletechildren'] = false;
|
||||
if ($sxtask['deletechildren'] && $rec->is_grouping()) {
|
||||
$tmp['deletechildren'] = true;
|
||||
}
|
||||
$ret[] = $tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* work on ONE record
|
||||
*
|
||||
* @param appbox $appbox
|
||||
* @param array $row
|
||||
* @return \task_period_RecordMover
|
||||
*/
|
||||
protected function processOneContent(appbox $appbox, $row)
|
||||
{
|
||||
$logsql = (int) ($this->sxTaskSettings->logsql) > 0;
|
||||
$databox = $this->dependencyContainer['phraseanet.appbox']->get_databox($row['sbas_id']);
|
||||
$rec = new record_adapter($this->dependencyContainer, $row['sbas_id'], $row['record_id']);
|
||||
switch ($row['action']) {
|
||||
|
||||
case 'UPDATE':
|
||||
|
||||
// change collection ?
|
||||
if (array_key_exists('coll', $row)) {
|
||||
$coll = collection::get_from_coll_id($this->dependencyContainer, $databox, $row['coll']);
|
||||
$rec->move_to_collection($coll, $this->dependencyContainer['phraseanet.appbox']);
|
||||
$this['phraseanet.SE']->updateRecord($rec);
|
||||
if ($logsql) {
|
||||
$this->log(sprintf("on sbas %s move rid %s to coll %s \n", $row['sbas_id'], $row['record_id'], $coll->get_coll_id()));
|
||||
}
|
||||
}
|
||||
|
||||
// change sb ?
|
||||
if (array_key_exists('sb', $row)) {
|
||||
$status = str_split($rec->get_status());
|
||||
foreach (str_split(strrev($row['sb'])) as $bit => $val) {
|
||||
if ($val == '0' || $val == '1') {
|
||||
$status[31 - $bit] = $val;
|
||||
}
|
||||
}
|
||||
$status = implode('', $status);
|
||||
$rec->set_binary_status($status);
|
||||
$this->dependencyContainer['phraseanet.SE']->updateRecord($rec);
|
||||
if ($logsql) {
|
||||
$this->log(sprintf("on sbas %s set rid %s status to %s \n", $row['sbas_id'], $row['record_id'], $status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DELETE':
|
||||
if ($row['deletechildren'] && $rec->is_grouping()) {
|
||||
foreach ($rec->get_children() as $child) {
|
||||
$child->delete();
|
||||
$this->dependencyContainer['phraseanet.SE']->removeRecord($child);
|
||||
if ($logsql) {
|
||||
$this->log(sprintf("on sbas %s delete (grp child) rid %s \n", $row['sbas_id'], $child->get_record_id()));
|
||||
}
|
||||
}
|
||||
}
|
||||
$rec->delete();
|
||||
$this->dependencyContainer['phraseanet.SE']->removeRecord($rec);
|
||||
if ($logsql) {
|
||||
$this->log(sprintf("on sbas %s delete rid %s \n", $row['sbas_id'], $rec->get_record_id()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* all work done on processOneContent, so nothing to do here
|
||||
*
|
||||
* @param appbox $appbox
|
||||
* @param array $row
|
||||
* @return \task_period_RecordMover
|
||||
*/
|
||||
protected function postProcessOneContent(appbox $appbox, $row)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* compute sql for a task (<task> entry in settings)
|
||||
*
|
||||
* @param simplexml $sxtask
|
||||
* @param boolean $playTest
|
||||
* @return array
|
||||
*/
|
||||
private function calcSQL($sxtask, $playTest = false)
|
||||
{
|
||||
$sbas_id = (int) ($sxtask['sbas_id']);
|
||||
|
||||
$ret = array(
|
||||
'name' => $sxtask['name'] ? (string) $sxtask['name'] : 'sans nom',
|
||||
'name_htmlencoded' => \p4string::MakeString(($sxtask['name'] ? $sxtask['name'] : 'sans nom'), 'html'),
|
||||
'active' => trim($sxtask['active']) === '1',
|
||||
'sbas_id' => $sbas_id,
|
||||
'basename' => '',
|
||||
'basename_htmlencoded' => '',
|
||||
'action' => strtoupper($sxtask['action']),
|
||||
'sql' => NULL,
|
||||
'err' => '',
|
||||
'err_htmlencoded' => '',
|
||||
);
|
||||
|
||||
try {
|
||||
$dbox = $this->dependencyContainer['phraseanet.appbox']->get_databox($sbas_id);
|
||||
|
||||
$ret['basename'] = $dbox->get_label($this->dependencyContainer['locale.I18n']);
|
||||
$ret['basename_htmlencoded'] = htmlentities($ret['basename']);
|
||||
switch ($ret['action']) {
|
||||
case 'UPDATE':
|
||||
$ret['sql'] = $this->calcUPDATE($sbas_id, $sxtask, $playTest);
|
||||
break;
|
||||
case 'DELETE':
|
||||
$ret['sql'] = $this->calcDELETE($sbas_id, $sxtask, $playTest);
|
||||
$ret['deletechildren'] = (int) ($sxtask['deletechildren']);
|
||||
break;
|
||||
default:
|
||||
$ret['err'] = "bad action '" . $ret['action'] . "'";
|
||||
$ret['err_htmlencoded'] = htmlentities($ret['err']);
|
||||
break;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$ret['err'] = "bad sbas '" . $sbas_id . "'";
|
||||
$ret['err_htmlencoded'] = htmlentities($ret['err']);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* compute entry for a UPDATE query
|
||||
*
|
||||
* @param integer $sbas_id
|
||||
* @param simplexml $sxtask
|
||||
* @param boolean $playTest
|
||||
* @return array
|
||||
*/
|
||||
private function calcUPDATE($sbas_id, &$sxtask, $playTest)
|
||||
{
|
||||
$tws = array(); // NEGATION of updates, used to build the 'test' sql
|
||||
//
|
||||
// set coll_id ?
|
||||
if (($x = (int) ($sxtask->to->coll['id'])) > 0) {
|
||||
$tws[] = 'coll_id!=' . $x;
|
||||
}
|
||||
|
||||
// set status ?
|
||||
$x = $sxtask->to->status['mask'];
|
||||
$mx = str_replace(' ', '0', ltrim(str_replace(array('0', 'x'), array(' ', ' '), $x)));
|
||||
$ma = str_replace(' ', '0', ltrim(str_replace(array('x', '0'), array(' ', '1'), $x)));
|
||||
if ($mx && $ma)
|
||||
$tws[] = '((status ^ 0b' . $mx . ') & 0b' . $ma . ')!=0';
|
||||
elseif ($mx)
|
||||
$tws[] = '(status ^ 0b' . $mx . ')!=0';
|
||||
elseif ($ma)
|
||||
$tws[] = '(status & 0b' . $ma . ')!=0';
|
||||
|
||||
// compute the 'where' clause
|
||||
list($tw, $join) = $this->calcWhere($sbas_id, $sxtask);
|
||||
|
||||
// ... complete the where to buid the TEST
|
||||
if (count($tws) == 1)
|
||||
$tw[] = $tws[0];
|
||||
elseif (count($tws) > 1)
|
||||
$tw[] = '(' . implode(') OR (', $tws) . ')';
|
||||
if (count($tw) == 1)
|
||||
$where = $tw[0];
|
||||
if (count($tw) > 1)
|
||||
$where = '(' . implode(') AND (', $tw) . ')';
|
||||
|
||||
// build the TEST sql (select)
|
||||
$sql_test = 'SELECT record_id FROM record' . $join;
|
||||
if (count($tw) > 0)
|
||||
$sql_test .= ' WHERE ' . ((count($tw) == 1) ? $tw[0] : '(' . implode(') AND (', $tw) . ')');
|
||||
|
||||
// build the real sql (select)
|
||||
$sql = 'SELECT record_id FROM record' . $join;
|
||||
if (count($tw) > 0)
|
||||
$sql .= ' WHERE ' . ((count($tw) == 1) ? $tw[0] : '(' . implode(') AND (', $tw) . ')');
|
||||
|
||||
$ret = array(
|
||||
'real' => array(
|
||||
'sql' => $sql,
|
||||
'sql_htmlencoded' => htmlentities($sql),
|
||||
),
|
||||
'test' => array(
|
||||
'sql' => $sql_test,
|
||||
'sql_htmlencoded' => htmlentities($sql_test),
|
||||
'result' => NULL,
|
||||
'err' => NULL
|
||||
)
|
||||
);
|
||||
|
||||
if ($playTest) {
|
||||
$ret['test']['result'] = $this->playTest($sbas_id, $sql_test);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* compute entry for a DELETE task
|
||||
*
|
||||
* @param integer $sbas_id
|
||||
* @param simplexml $sxtask
|
||||
* @param boolean $playTest
|
||||
* @return array
|
||||
*/
|
||||
private function calcDELETE($sbas_id, &$sxtask, $playTest)
|
||||
{
|
||||
// compute the 'where' clause
|
||||
list($tw, $join) = $this->calcWhere($sbas_id, $sxtask);
|
||||
|
||||
// build the TEST sql (select)
|
||||
$sql_test = 'SELECT SQL_CALC_FOUND_ROWS record_id FROM record' . $join;
|
||||
if (count($tw) > 0)
|
||||
$sql_test .= ' WHERE ' . ((count($tw) == 1) ? $tw[0] : '(' . implode(') AND (', $tw) . ')');
|
||||
$sql_test .= ' LIMIT 10';
|
||||
|
||||
// build the real sql (select)
|
||||
$sql = 'SELECT record_id FROM record' . $join;
|
||||
if (count($tw) > 0)
|
||||
$sql .= ' WHERE ' . ((count($tw) == 1) ? $tw[0] : '(' . implode(') AND (', $tw) . ')');
|
||||
|
||||
$ret = array(
|
||||
'real' => array(
|
||||
'sql' => $sql,
|
||||
'sql_htmlencoded' => htmlentities($sql),
|
||||
),
|
||||
'test' => array(
|
||||
'sql' => $sql_test,
|
||||
'sql_htmlencoded' => htmlentities($sql_test),
|
||||
'result' => NULL,
|
||||
'err' => NULL
|
||||
)
|
||||
);
|
||||
|
||||
if ($playTest) {
|
||||
$ret['test']['result'] = $this->playTest($sbas_id, $sql_test);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* compute the 'where' clause
|
||||
* returns an array of clauses to be joined by 'and'
|
||||
* and a 'join' to needed tables
|
||||
*
|
||||
* @param integer $sbas_id
|
||||
* @param simplecms $sxtask
|
||||
* @return array
|
||||
*/
|
||||
private function calcWhere($sbas_id, &$sxtask)
|
||||
{
|
||||
$connbas = connection::getPDOConnection($this->dependencyContainer, $sbas_id);
|
||||
|
||||
$tw = array();
|
||||
$join = '';
|
||||
|
||||
$ijoin = 0;
|
||||
|
||||
// criteria <type type="XXX" />
|
||||
if (($x = $sxtask->from->type['type']) !== NULL) {
|
||||
switch (strtoupper($x)) {
|
||||
case 'RECORD':
|
||||
$tw[] = 'parent_record_id!=record_id';
|
||||
break;
|
||||
case 'STORY':
|
||||
$tw[] = 'parent_record_id=record_id';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// criteria <text field="XXX" compare="OP" value="ZZZ" />
|
||||
foreach ($sxtask->from->text as $x) {
|
||||
$ijoin++;
|
||||
$comp = strtoupper($x['compare']);
|
||||
if (in_array($comp, array('<', '>', '<=', '>=', '=', '!='))) {
|
||||
$s = 'p' . $ijoin . '.name=\'' . $x['field'] . '\' AND p' . $ijoin . '.value' . $comp;
|
||||
$s .= '' . $connbas->quote($x['value']) . '';
|
||||
|
||||
$tw[] = $s;
|
||||
$join .= ' INNER JOIN prop AS p' . $ijoin . ' USING(record_id)';
|
||||
} else {
|
||||
// bad comparison operator
|
||||
}
|
||||
}
|
||||
|
||||
// criteria <date direction ="XXX" field="YYY" delta="Z" />
|
||||
foreach ($sxtask->from->date as $x) {
|
||||
$ijoin++;
|
||||
$s = 'p' . $ijoin . '.name=\'' . $x['field'] . '\' AND NOW()';
|
||||
$s .= strtoupper($x['direction']) == 'BEFORE' ? '<' : '>=';
|
||||
$delta = (int) ($x['delta']);
|
||||
if ($delta > 0)
|
||||
$s .= '(p' . $ijoin . '.value+INTERVAL ' . $delta . ' DAY)';
|
||||
elseif ($delta < 0)
|
||||
$s .= '(p' . $ijoin . '.value-INTERVAL ' . -$delta . ' DAY)';
|
||||
else
|
||||
$s .= 'p' . $ijoin . '.value';
|
||||
|
||||
$tw[] = $s;
|
||||
$join .= ' INNER JOIN prop AS p' . $ijoin . ' USING(record_id)';
|
||||
}
|
||||
|
||||
// criteria <coll compare="OP" id="X,Y,Z" />
|
||||
if (($x = $sxtask->from->coll) !== NULL) {
|
||||
$tcoll = explode(',', $x['id']);
|
||||
foreach ($tcoll as $i => $c)
|
||||
$tcoll[$i] = (int) $c;
|
||||
if ($x['compare'] == '=') {
|
||||
if (count($tcoll) == 1) {
|
||||
$tw[] = 'coll_id = ' . $tcoll[0];
|
||||
} else {
|
||||
$tw[] = 'coll_id IN(' . implode(',', $tcoll) . ')';
|
||||
}
|
||||
} elseif ($x['compare'] == '!=') {
|
||||
if (count($tcoll) == 1) {
|
||||
$tw[] = 'coll_id != ' . $tcoll[0];
|
||||
} else {
|
||||
$tw[] = 'coll_id NOT IN(' . implode(',', $tcoll) . ')';
|
||||
}
|
||||
} else {
|
||||
// bad operator
|
||||
}
|
||||
}
|
||||
|
||||
// criteria <status mask="XXXXX" />
|
||||
$x = $sxtask->from->status['mask'];
|
||||
$mx = str_replace(' ', '0', ltrim(str_replace(array('0', 'x'), array(' ', ' '), $x)));
|
||||
$ma = str_replace(' ', '0', ltrim(str_replace(array('x', '0'), array(' ', '1'), $x)));
|
||||
if ($mx && $ma) {
|
||||
$tw[] = '((status^0b' . $mx . ')&0b' . $ma . ')=0';
|
||||
} elseif ($mx) {
|
||||
$tw[] = '(status^0b' . $mx . ')=0';
|
||||
} elseif ($ma) {
|
||||
$tw[] = '(status&0b' . $ma . ")=0";
|
||||
}
|
||||
|
||||
if (count($tw) == 1) {
|
||||
$where = $tw[0];
|
||||
}
|
||||
if (count($tw) > 1) {
|
||||
$where = '(' . implode(') AND (', $tw) . ')';
|
||||
}
|
||||
|
||||
return array($tw, $join);
|
||||
}
|
||||
|
||||
/**
|
||||
* play a 'test' sql on sbas, return the number of records and the 10 first rids
|
||||
*
|
||||
* @param integer $sbas_id
|
||||
* @param string $sql
|
||||
* @return array
|
||||
*/
|
||||
private function playTest($sbas_id, $sql)
|
||||
{
|
||||
$connbas = connection::getPDOConnection($this->dependencyContainer, $sbas_id);
|
||||
$result = array('rids' => array(), 'err' => '', 'n' => null);
|
||||
|
||||
$result['n'] = $connbas->query('SELECT COUNT(*) AS n FROM (' . $sql . ') AS x')->fetchColumn();
|
||||
|
||||
$stmt = $connbas->prepare('SELECT record_id FROM (' . $sql . ') AS x LIMIT 10');
|
||||
if ($stmt->execute(array())) {
|
||||
while (($row = $stmt->fetch(PDO::FETCH_ASSOC))) {
|
||||
$result['rids'][] = $row['record_id'];
|
||||
}
|
||||
$stmt->closeCursor();
|
||||
} else {
|
||||
$result['err'] = $connbas->last_error();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* facility called by xhttp/jquery from interface for ex. when switching interface from gui<->xml
|
||||
*/
|
||||
public function facility()
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm2 = $request->get_parms(
|
||||
'ACT', 'xml'
|
||||
);
|
||||
|
||||
$ret = array('tasks' => array());
|
||||
switch ($parm2['ACT']) {
|
||||
case 'CALCTEST':
|
||||
$sxml = simplexml_load_string($parm2['xml']);
|
||||
if (isset($sxml->tasks->task)) {
|
||||
foreach ($sxml->tasks->task as $sxtask) {
|
||||
$ret['tasks'][] = $this->calcSQL($sxtask, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'PLAYTEST':
|
||||
$sxml = simplexml_load_string($parm2['xml']);
|
||||
if (isset($sxml->tasks->task)) {
|
||||
foreach ($sxml->tasks->task as $sxtask) {
|
||||
$ret['tasks'][] = $this->calcSQL($sxtask, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'CALCSQL':
|
||||
$xml = $this->graphic2xml('<?xml version="1.0" encoding="UTF-8"?><tasksettings/>');
|
||||
$sxml = simplexml_load_string($xml);
|
||||
if (isset($sxml->tasks->task)) {
|
||||
foreach ($sxml->tasks->task as $sxtask) {
|
||||
$ret['tasks'][] = $this->calcSQL($sxtask, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return json_encode($ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*/
|
||||
public static function getDefaultSettings(Configuration $config, array $params = array())
|
||||
{
|
||||
$period = isset($params['period']) ? $params['period'] : self::MINPERIOD;
|
||||
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||
<tasksettings>
|
||||
<period>". min(max($period, self::MINPERIOD), self::MAXPERIOD) ."</period>
|
||||
<logsql>0</logsql>
|
||||
<!--
|
||||
<tasks>
|
||||
//Maintain offline (sb4 = 1) all docs under copyright
|
||||
<task active=\"1\" name=\"confidentiel\" action=\"update\" sbas_id=\"1\">
|
||||
<from>
|
||||
<date direction=\"before\" field=\"FIN_COPYRIGHT\"/>
|
||||
</from>
|
||||
<to>
|
||||
<status mask=\"x1xxxx\"/>
|
||||
</to>
|
||||
</task>
|
||||
//Put online (sb4 = 0) all docs from 'public' collection and between the copyright date and the date of filing
|
||||
<task active=\"1\" name=\"visible\" action=\"update\" sbas_id=\"1\">
|
||||
<from>
|
||||
<coll compare=\"=\" id=\"5\"/>
|
||||
<date direction=\"after\" field=\"FIN_COPYRIGHT\"/>
|
||||
<date direction=\"before\" field=\"ARCHIVAGE\"/>
|
||||
</from>
|
||||
<to>
|
||||
<status mask=\"x0xxxx\"/>
|
||||
</to>
|
||||
</task>
|
||||
// Warn 10 days before archiving (raise sb5)
|
||||
<task active=\"1\" name=\"bientôt la fin\" action=\"update\" sbas_id=\"1\">
|
||||
<from>
|
||||
<coll compare=\"=\" id=\"5\"/>
|
||||
<date direction=\"after\" field=\"ARCHIVAGE\" delta=\"-10\"/>
|
||||
</from>
|
||||
<to>
|
||||
<status mask=\"1xxxxx\"/>
|
||||
</to>
|
||||
</task>
|
||||
//Move to 'archive' collection
|
||||
<task active=\"1\" name=\"archivage\" action=\"update\" sbas_id=\"1\">
|
||||
<from>
|
||||
<coll compare=\"=\" id=\"5\"/>
|
||||
<date direction=\"after\" field=\"ARCHIVAGE\" />
|
||||
</from>
|
||||
<to>
|
||||
<status mask=\"00xxxx\"/> on nettoie les status pour la forme
|
||||
<coll id=\"666\" />
|
||||
</to>
|
||||
</task>
|
||||
//Purge the archived documents from one year that are in the 'archive' collection
|
||||
<task active=\"1\" name=\"archivage\" action=\"delete\" sbas_id=\"1\">
|
||||
<from>
|
||||
<coll compare=\"=\" id=\"666\"/>
|
||||
<date direction=\"after\" field=\"ARCHIVAGE\" delta=\"+365\" />
|
||||
</from>
|
||||
</task>
|
||||
</tasks>
|
||||
-->
|
||||
</tasksettings>";
|
||||
}
|
||||
}
|
@@ -1,178 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
class task_period_apibridge extends task_appboxAbstract
|
||||
{
|
||||
|
||||
/**
|
||||
* Return the name of the task
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return 'API bridge uploader';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get help
|
||||
* @return string
|
||||
*/
|
||||
public static function help()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param appbox $appbox
|
||||
* @return Array
|
||||
*/
|
||||
protected function retrieveContent(appbox $appbox)
|
||||
{
|
||||
$status = array(Bridge_Element::STATUS_PENDING, Bridge_Element::STATUS_PROCESSING, Bridge_Element::STATUS_PROCESSING_SERVER);
|
||||
|
||||
$params = array();
|
||||
$n = 1;
|
||||
|
||||
foreach ($status as $stat) {
|
||||
$params[':status' . $n] = $stat;
|
||||
$n ++;
|
||||
}
|
||||
|
||||
$sql = 'SELECT id, account_id FROM bridge_elements'
|
||||
. ' WHERE (status = ' . implode(' OR status = ', array_keys($params)) . ')';
|
||||
|
||||
$stmt = $appbox->get_connection()->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param appbox $appbox
|
||||
* @param array $row
|
||||
* @return task_period_apibridge
|
||||
*/
|
||||
protected function processOneContent(appbox $appbox, $row)
|
||||
{
|
||||
try {
|
||||
$account = Bridge_Account::load_account($this->dependencyContainer, $row['account_id']);
|
||||
$element = new Bridge_Element($this->dependencyContainer, $account, $row['id']);
|
||||
|
||||
$this->log("process " . $element->get_id() . " with status " . $element->get_status());
|
||||
|
||||
if ($element->get_status() == Bridge_Element::STATUS_PENDING) {
|
||||
$this->upload_element($element);
|
||||
} else {
|
||||
$this->update_element($element);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$sql = 'UPDATE bridge_elements SET status = :status WHERE id = :id';
|
||||
|
||||
$params = array(
|
||||
':status' => Bridge_Element::STATUS_ERROR
|
||||
, ':id' => $row['id']
|
||||
);
|
||||
|
||||
$stmt = $appbox->get_connection()->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param appbox $appbox
|
||||
* @param array $row
|
||||
* @return task_period_apibridge
|
||||
*/
|
||||
protected function postProcessOneContent(appbox $appbox, $row)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Bridge_Element $element
|
||||
* @return task_period_apibridge
|
||||
*/
|
||||
private function upload_element(Bridge_Element $element)
|
||||
{
|
||||
$account = $element->get_account();
|
||||
$element->set_status(Bridge_Element::STATUS_PROCESSING);
|
||||
$dist_id = null;
|
||||
try {
|
||||
$dist_id = $account->get_api()->upload($element->get_record(), $element->get_datas());
|
||||
$element->set_uploaded_on(new DateTime());
|
||||
} catch (Exception $e) {
|
||||
$this->log('Error while uploading : ' . $e->getMessage());
|
||||
$element->set_status(Bridge_Element::STATUS_ERROR);
|
||||
}
|
||||
$element->set_dist_id($dist_id);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Bridge_Element $element
|
||||
* @return task_period_apibridge
|
||||
*/
|
||||
protected function update_element(Bridge_Element $element)
|
||||
{
|
||||
$account = $element->get_account();
|
||||
$connector_status = $account->get_api()->get_element_status($element);
|
||||
|
||||
$status = $element->get_account()->get_api()->map_connector_to_element_status($connector_status);
|
||||
$error_message = $element->get_account()->get_api()->get_error_message_from_status($connector_status);
|
||||
|
||||
$previous_status = $element->get_status();
|
||||
|
||||
if ($status) {
|
||||
$element->set_status($status);
|
||||
$this->log('updating status for : ' . $element->get_id() . " to " . $status);
|
||||
}
|
||||
$element->set_connector_status($connector_status);
|
||||
|
||||
if ($status === $previous_status) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($status) {
|
||||
case Bridge_Element::STATUS_ERROR:
|
||||
|
||||
$params = array(
|
||||
'usr_id' => $account->get_user()->get_id()
|
||||
, 'reason' => $error_message
|
||||
, 'account_id' => $account->get_id()
|
||||
, 'sbas_id' => $element->get_record()->get_sbas_id()
|
||||
, 'record_id' => $element->get_record()->get_record_id()
|
||||
);
|
||||
$this->dependencyContainer['events-manager']->trigger('__BRIDGE_UPLOAD_FAIL__', $params);
|
||||
|
||||
break;
|
||||
default:
|
||||
case Bridge_Element::STATUS_DONE:
|
||||
case Bridge_Element::STATUS_PENDING:
|
||||
case Bridge_Element::STATUS_PROCESSING_SERVER:
|
||||
case Bridge_Element::STATUS_PROCESSING:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,656 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Core\Configuration\Configuration;
|
||||
use Symfony\Component\Process\ExecutableFinder;
|
||||
|
||||
class task_period_cindexer extends task_abstract
|
||||
{
|
||||
// how to execute indexer (choose in 'run2' method)
|
||||
private $method;
|
||||
|
||||
const METHOD_FORK = 'METHOD_FORK';
|
||||
const METHOD_EXEC = 'METHOD_EXEC';
|
||||
const METHOD_PROC_OPEN = 'METHOD_PROC_OPEN';
|
||||
const ERR_EXECUTABLE_NOT_FOUND = 2; // aka ENOENT (No such file or directory)
|
||||
const ERR_CRASHED = 14; // aka EFAULT (Bad address)
|
||||
const ERR_CANT_FORK = 3; // aka ESRCH (No such process)
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $host;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $port;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $base;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $socket;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $charset;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $debugmask;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $stem;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $sortempty;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $nolog;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $winsvc_run;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return(_("Indexation task"));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function help()
|
||||
{
|
||||
return(_("This task is used to index records for Phrasea engine."));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $oldxml
|
||||
* @return string
|
||||
*/
|
||||
public function graphic2xml($oldxml)
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm2 = $request->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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return($dom->saveXML());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function printInterfaceJS()
|
||||
{
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
|
||||
function taskFillGraphic_<?php echo(get_class($this));?>(xml)
|
||||
{
|
||||
if (xml) {
|
||||
xml = $.parseXML(xml);
|
||||
xml = $(xml);
|
||||
|
||||
var isyes = function(v) {
|
||||
v = v.toUpperCase().trim();
|
||||
|
||||
return v=='O' || v=='Y' || v=='OUI' || v=='YES' || v=='1';
|
||||
}
|
||||
|
||||
with(document.forms['graphicForm'])
|
||||
{
|
||||
host.value = xml.find("host").text();
|
||||
port.value = xml.find("port").text();
|
||||
base.value = xml.find("base").text();
|
||||
user.value = xml.find("user").text();
|
||||
socket.value = xml.find("socket").text();
|
||||
password.value = xml.find("password").text();
|
||||
clng.value = xml.find("clng").text();
|
||||
nolog.checked = isyes(xml.find("nolog").text());
|
||||
winsvc_run.checked = isyes(xml.find("winsvc_run").text());
|
||||
charset.value = xml.find("charset").text();
|
||||
stem.value = xml.find("stem").text();
|
||||
sortempty.value = xml.find("sortempty").text();
|
||||
debugmask.value = 0|xml.find("debugmask").text();
|
||||
}
|
||||
}
|
||||
|
||||
var cmd = '';
|
||||
with(document.forms['graphicForm'])
|
||||
{
|
||||
cmd += "<?php echo $this->getIndexer() ?>";
|
||||
if(host.value)
|
||||
cmd += " -h=" + host.value;
|
||||
if(port.value)
|
||||
cmd += " -P=" + port.value;
|
||||
if(base.value)
|
||||
cmd += " -b=" + base.value;
|
||||
if(user.value)
|
||||
cmd += " -u=" + user.value;
|
||||
if(password.value)
|
||||
cmd += " -p=xxxxxx"; // + password.value;
|
||||
if(socket.value)
|
||||
cmd += " --socket=" + socket.value;
|
||||
if(charset.value)
|
||||
cmd += " --default-character-set=" + charset.value;
|
||||
|
||||
cmd += " -o";
|
||||
|
||||
if(nolog.checked)
|
||||
cmd += " -n";
|
||||
if(clng.value)
|
||||
cmd += " -c=" + clng.value;
|
||||
if(stem.value)
|
||||
cmd += " --stem=" + stem.value;
|
||||
if(sortempty.value)
|
||||
cmd += " --sort-empty=" + sortempty.value;
|
||||
if(debugmask.value)
|
||||
cmd += " -d=" + debugmask.value;
|
||||
if(winsvc_run.checked)
|
||||
cmd += " --run";
|
||||
}
|
||||
$('#cmd').html(cmd);
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#graphicForm *").change(function(){
|
||||
taskFillGraphic_<?php echo(get_class($this));?>(null);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<?php
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return return
|
||||
*/
|
||||
public function getInterfaceHTML()
|
||||
{
|
||||
ob_start();
|
||||
?>
|
||||
<form id="graphicForm" name="graphicForm" class="form-horizontal" onsubmit="return(false);" method="post">
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('MySQL Host') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="host" value="">
|
||||
</div>
|
||||
<label class="control-label"><?php echo _('MySQL Port') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="port" value="">
|
||||
</div>
|
||||
<label class="control-label"><?php echo _('MySQL Database') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="base" value="">
|
||||
</div>
|
||||
<label class="control-label"><?php echo _('MySQL Login') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="user" value="">
|
||||
</div>
|
||||
<label class="control-label"><?php echo _('MySQL password') ?></label>
|
||||
<div class="controls">
|
||||
<input type="password" name="password" value="">
|
||||
</div>
|
||||
<label class="control-label"><?php echo _('MySQL connection charset') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="charset" class="input-small" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Socket port') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="socket" class="input-small" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Debug binary mask') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="debugmask" class="input-small" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Default language for thesaurus candidates') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="clng" class="input-small" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Enable stemming languages') ?></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="stem" class="input-small" value="">
|
||||
<span class="help-inline"><?php echo _('example : fr,en') ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Sort records with an empty field') ?></label>
|
||||
<div class="controls">
|
||||
<select name="sortempty">
|
||||
<option value=""><?php echo _('Hide records') ?></option>
|
||||
<option value="A"><?php echo _('At the beginning') ?></option>
|
||||
<option value="Z"><?php echo _('At the end') ?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="nolog">
|
||||
<?php echo _('Do not log, output to console') ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="winsvc_run">
|
||||
<?php echo _('Run as application, not as service') ?>
|
||||
<span class="help-inline">(<?php echo _('Windows specific') ?>)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<center>
|
||||
<div style="margin:10px; padding:5px; border:1px #000000 solid; font-family:monospace; font-size:14px; text-align:left; color:#00e000; background-color:#404040" id="cmd">cmd</div>
|
||||
</center>
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param SimpleXMLElement $sx_task_settings
|
||||
* @return task_cindexer
|
||||
*/
|
||||
protected function loadSettings(SimpleXMLElement $sx_task_settings)
|
||||
{
|
||||
$this->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();
|
||||
|
||||
$this->method = self::METHOD_PROC_OPEN;
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
$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));
|
||||
|
||||
$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 ++) {
|
||||
$this->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 ++) {
|
||||
$this->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);
|
||||
$this->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;
|
||||
$this->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));
|
||||
}
|
||||
$this->sleep(2);
|
||||
}
|
||||
} // while running
|
||||
}
|
||||
}
|
||||
|
||||
private function run_with_exec($cmd, $args, $args_nopwd)
|
||||
{
|
||||
pcntl_exec($cmd, $args);
|
||||
$this->sleep(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*/
|
||||
public static function getDefaultSettings(Configuration $config, array $params = array())
|
||||
{
|
||||
$database = $config['main']['database'];
|
||||
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<tasksettings>\n"
|
||||
."<host>" . $database['host'] . "</host><port>"
|
||||
. $database['port'] . "</port><base>"
|
||||
. $database['dbname'] . "</base><user>"
|
||||
. $database['user'] . "</user><password>"
|
||||
. $database['password'] . "</password><socket>25200</socket>"
|
||||
. "<use_sbas>1</use_sbas><nolog>0</nolog><clng></clng>"
|
||||
. "<winsvc_run>0</winsvc_run><charset>utf8</charset></tasksettings>";
|
||||
}
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Core\Configuration\Configuration;
|
||||
|
||||
class task_period_emptyColl extends task_appboxAbstract
|
||||
{
|
||||
protected $base_id;
|
||||
protected $suicidable = true;
|
||||
protected $total_records = 0;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return(_("Vidage de collection"));
|
||||
}
|
||||
|
||||
public static function interfaceAvailable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function help()
|
||||
{
|
||||
return("Vide une collection");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
public static function getDefaultSettings(Configuration $config, array $params = array())
|
||||
{
|
||||
return '<?xml version="1.0" encoding="UTF-8"?><tasksettings><bas_id>' . (isset($params['bas_id']) ? $params['bas_id'] : '' ) . '</bas_id></tasksettings>';
|
||||
}
|
||||
|
||||
protected function loadSettings(SimpleXMLElement $sx_task_settings)
|
||||
{
|
||||
$this->base_id = (int) $sx_task_settings->base_id;
|
||||
parent::loadSettings($sx_task_settings);
|
||||
}
|
||||
|
||||
protected function retrieveContent(appbox $appbox)
|
||||
{
|
||||
if (! $this->base_id) {
|
||||
$this->setState(self::STATE_STOPPED);
|
||||
|
||||
return array();
|
||||
}
|
||||
$collection = collection::get_from_base_id($this->dependencyContainer, $this->base_id);
|
||||
$this->total_records = $collection->get_record_amount();
|
||||
$collection->empty_collection(200);
|
||||
$this->records_done += $this->total_records;
|
||||
$this->setProgress($this->records_done, $this->total_records);
|
||||
|
||||
if ($this->total_records == 0) {
|
||||
$this->setState(self::STATE_STOPPED);
|
||||
$this->log('Job finished');
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function processOneContent(appbox $appbox, $row)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function postProcessOneContent(appbox $appbox, $row)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -1,618 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Core\Configuration\Configuration;
|
||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailSuccessFTPSender;
|
||||
use Alchemy\Phrasea\Notification\Receiver;
|
||||
use Alchemy\Phrasea\Model\Entities\FtpExport;
|
||||
use Alchemy\Phrasea\Model\Entities\FtpExportElement;
|
||||
|
||||
class task_period_ftp extends task_appboxAbstract
|
||||
{
|
||||
protected $proxy;
|
||||
protected $proxyport;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return(_("task::ftp:FTP Push"));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function help()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $oldxml
|
||||
* @return string
|
||||
*/
|
||||
public function graphic2xml($oldxml)
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm2 = $request->get_parms('proxy', 'proxyport', 'period', 'syslog');
|
||||
$dom = new DOMDocument();
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
if ((@$dom->loadXML($oldxml)) != FALSE) {
|
||||
foreach (array('str:proxy', 'str:proxyport', 'str:period', 'pop:syslog') 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":
|
||||
case "pop":
|
||||
$ns->appendChild($dom->createTextNode($pvalue));
|
||||
break;
|
||||
case "boo":
|
||||
$ns->appendChild($dom->createTextNode($pvalue ? '1' : '0'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return($dom->saveXML());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function printInterfaceJS()
|
||||
{
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
function taskFillGraphic_<?php echo(get_class($this));?>(xml)
|
||||
{
|
||||
if (xml) {
|
||||
xml = $.parseXML(xml);
|
||||
xml = $(xml);
|
||||
|
||||
with(document.forms['graphicForm'])
|
||||
{
|
||||
proxy.value = xml.find("proxy").text();
|
||||
proxyport.value = xml.find("proxyport").text();
|
||||
period.value = xml.find("period").text();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
var limits = {
|
||||
'period' :{'min':<?php echo self::MINPERIOD; ?>, 'max':<?php echo self::MAXPERIOD; ?>}
|
||||
} ;
|
||||
$(".formElem").change(function(){
|
||||
fieldname = $(this).attr("name");
|
||||
switch ((this.nodeName+$(this).attr("type")).toLowerCase()) {
|
||||
case "inputtext":
|
||||
if (typeof(limits[fieldname])!='undefined') {
|
||||
var v = 0|this.value;
|
||||
if(v < limits[fieldname].min)
|
||||
v = limits[fieldname].min;
|
||||
else if(v > limits[fieldname].max)
|
||||
v = limits[fieldname].max;
|
||||
this.value = v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
setDirty();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInterfaceHTML()
|
||||
{
|
||||
ob_start();
|
||||
?>
|
||||
<form id="graphicForm" name="graphicForm" class="form-horizontal" onsubmit="return(false);" method="post">
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::ftp:proxy') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="proxy" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::ftp:proxy port') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="proxyport" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::_common_:periodicite de la tache') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-small" type="text" name="period" />
|
||||
<span class="help-inline"><?php echo _('task::_common_:secondes (unite temporelle)') ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public function saveChanges(connection_pdo $conn, $taskid, &$taskrow)
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm = $request->get_parms(
|
||||
'xml'
|
||||
, 'name'
|
||||
, 'active'
|
||||
, 'proxy'
|
||||
, 'proxyport'
|
||||
, 'period'
|
||||
);
|
||||
|
||||
if ($parm["xml"] === null) {
|
||||
// pas de xml 'raw' : on accepte les champs 'graphic view'
|
||||
$domTaskSettings = new DOMDocument();
|
||||
if ((@$domTaskSettings->loadXML($taskrow["settings"])) != FALSE) {
|
||||
$xmlchanged = false;
|
||||
foreach (array(
|
||||
'proxy'
|
||||
, 'proxyport'
|
||||
, 'period'
|
||||
) as $f) {
|
||||
if ($parm[$f] !== NULL) {
|
||||
if (($ns = $domTaskSettings->getElementsByTagName($f)->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 = $domTaskSettings->documentElement->appendChild($domTaskSettings->createElement($f));
|
||||
}
|
||||
// on fixe sa valeur
|
||||
$ns->appendChild($domTaskSettings->createTextNode($parm[$f]));
|
||||
$xmlchanged = true;
|
||||
}
|
||||
}
|
||||
if ($xmlchanged) {
|
||||
$parm["xml"] = $domTaskSettings->saveXML();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// si on doit changer le xml, on verifie qu'il est valide
|
||||
$domdoc = new DOMDocument();
|
||||
if ($parm["xml"] && ! @$domdoc->loadXML($parm["xml"])) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
$sql = "";
|
||||
$params = array(':task_id' => $taskid);
|
||||
if ($parm["xml"] !== NULL) {
|
||||
$sql .= ( $sql ? " ," : "") . "settings = :settings";
|
||||
$params[':settings'] = $parm['xml'];
|
||||
}
|
||||
if ($parm["name"] !== NULL) {
|
||||
$sql .= ( $sql ? " ," : "") . "name = :name";
|
||||
$params[':name'] = $parm['name'];
|
||||
}
|
||||
if ($parm["active"] !== NULL) {
|
||||
$sql .= ( $sql ? " ," : "") . "active = :active";
|
||||
$params[':active'] = $parm['active'];
|
||||
}
|
||||
|
||||
if ($sql) {
|
||||
try {
|
||||
$sql = "UPDATE task2 SET $sql WHERE task_id = :task_id";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$stmt->closeCursor();
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadSettings(SimpleXMLElement $sx_task_settings)
|
||||
{
|
||||
$this->proxy = (string) $sx_task_settings->proxy;
|
||||
$this->proxyport = (string) $sx_task_settings->proxyport;
|
||||
|
||||
parent::loadSettings($sx_task_settings);
|
||||
}
|
||||
|
||||
protected function retrieveContent(appbox $appbox)
|
||||
{
|
||||
foreach ($this->dependencyContainer['EM']
|
||||
->getRepository('Alchemy\Phrasea\Model\Entities\FtpExport')
|
||||
->findCrashedExports(new \DateTime('-1 month')) as $export) {
|
||||
$this->dependencyContainer['EM']->remove($export);
|
||||
}
|
||||
$this->dependencyContainer['EM']->flush();
|
||||
|
||||
return $this->dependencyContainer['EM']
|
||||
->getRepository('Alchemy\Phrasea\Model\Entities\FtpExport')
|
||||
->findDoableExports();
|
||||
}
|
||||
|
||||
protected function processOneContent(appbox $appbox, $export)
|
||||
{
|
||||
$state = "";
|
||||
$ftp_server = $export->getAddr();
|
||||
$ftp_user_name = $export->getLogin();
|
||||
$ftp_user_pass = $export->getPwd();
|
||||
|
||||
$ftpLog = $ftp_user_name . "@" . p4string::addEndSlash($ftp_server) . $export->getDestfolder();
|
||||
|
||||
if ($export->getCrash() == 0) {
|
||||
$line = sprintf(
|
||||
_('task::ftp:Etat d\'envoi FTP vers le serveur' .
|
||||
' "%1$s" avec le compte "%2$s" et pour destination le dossier : "%3$s"') . PHP_EOL
|
||||
, $ftp_server
|
||||
, $ftp_user_name
|
||||
, $export->getDestfolder()
|
||||
);
|
||||
$state .= $line;
|
||||
$this->logger->addDebug($line);
|
||||
}
|
||||
|
||||
$state .= $line = sprintf(
|
||||
_("task::ftp:TENTATIVE no %s, %s")
|
||||
, $export->getCrash() + 1
|
||||
, " (" . date('r') . ")"
|
||||
) . PHP_EOL;
|
||||
|
||||
$this->logger->addDebug($line);
|
||||
|
||||
try {
|
||||
$ssl = $export->isSsl();
|
||||
$ftp_client = $this->dependencyContainer['phraseanet.ftp.client']($ftp_server, 21, 300, $ssl, $this->proxy, $this->proxyport);
|
||||
$ftp_client->login($ftp_user_name, $ftp_user_pass);
|
||||
|
||||
if ($export->isPassif()) {
|
||||
try {
|
||||
$ftp_client->passive(true);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->addDebug($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (trim($export->getDestfolder()) != '') {
|
||||
try {
|
||||
$ftp_client->chdir($export->getDestFolder());
|
||||
$export->setDestfolder('/' . $export->getDestfolder());
|
||||
} catch (Exception $e) {
|
||||
$this->logger->addDebug($e->getMessage());
|
||||
}
|
||||
} else {
|
||||
$export->setDestfolder('/');
|
||||
}
|
||||
|
||||
if (trim($export->getFoldertocreate()) != '') {
|
||||
try {
|
||||
$ftp_client->mkdir($export->getFoldertocreate());
|
||||
} catch (Exception $e) {
|
||||
$this->logger->addDebug($e->getMessage());
|
||||
}
|
||||
try {
|
||||
$new_dir = $ftp_client->add_end_slash($export->getDestfolder())
|
||||
. $export->getFoldertocreate();
|
||||
$ftp_client->chdir($new_dir);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->addDebug($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$obj = array();
|
||||
|
||||
$basefolder = '';
|
||||
if (!in_array(trim($export->getDestfolder()), array('.', './', ''))) {
|
||||
$basefolder = p4string::addEndSlash($export->getDestfolder());
|
||||
}
|
||||
|
||||
$basefolder .= $export->getFoldertocreate();
|
||||
|
||||
if (in_array(trim($basefolder), array('.', './', ''))) {
|
||||
$basefolder = '/';
|
||||
}
|
||||
|
||||
foreach ($export->getElements() as $exportElement) {
|
||||
if ($exportElement->isDone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$base_id = $exportElement->getBaseId();
|
||||
$record_id = $exportElement->getRecordId();
|
||||
$subdef = $exportElement->getSubdef();
|
||||
$localfile = null;
|
||||
|
||||
try {
|
||||
$sbas_id = phrasea::sbasFromBas($this->dependencyContainer, $base_id);
|
||||
$record = new record_adapter($this->dependencyContainer, $sbas_id, $record_id);
|
||||
|
||||
$sdcaption = $record->get_caption()->serialize(caption_record::SERIALIZE_XML, $exportElement->isBusinessfields());
|
||||
|
||||
$remotefile = $exportElement->getFilename();
|
||||
|
||||
if ($subdef == 'caption') {
|
||||
$desc = $record->get_caption()->serialize(\caption_record::SERIALIZE_XML, $exportElement->isBusinessfields());
|
||||
|
||||
$localfile = $this->dependencyContainer['root.path'] . '/tmp/' . md5($desc . time() . mt_rand());
|
||||
if (file_put_contents($localfile, $desc) === false) {
|
||||
throw new Exception('Impossible de creer un fichier temporaire');
|
||||
}
|
||||
} elseif ($subdef == 'caption-yaml') {
|
||||
$desc = $record->get_caption()->serialize(\caption_record::SERIALIZE_YAML, $exportElement->isBusinessfields());
|
||||
|
||||
$localfile = $this->dependencyContainer['root.path'] . '/tmp/' . md5($desc . time() . mt_rand());
|
||||
if (file_put_contents($localfile, $desc) === false) {
|
||||
throw new Exception('Impossible de creer un fichier temporaire');
|
||||
}
|
||||
} else {
|
||||
$sd = $record->get_subdefs();
|
||||
|
||||
if (!$sd || !isset($sd[$subdef])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$localfile = $sd[$subdef]->get_pathfile();
|
||||
if (!file_exists($localfile)) {
|
||||
throw new Exception('Le fichier local n\'existe pas');
|
||||
}
|
||||
}
|
||||
|
||||
$current_folder = p4string::delEndSlash(str_replace('//', '/', $basefolder . $exportElement->getFolder()));
|
||||
|
||||
if ($ftp_client->pwd() != $current_folder) {
|
||||
try {
|
||||
$ftp_client->chdir($current_folder);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->addDebug($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$ftp_client->put($remotefile, $localfile);
|
||||
|
||||
$obj[] = array(
|
||||
"name" => $subdef, "size" => filesize($localfile),
|
||||
"shortXml" => ($sdcaption ? $sdcaption : '')
|
||||
);
|
||||
|
||||
if ($subdef == 'caption') {
|
||||
unlink($localfile);
|
||||
}
|
||||
|
||||
$exportElement
|
||||
->setDone(true)
|
||||
->setError(false);
|
||||
$this->dependencyContainer['EM']->persist($exportElement);
|
||||
$this->dependencyContainer['EM']->flush();
|
||||
$this->logexport($record, $obj, $ftpLog);
|
||||
} catch (Exception $e) {
|
||||
$state .= $line = sprintf(_('task::ftp:File "%1$s" (record %2$s) de la base "%3$s"' .
|
||||
' (Export du Document) : Transfert cancelled (le document n\'existe plus)')
|
||||
, basename($localfile), $record_id
|
||||
, phrasea::sbas_labels(phrasea::sbasFromBas($this->dependencyContainer, $base_id), $this->dependencyContainer)) . "\n<br/>";
|
||||
|
||||
$this->logger->addDebug($line);
|
||||
|
||||
// One failure max
|
||||
$exportElement
|
||||
->setDone($exportElement->isError())
|
||||
->setError(true);
|
||||
$this->dependencyContainer['EM']->persist($exportElement);
|
||||
$this->dependencyContainer['EM']->flush();
|
||||
}
|
||||
}
|
||||
|
||||
if ($export->isLogfile()) {
|
||||
$this->logger->addDebug("logfile ");
|
||||
|
||||
$date = new DateTime();
|
||||
$buffer = '#transfert finished ' . $date->format(DATE_ATOM) . "\n\n";
|
||||
|
||||
foreach ($export->getElements() as $exportElement) {
|
||||
if (!$exportElement->isDone() || $exportElement->isError()) {
|
||||
continue;
|
||||
}
|
||||
$filename = $exportElement->getFilename();
|
||||
$folder = $exportElement->getFilename();
|
||||
$root = $export->getFoldertocreate();
|
||||
|
||||
$buffer .= $root . '/' . $folder . $filename . "\n";
|
||||
}
|
||||
|
||||
$tmpfile = $this->dependencyContainer['root.path'] . '/tmp/tmpftpbuffer' . $date->format('U') . '.txt';
|
||||
|
||||
file_put_contents($tmpfile, $buffer);
|
||||
|
||||
$remotefile = $date->format('U') . '-transfert.log';
|
||||
$ftp_client->chdir($export->getDestFolder());
|
||||
$ftp_client->put($remotefile, $tmpfile);
|
||||
unlink($tmpfile);
|
||||
}
|
||||
|
||||
$ftp_client->close();
|
||||
unset($ftp_client);
|
||||
} catch (Exception $e) {
|
||||
$state .= $line = $e . "\n";
|
||||
|
||||
$this->logger->addDebug($line);
|
||||
|
||||
$export->incrementCrash();
|
||||
$this->dependencyContainer['EM']->persist($export);
|
||||
$this->dependencyContainer['EM']->flush();
|
||||
|
||||
unset($ftp_client);
|
||||
}
|
||||
|
||||
$this->finalize($appbox, $export);
|
||||
}
|
||||
|
||||
protected function postProcessOneContent(appbox $appbox, $row)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function finalize(appbox $appbox, FtpExport $export)
|
||||
{
|
||||
if ($export->getCrash() >= $export->getNbretry()) {
|
||||
$this->send_mails($appbox, $export);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$total = count($export->getElements());
|
||||
$done = count($export->getElements()->filter(function (FtpExportElement $element) {
|
||||
return $element->isDone();
|
||||
}));
|
||||
$error = count($export->getElements()->filter(function (FtpExportElement $element) {
|
||||
return $element->isError();
|
||||
}));
|
||||
|
||||
if ($done === $total) {
|
||||
$this->send_mails($appbox, $export);
|
||||
|
||||
if ((int) $error === 0) {
|
||||
$this->dependencyContainer['EM']->remove($export);
|
||||
$this->dependencyContainer['EM']->flush();
|
||||
} else {
|
||||
$export->setCrash($export->getNbretry());
|
||||
foreach ($export->getElements() as $element) {
|
||||
if (!$element->isError()) {
|
||||
$this->dependencyContainer['EM']->remove($export);
|
||||
}
|
||||
}
|
||||
$this->dependencyContainer['EM']->flush();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
public function send_mails(appbox $appbox, FtpExport $export)
|
||||
{
|
||||
$transferts = array();
|
||||
$transfert_status = _('task::ftp:Tous les documents ont ete transferes avec succes');
|
||||
|
||||
foreach ($export->getElements() as $element) {
|
||||
if (!$element->isError() && $element->isDone()) {
|
||||
$transferts[] =
|
||||
'<li>' . sprintf(_('task::ftp:Record %1$s - %2$s de la base (%3$s - %4$s) - %5$s')
|
||||
, $element->getRecordId(), $element->getFilename()
|
||||
, phrasea::sbas_labels(phrasea::sbasFromBas($this->dependencyContainer, $element->getBaseId()), $this->dependencyContainer)
|
||||
, phrasea::bas_labels($element->getBaseId(), $this->dependencyContainer), $element->getSubdef()) . ' : ' . _('Transfert OK') . '</li>';
|
||||
} else {
|
||||
$transferts[] =
|
||||
'<li>' . sprintf(_('task::ftp:Record %1$s - %2$s de la base (%3$s - %4$s) - %5$s')
|
||||
, $element->getRecordId(), $element->getFilename()
|
||||
, phrasea::sbas_labels(phrasea::sbasFromBas($this->dependencyContainer, $element->getBaseId()), $this->dependencyContainer), phrasea::bas_labels($element->getBaseId(), $this->dependencyContainer)
|
||||
, $element->getSubdef()) . ' : ' . _('Transfert Annule') . '</li>';
|
||||
$transfert_status = _('task::ftp:Certains documents n\'ont pas pu etre tranferes');
|
||||
}
|
||||
}
|
||||
|
||||
if ($export->getCrash() >= $export->getNbretry()) {
|
||||
$connection_status = _('Des difficultes ont ete rencontres a la connection au serveur distant');
|
||||
} else {
|
||||
$connection_status = _('La connection vers le serveur distant est OK');
|
||||
}
|
||||
|
||||
$text_mail_sender = $export->getTextMailSender();
|
||||
$text_mail_receiver = $export->getTextMailReceiver();
|
||||
$mail = $export->getMail();
|
||||
$sendermail = $export->getSendermail();
|
||||
$ftp_server = $export->getAddr();
|
||||
|
||||
$message = "\n\n----------------------------------------\n\n";
|
||||
$message = $connection_status . "\n";
|
||||
$message .= $transfert_status . "\n";
|
||||
$message .= _("task::ftp:Details des fichiers") . "\n\n";
|
||||
|
||||
$message .= implode("\n", $transferts);
|
||||
|
||||
$sender_message = $text_mail_sender . $message;
|
||||
$receiver_message = $text_mail_receiver . $message;
|
||||
|
||||
try {
|
||||
$receiver = new Receiver(null, $sendermail);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$receiver = null;
|
||||
}
|
||||
|
||||
if ($receiver) {
|
||||
$mail = MailSuccessFTPSender::create($this->dependencyContainer, $receiver, null, $sender_message);
|
||||
$mail->setServer($ftp_server);
|
||||
$this->dependencyContainer['notification.deliverer']->deliver($mail);
|
||||
}
|
||||
|
||||
try {
|
||||
$receiver = new Receiver(null, $mail);
|
||||
$mail = MailSuccessFTPSender::create($this->dependencyContainer, $receiver, null, $receiver_message);
|
||||
$mail->setServer($ftp_server);
|
||||
$this->dependencyContainer['notification.deliverer']->deliver($mail);
|
||||
} catch (\Exception $e) {
|
||||
$this->log('Unable to deliver success message');
|
||||
}
|
||||
}
|
||||
|
||||
public function logexport(record_adapter $record, $obj, $ftpLog)
|
||||
{
|
||||
foreach ($obj as $oneObj) {
|
||||
$this->dependencyContainer['phraseanet.logger']($record->get_databox())
|
||||
->log($record, Session_Logger::EVENT_EXPORTFTP, $ftpLog, '');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*/
|
||||
public static function getDefaultSettings(Configuration $config, array $params = array())
|
||||
{
|
||||
$period = isset($params['period']) ? $params['period'] : self::MINPERIOD;
|
||||
|
||||
return sprintf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||
<tasksettings>
|
||||
<proxy></proxy>
|
||||
<proxyport></proxyport>
|
||||
<period>%s</period>
|
||||
<syslog></syslog>
|
||||
</tasksettings>", min(max($period, self::MINPERIOD), self::MAXPERIOD));
|
||||
}
|
||||
}
|
@@ -1,473 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Core\Configuration\Configuration;
|
||||
|
||||
class task_period_ftpPull extends task_appboxAbstract
|
||||
{
|
||||
protected $proxy;
|
||||
protected $proxyport;
|
||||
protected $host;
|
||||
protected $port;
|
||||
protected $user;
|
||||
protected $password;
|
||||
protected $ssl;
|
||||
protected $passive;
|
||||
protected $ftppath;
|
||||
protected $localpath;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return(_("task::ftp:FTP Pull"));
|
||||
}
|
||||
|
||||
public static function help()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function graphic2xml($oldxml)
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm2 = $request->get_parms(
|
||||
'proxy'
|
||||
, 'proxyport'
|
||||
, 'host'
|
||||
, 'port'
|
||||
, 'user'
|
||||
, 'password'
|
||||
, 'ssl'
|
||||
, 'ftppath'
|
||||
, 'localpath'
|
||||
, 'passive'
|
||||
, 'period'
|
||||
);
|
||||
$dom = new DOMDocument();
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
if (@$dom->loadXML($oldxml)) {
|
||||
$xmlchanged = false;
|
||||
foreach (array(
|
||||
'str:proxy'
|
||||
, 'str:proxyport'
|
||||
, 'str:period'
|
||||
, 'boo:passive'
|
||||
, 'boo:ssl'
|
||||
, 'str:password'
|
||||
, 'str:user'
|
||||
, 'str:ftppath'
|
||||
, 'str:localpath'
|
||||
, 'str:port'
|
||||
, 'str:host'
|
||||
) as $pname) {
|
||||
$ptype = substr($pname, 0, 3);
|
||||
$pname = substr($pname, 4);
|
||||
$pvalue = $parm2[$pname];
|
||||
if ($ns = $dom->getElementsByTagName($pname)->item(0)) {
|
||||
// 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":
|
||||
case "pop":
|
||||
$ns->appendChild($dom->createTextNode($pvalue));
|
||||
break;
|
||||
case "boo":
|
||||
$ns->appendChild($dom->createTextNode($pvalue ? '1' : '0'));
|
||||
break;
|
||||
}
|
||||
$xmlchanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
return($dom->saveXML());
|
||||
}
|
||||
|
||||
|
||||
public function printInterfaceJS()
|
||||
{
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
|
||||
function taskFillGraphic_<?php echo(get_class($this));?>(xml)
|
||||
{
|
||||
if (xml) {
|
||||
xml = $.parseXML(xml);
|
||||
xml = $(xml);
|
||||
|
||||
with(document.forms['graphicForm'])
|
||||
{
|
||||
proxy.value = xml.find("proxy").text();
|
||||
proxyport.value = xml.find("proxyport").text();
|
||||
period.value = xml.find("period").text();
|
||||
localpath.value = xml.find("localpath").text();
|
||||
ftppath.value = xml.find("ftppath").text();
|
||||
host.value = xml.find("host").text();
|
||||
port.value = xml.find("port").text();
|
||||
user.value = xml.find("user").text();
|
||||
password.value = xml.find("password").text();
|
||||
ssl.checked = Number(xml.find("ssl").text()) > 0;
|
||||
passive.checked = Number(xml.find("passive").text()) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
var limits = {
|
||||
'period' :{'min':<?php echo self::MINPERIOD; ?>, 'max':<?php echo self::MAXPERIOD; ?>}
|
||||
} ;
|
||||
$(".formElem").change(function(){
|
||||
fieldname = $(this).attr("name");
|
||||
switch ((this.nodeName+$(this).attr("type")).toLowerCase()) {
|
||||
case "inputtext":
|
||||
if (typeof(limits[fieldname])!='undefined') {
|
||||
var v = 0|this.value;
|
||||
if(v < limits[fieldname].min)
|
||||
v = limits[fieldname].min;
|
||||
else if(v > limits[fieldname].max)
|
||||
v = limits[fieldname].max;
|
||||
this.value = v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
setDirty();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
public function getInterfaceHTML()
|
||||
{
|
||||
ob_start();
|
||||
?>
|
||||
<form name="graphicForm" onsubmit="return(false);" method="post">
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::ftp:proxy') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="proxy" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::ftp:proxy port') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="proxyport" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo('task::ftp:host') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="host" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo('task::ftp:port') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="port" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo('task::ftp:user') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="user" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo('task::ftp:password') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="password" name="password" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo('task::ftp:chemin distant') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="ftppath" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo('task::ftp:localpath') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="text" name="localpath" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::ftp:mode passif') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem" type="checkbox" name="passive" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input class="formElem" type="checkbox" name="ssl" />
|
||||
<?php echo _('task::ftp:utiliser SSL') ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::_common_:periodicite de la tache') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-small" type="text" name="period" value="">
|
||||
<span class="help-inline"><?php echo _('task::_common_:secondes (unite temporelle)') ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public function saveChanges(connection_pdo $conn, $taskid, &$taskrow)
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm = $request->get_parms(
|
||||
'xml'
|
||||
, 'name'
|
||||
, 'active'
|
||||
, 'proxy'
|
||||
, 'proxyport'
|
||||
, 'period'
|
||||
, 'localpath'
|
||||
, 'ftppath'
|
||||
, 'port'
|
||||
, 'host'
|
||||
, 'user'
|
||||
, 'password'
|
||||
, 'passive'
|
||||
, 'ssl'
|
||||
);
|
||||
|
||||
if ($parm["xml"] === null) {
|
||||
// pas de xml 'raw' : on accepte les champs 'graphic view'
|
||||
$domdoc = new DOMDocument();
|
||||
if (($domTaskSettings = $domdoc->loadXML($taskrow["settings"])) != FALSE) {
|
||||
$xmlchanged = false;
|
||||
foreach (array(
|
||||
'proxy'
|
||||
, 'proxyport'
|
||||
, 'period'
|
||||
, 'localpath'
|
||||
, 'ftppath'
|
||||
, 'host'
|
||||
, 'port'
|
||||
, 'user'
|
||||
, 'password'
|
||||
, 'passive'
|
||||
, 'ssl'
|
||||
) as $f) {
|
||||
if ($parm[$f] !== NULL) {
|
||||
if (($ns = $domTaskSettings->getElementsByTagName($f)->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 = $domTaskSettings->documentElement->appendChild($domTaskSettings->createElement($f));
|
||||
}
|
||||
// on fixe sa valeur
|
||||
$ns->appendChild($domTaskSettings->createTextNode($parm[$f]));
|
||||
$xmlchanged = true;
|
||||
}
|
||||
}
|
||||
if ($xmlchanged) {
|
||||
$parm["xml"] = $domTaskSettings->saveXML();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// si on doit changer le xml, on verifie qu'il est valide
|
||||
$domdoc = new DOMDocument();
|
||||
if ($parm["xml"] && ! $domdoc->loadXML($parm["xml"])) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
$sql = "";
|
||||
$params = array(':task_id' => $taskid);
|
||||
if ($parm["xml"] !== NULL) {
|
||||
$sql .= ( $sql ? " ," : "") . "settings = :settings";
|
||||
$params[':settings'] = $parm['xml'];
|
||||
}
|
||||
if ($parm["name"] !== NULL) {
|
||||
$sql .= ( $sql ? " ," : "") . "name = :name";
|
||||
$params[':name'] = $parm['name'];
|
||||
}
|
||||
if ($parm["active"] !== NULL) {
|
||||
$sql .= ( $sql ? " ," : "") . "active = :active";
|
||||
$params[':active'] = $parm['active'];
|
||||
}
|
||||
|
||||
if ($sql) {
|
||||
try {
|
||||
$sql = "UPDATE task2 SET $sql WHERE task_id = :task_id";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$stmt->closeCursor();
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadSettings(SimpleXMLElement $sx_task_settings)
|
||||
{
|
||||
$this->proxy = (string) $sx_task_settings->proxy;
|
||||
$this->proxyport = (string) $sx_task_settings->proxyport;
|
||||
$this->host = (string) ($sx_task_settings->host);
|
||||
$this->port = (string) ($sx_task_settings->port);
|
||||
$this->user = (string) ($sx_task_settings->user);
|
||||
$this->password = (string) ($sx_task_settings->password);
|
||||
$this->ssl = !!((string) ($sx_task_settings->ssl));
|
||||
$this->passive = !!((string) ($sx_task_settings->passive));
|
||||
$this->ftppath = (string) ($sx_task_settings->ftppath);
|
||||
$this->localpath = (string) ($sx_task_settings->localpath);
|
||||
|
||||
parent::loadSettings($sx_task_settings);
|
||||
}
|
||||
|
||||
protected function retrieveContent(appbox $appbox)
|
||||
{
|
||||
foreach (array('localpath', 'host', 'port', 'user', 'password', 'ftppath') as $f) {
|
||||
if (trim((string) ($this->{$f})) === '') {
|
||||
$this->log(sprintf('setting \'%s\' must be set', $f), self::LOG_ERROR);
|
||||
$this->running = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
$this->dependencyContainer['filesystem']->mkdir($this->localpath, 0750);
|
||||
|
||||
if (!is_dir($this->localpath)) {
|
||||
$this->log(sprintf('\'%s\' does not exists', $this->localpath), self::LOG_ERROR);
|
||||
$this->running = FALSE;
|
||||
}
|
||||
if (!is_writeable($this->localpath)) {
|
||||
$this->log(sprintf('\'%s\' is not writeable', $this->localpath), self::LOG_ERROR);
|
||||
$this->running = FALSE;
|
||||
}
|
||||
|
||||
if (!$this->running) {
|
||||
$this->set_status(self::STATE_STOPPED);
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
try {
|
||||
$ftp = $this->dependencyContainer['phraseanet.ftp.client']($this->host, $this->port, 90, $this->ssl, $this->proxy, $this->proxyport);
|
||||
$ftp->login($this->user, $this->password);
|
||||
$ftp->chdir($this->ftppath);
|
||||
$list_1 = $ftp->list_directory(true);
|
||||
|
||||
$done = 0;
|
||||
$todo = count($list_1);
|
||||
$this->setProgress($done, $todo);
|
||||
|
||||
$this->logger->addDebug("attente de 25sec pour avoir les fichiers froids...");
|
||||
|
||||
$this->sleep(25);
|
||||
if (!$this->running) {
|
||||
if (isset($ftp) && $ftp instanceof ftpclient) {
|
||||
$ftp->close();
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
$list_2 = $ftp->list_directory(true);
|
||||
|
||||
foreach ($list_1 as $filepath => $timestamp) {
|
||||
$done++;
|
||||
$this->setProgress($done, $todo);
|
||||
|
||||
if (!isset($list_2[$filepath])) {
|
||||
$this->logger->addDebug("le fichier $filepath a disparu...\n");
|
||||
continue;
|
||||
}
|
||||
if ($list_2[$filepath] !== $timestamp) {
|
||||
$this->logger->addDebug("le fichier $filepath a ete modifie depuis le dernier passage...");
|
||||
continue;
|
||||
}
|
||||
|
||||
$finalpath = p4string::addEndSlash($this->localpath) . ($filepath[0] == '/' ? mb_substr($filepath, 1) : $filepath);
|
||||
$this->logger->addDebug("Ok pour rappatriement de $filepath vers $finalpath\n");
|
||||
|
||||
try {
|
||||
if (file_exists($finalpath)) {
|
||||
throw new Exception("Un fichier du meme nom ($finalpath) existe deja...");
|
||||
}
|
||||
|
||||
$this->dependencyContainer['filesystem']->mkdir(dirname($finalpath), 0750);
|
||||
|
||||
$ftp->get($finalpath, $filepath);
|
||||
$ftp->delete($filepath);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->addDebug("Erreur lors du rappatriement de $filepath : " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$ftp->close();
|
||||
|
||||
$this->setProgress(0, 0);
|
||||
} catch (Exception $e) {
|
||||
if (isset($ftp) && $ftp instanceof ftpclient) {
|
||||
$ftp->close();
|
||||
}
|
||||
$this->log($e->getMessage(), self::LOG_ERROR);
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
protected function processOneContent(appbox $appbox, $row)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function postProcessOneContent(appbox $appbox, $row)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*/
|
||||
public static function getDefaultSettings(Configuration $config, array $params = array())
|
||||
{
|
||||
$period = isset($params['period']) ? $params['period'] : self::MINPERIOD;
|
||||
|
||||
return sprintf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||
<tasksettings>
|
||||
<proxy></proxy>
|
||||
<proxyport></proxyport>
|
||||
<period>%s</period>
|
||||
<passive>0</passive>
|
||||
<ssl>0</ssl>
|
||||
<password></password>
|
||||
<user></user>
|
||||
<ftppath></ftppath>
|
||||
<localpath></localpath>
|
||||
<port>21</port>
|
||||
<host></host>
|
||||
</tasksettings>", min(max($period, self::MINPERIOD), self::MAXPERIOD));
|
||||
}
|
||||
}
|
@@ -1,372 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Core\Configuration\Configuration;
|
||||
|
||||
use MediaAlchemyst\Transmuter\Image2Image;
|
||||
|
||||
class task_period_subdef extends task_databoxAbstract
|
||||
{
|
||||
const MINFLUSH = 10;
|
||||
|
||||
/**
|
||||
* Record buffer for writing meta datas after building subdefs
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $recs_to_write = array();
|
||||
|
||||
/**
|
||||
* Maximum buffer size before flushing records
|
||||
*
|
||||
* @var <type>
|
||||
*/
|
||||
protected $record_buffer_size;
|
||||
|
||||
protected $thumbnailExtraction;
|
||||
|
||||
/**
|
||||
* Return about text
|
||||
*
|
||||
* @return <type>
|
||||
*/
|
||||
public static function help()
|
||||
{
|
||||
return(
|
||||
_("task::subdef:creation des sous definitions des documents d'origine")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns task name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return(_('task::subdef:creation des sous definitions'));
|
||||
}
|
||||
|
||||
protected function loadSettings(SimpleXMLElement $sx_task_settings)
|
||||
{
|
||||
$this->thumbnailExtraction = (Boolean) trim($sx_task_settings->embedded);
|
||||
|
||||
parent::loadSettings($sx_task_settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* must return the xml (text) version of the form
|
||||
*
|
||||
* @param string $oldxml
|
||||
* @return string
|
||||
*/
|
||||
public function graphic2xml($oldxml)
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm2 = $request->get_parms('period', 'flush', 'maxrecs', 'maxmegs', 'embedded');
|
||||
$dom = new DOMDocument();
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
if (@$dom->loadXML($oldxml)) {
|
||||
foreach (array('str:period', 'str:flush', 'str:maxrecs', 'str:maxmegs', 'boo:embedded') as $pname) {
|
||||
$ptype = substr($pname, 0, 3);
|
||||
$pname = substr($pname, 4);
|
||||
$pvalue = $parm2[$pname];
|
||||
if (($ns = $dom->getElementsByTagName($pname)->item(0)) != NULL) {
|
||||
while (($n = $ns->firstChild)) {
|
||||
$ns->removeChild($n);
|
||||
}
|
||||
} else {
|
||||
$ns = $dom->documentElement->appendChild($dom->createElement($pname));
|
||||
}
|
||||
switch ($ptype) {
|
||||
case "str":
|
||||
case "pop":
|
||||
$ns->appendChild($dom->createTextNode($pvalue));
|
||||
break;
|
||||
case "boo":
|
||||
$ns->appendChild($dom->createTextNode($pvalue ? '1' : '0'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return($dom->saveXML());
|
||||
}
|
||||
|
||||
/**
|
||||
* must fill the graphic form (using js) from xml
|
||||
*
|
||||
* @param string $xml
|
||||
* @param string $form
|
||||
* @return string
|
||||
*/
|
||||
public function xml2graphic($xml, $form)
|
||||
{
|
||||
if (false !== $sxml = simplexml_load_string($xml)) {
|
||||
if ((int) ($sxml->period) < self::MINPERIOD) {
|
||||
$sxml->period = self::MINPERIOD;
|
||||
} elseif ((int) ($sxml->period) > self::MAXPERIOD) {
|
||||
$sxml->period = self::MAXPERIOD;
|
||||
}
|
||||
|
||||
if ((int) ($sxml->flush) < self::MINFLUSH) {
|
||||
$sxml->flush = self::MINFLUSH;
|
||||
} elseif ((int) ($sxml->flush) > self::MAXFLUSH) {
|
||||
$sxml->flush = self::MAXFLUSH;
|
||||
}
|
||||
|
||||
if ((int) ($sxml->maxrecs) < self::MINRECS) {
|
||||
$sxml->maxrecs = self::MINRECS;
|
||||
} elseif (self::MAXRECS != -1 && (int) ($sxml->maxrecs) > self::MAXRECS) {
|
||||
$sxml->maxrecs = self::MAXRECS;
|
||||
}
|
||||
|
||||
if ((int) ($sxml->maxmegs) < self::MINMEGS) {
|
||||
$sxml->maxmegs = self::MINMEGS;
|
||||
} elseif (self::MAXMEGS != -1 && (int) ($sxml->maxmegs) > self::MAXMEGS) {
|
||||
$sxml->maxmegs = self::MAXMEGS;
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
<?php echo $form ?>.period.value = "<?php echo p4string::MakeString($sxml->period, "js", '"') ?>";
|
||||
<?php echo $form ?>.flush.value = "<?php echo p4string::MakeString($sxml->flush, "js", '"') ?>";
|
||||
<?php echo $form ?>.maxrecs.value = "<?php echo p4string::MakeString($sxml->maxrecs, "js", '"') ?>";
|
||||
<?php echo $form ?>.maxmegs.value = "<?php echo p4string::MakeString($sxml->maxmegs, "js", '"') ?>";
|
||||
<?php echo $form ?>.embedded.value = <?php echo (Boolean) trim($sxml->embedded); ?>;
|
||||
</script>
|
||||
|
||||
<?php
|
||||
|
||||
return("");
|
||||
} else {
|
||||
return("BAD XML");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* generates le code js de l'interface 'graphic view'
|
||||
*
|
||||
*/
|
||||
public function printInterfaceJS()
|
||||
{
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
function taskFillGraphic_<?php echo(get_class($this));?>(xml)
|
||||
{
|
||||
if (xml) {
|
||||
xml = $.parseXML(xml);
|
||||
xml = $(xml);
|
||||
|
||||
with(document.forms['graphicForm'])
|
||||
{
|
||||
period.value = xml.find("period").text();
|
||||
flush.value = xml.find("flush").text();
|
||||
maxrecs.value = xml.find("maxrecs").text();
|
||||
maxmegs.value = xml.find("maxmegs").text();
|
||||
embedded.checked = !!parseInt(xml.find("embedded").text());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
var limits = {
|
||||
'period' :{'min':<?php echo self::MINPERIOD; ?>, 'max':<?php echo self::MAXPERIOD; ?>},
|
||||
'flush' :{'min':<?php echo self::MINFLUSH; ?>, 'max':<?php echo self::MAXFLUSH; ?>},
|
||||
'maxrecs':{'min':<?php echo self::MINRECS; ?>, 'max':<?php echo self::MAXRECS; ?>},
|
||||
'maxmegs':{'min':<?php echo self::MINMEGS; ?>, 'max':<?php echo self::MAXMEGS; ?>}
|
||||
} ;
|
||||
$(".formElem").change(function(){
|
||||
fieldname = $(this).attr("name");
|
||||
switch ((this.nodeName+$(this).attr("type")).toLowerCase()) {
|
||||
case "inputtext":
|
||||
if (typeof(limits[fieldname])!='undefined') {
|
||||
var v = 0|this.value;
|
||||
if(v < limits[fieldname].min)
|
||||
v = limits[fieldname].min;
|
||||
else if(v > limits[fieldname].max)
|
||||
v = limits[fieldname].max;
|
||||
this.value = v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
setDirty();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* return interface 'graphic view'
|
||||
*
|
||||
*/
|
||||
public function getInterfaceHTML()
|
||||
{
|
||||
ob_start();
|
||||
?>
|
||||
<form id="graphicForm" class="form-horizontal" name="graphicForm" onsubmit="return(false);" method="post">
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::_common_:periodicite de la tache') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-small" type="text" name="period" />
|
||||
<span class="help-inline"><?php echo _('task::_common_:secondes (unite temporelle)') ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"> <?php echo sprintf(_("Number of records to process per batch")) ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-mini" type="text" name="flush" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Restart the task every X records') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-mini" type="text" name="maxrecs" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Restart the task if memory reaches') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-mini" type="text" name="maxmegs" value="">
|
||||
<span class="help-inline">Mo</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Try to extract embedded thumbnails') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-mini" type="checkbox" name="embedded" value="1">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public function retrieveSbasContent(databox $databox)
|
||||
{
|
||||
Image2Image::$lookForEmbeddedPreview = $this->thumbnailExtraction;
|
||||
|
||||
$connbas = $databox->get_connection();
|
||||
|
||||
$sql = 'SELECT coll_id, record_id
|
||||
FROM record
|
||||
WHERE jeton & ' . JETON_MAKE_SUBDEF . ' > 0
|
||||
ORDER BY record_id DESC LIMIT 0, '.$this->maxrecs;
|
||||
$stmt = $connbas->prepare($sql);
|
||||
$stmt->execute();
|
||||
$rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
public function processOneContent(databox $databox, $row)
|
||||
{
|
||||
$record_id = $row['record_id'];
|
||||
$this->log(sprintf(
|
||||
"Generate subdefs for : sbasid=%s / databox=%s / recordid=%s "
|
||||
, $databox->get_sbas_id(), $databox->get_dbname() , $record_id)
|
||||
, self::LOG_INFO
|
||||
);
|
||||
|
||||
try {
|
||||
$record = new record_adapter($this->dependencyContainer, $this->sbas_id, $record_id);
|
||||
|
||||
$record->generate_subdefs($databox, $this->dependencyContainer);
|
||||
} catch (\Exception $e) {
|
||||
$this->log(
|
||||
sprintf(
|
||||
"Generate subdefs failed for : sbasid=%s / databox=%s / recordid=%s : %s"
|
||||
, $databox->get_sbas_id(), $databox->get_dbname() , $record_id, $e->getMessage())
|
||||
, self::LOG_WARNING
|
||||
);
|
||||
}
|
||||
|
||||
$this->recs_to_write[] = $record->get_record_id();
|
||||
|
||||
if (count($this->recs_to_write) >= $this->record_buffer_size) {
|
||||
$this->flushRecordsSbas();
|
||||
}
|
||||
unset($record);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function postProcessOneContent(databox $databox, $row)
|
||||
{
|
||||
$connbas = $databox->get_connection();
|
||||
$sql = 'UPDATE record
|
||||
SET jeton=(jeton & ~' . JETON_MAKE_SUBDEF . '), moddate=NOW()
|
||||
WHERE record_id=:record_id';
|
||||
|
||||
$stmt = $connbas->prepare($sql);
|
||||
$stmt->execute(array(':record_id' => $row['record_id']));
|
||||
$stmt->closeCursor();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function flushRecordsSbas()
|
||||
{
|
||||
$sql = implode(', ', $this->recs_to_write);
|
||||
|
||||
if ($sql != '') {
|
||||
$this->log(sprintf(
|
||||
'setting %d record(s) to subdef meta writing'
|
||||
, count($this->recs_to_write)
|
||||
), self::LOG_INFO);
|
||||
|
||||
try {
|
||||
$connbas = connection::getPDOConnection($this->dependencyContainer, $this->sbas_id);
|
||||
$sql = 'UPDATE record
|
||||
SET status=(status & ~0x03),
|
||||
jeton=(jeton | ' . JETON_WRITE_META_SUBDEF . ')
|
||||
WHERE record_id IN (' . $sql . ')';
|
||||
$stmt = $connbas->prepare($sql);
|
||||
$stmt->execute();
|
||||
$stmt->closeCursor();
|
||||
} catch (\Exception $e) {
|
||||
$this->log($e->getMessage(), self::LOG_CRITICAL);
|
||||
}
|
||||
}
|
||||
$this->recs_to_write = array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*/
|
||||
public static function getDefaultSettings(Configuration $config, array $params = array())
|
||||
{
|
||||
$period = isset($params['period']) ? $params['period'] : self::MINPERIOD;
|
||||
$flush = isset($params['flush']) ? $params['flush'] : self::MINFLUSH;
|
||||
$maxrecs = isset($params['maxrecs']) ? $params['maxrecs'] : self::MINRECS;
|
||||
$maxmegs = isset($params['maxmegs']) ? $params['maxmegs'] : self::DEFMEGS;
|
||||
|
||||
return sprintf('<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tasksettings>
|
||||
<period>%s</period>
|
||||
<flush>%s</flush>
|
||||
<maxrecs>%s</maxrecs>
|
||||
<maxmegs>%s</maxmegs>
|
||||
<embedded>0</embedded>
|
||||
</tasksettings>',
|
||||
min(max($period, self::MINPERIOD), self::MAXPERIOD),
|
||||
min(max($flush, self::MINFLUSH), self::MAXFLUSH),
|
||||
min(max($maxrecs, self::MINRECS), self::MAXRECS),
|
||||
min(max($maxmegs, self::MINMEGS), self::MAXMEGS)
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
class task_period_test extends task_appboxAbstract
|
||||
{
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return "Test";
|
||||
}
|
||||
|
||||
public static function help()
|
||||
{
|
||||
return "just saying what i'm doing";
|
||||
}
|
||||
|
||||
protected function retrieveContent(appbox $appbox)
|
||||
{
|
||||
$this->log('test class, retrieve content');
|
||||
|
||||
return array(array('hello'), array('world'));
|
||||
}
|
||||
|
||||
protected function processOneContent(appbox $appbox, $row)
|
||||
{
|
||||
$this->log(sprintf("test class, process content : `%s`", implode(' ', $row)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function postProcessOneContent(appbox $appbox, $row)
|
||||
{
|
||||
$this->log(sprintf("test class, post process content, they were %s", count($row)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -1,360 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Core\Configuration\Configuration;
|
||||
use PHPExiftool\Driver\Metadata;
|
||||
use PHPExiftool\Driver\Value;
|
||||
use PHPExiftool\Driver\Tag;
|
||||
use PHPExiftool\Writer;
|
||||
|
||||
class task_period_writemeta extends task_databoxAbstract
|
||||
{
|
||||
protected $clear_doc;
|
||||
protected $metasubdefs = array();
|
||||
|
||||
public static function help()
|
||||
{
|
||||
return(_("task::writemeta:(re)ecriture des metadatas dans les documents (et subdefs concernees)"));
|
||||
}
|
||||
|
||||
protected function loadSettings(SimpleXMLElement $sx_task_settings)
|
||||
{
|
||||
$this->clear_doc = p4field::isyes($sx_task_settings->cleardoc);
|
||||
parent::loadSettings($sx_task_settings);
|
||||
}
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return(_('task::writemeta:ecriture des metadatas'));
|
||||
}
|
||||
|
||||
public function graphic2xml($oldxml)
|
||||
{
|
||||
$request = http_request::getInstance();
|
||||
|
||||
$parm2 = $request->get_parms('period', 'cleardoc', 'maxrecs', 'maxmegs');
|
||||
$dom = new DOMDocument();
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
if ($dom->loadXML($oldxml)) {
|
||||
foreach (array('str:period', 'str:maxrecs', 'str:maxmegs', 'boo:cleardoc') 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":
|
||||
case "pop":
|
||||
$ns->appendChild($dom->createTextNode($pvalue));
|
||||
break;
|
||||
case "boo":
|
||||
$ns->appendChild($dom->createTextNode($pvalue ? '1' : '0'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return($dom->saveXML());
|
||||
}
|
||||
|
||||
public function xml2graphic($xml, $form)
|
||||
{
|
||||
if (false !== $sxml = simplexml_load_string($xml)) {
|
||||
|
||||
if ((int) ($sxml->period) < self::MINPERIOD) {
|
||||
$sxml->period = self::MINPERIOD;
|
||||
} elseif ((int) ($sxml->period) > self::MAXPERIOD) {
|
||||
$sxml->period = self::MAXPERIOD;
|
||||
}
|
||||
|
||||
if ((int) ($sxml->maxrecs) < self::MINRECS) {
|
||||
$sxml->maxrecs = self::MINRECS;
|
||||
} elseif (self::MAXRECS != -1 && (int) ($sxml->maxrecs) > self::MAXRECS) {
|
||||
$sxml->maxrecs = self::MAXRECS;
|
||||
}
|
||||
|
||||
if ((int) ($sxml->maxmegs) < self::MINMEGS) {
|
||||
$sxml->maxmegs = self::MINMEGS;
|
||||
} elseif (self::MAXMEGS != -1 && (int) ($sxml->maxmegs) > self::MAXMEGS) {
|
||||
$sxml->maxmegs = self::MAXMEGS;
|
||||
}
|
||||
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
<?php echo $form ?>.period.value = "<?php echo p4string::MakeString($sxml->period, "js", '"') ?>";
|
||||
<?php echo $form ?>.cleardoc.checked = <?php echo p4field::isyes($sxml->cleardoc) ? "true" : 'false' ?>;
|
||||
<?php echo $form ?>.maxrecs.value = "<?php echo p4string::MakeString($sxml->maxrecs, "js", '"') ?>";
|
||||
<?php echo $form ?>.maxmegs.value = "<?php echo p4string::MakeString($sxml->maxmegs, "js", '"') ?>";
|
||||
</script>
|
||||
<?php
|
||||
|
||||
return("");
|
||||
} else { // ... so we NEVER come here
|
||||
// bad xml
|
||||
return("BAD XML");
|
||||
}
|
||||
}
|
||||
|
||||
public function printInterfaceJS()
|
||||
{
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
function taskFillGraphic_<?php echo(get_class($this));?>(xml)
|
||||
{
|
||||
if (xml) {
|
||||
xml = $.parseXML(xml);
|
||||
xml = $(xml);
|
||||
|
||||
with(document.forms['graphicForm'])
|
||||
{
|
||||
period.value = xml.find("period").text();
|
||||
cleardoc.checked = Number(xml.find("cleardoc").text()) > 0;
|
||||
maxrecs.value = xml.find("maxrecs").text();
|
||||
maxmegs.value = xml.find("maxmegs").text();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
var limits = {
|
||||
'period':{'min':<?php echo self::MINPERIOD; ?>, 'max':<?php echo self::MAXPERIOD; ?>},
|
||||
'maxrecs':{'min':<?php echo self::MINRECS; ?>, 'max':<?php echo self::MAXRECS; ?>},
|
||||
'maxmegs':{'min':<?php echo self::MINMEGS; ?>, 'max':<?php echo self::MAXMEGS; ?>}
|
||||
} ;
|
||||
$(".formElem").change(function(){
|
||||
fieldname = $(this).attr("name");
|
||||
switch ((this.nodeName+$(this).attr("type")).toLowerCase()) {
|
||||
case "inputtext":
|
||||
if (typeof(limits[fieldname])!='undefined') {
|
||||
var v = 0|this.value;
|
||||
if(v < limits[fieldname].min)
|
||||
v = limits[fieldname].min;
|
||||
else if(v > limits[fieldname].max)
|
||||
v = limits[fieldname].max;
|
||||
this.value = v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
setDirty();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function getInterfaceHTML()
|
||||
{
|
||||
$sbas_ids = $this->dependencyContainer['authentication']->getUser()->ACL()->get_granted_sbas(array('bas_manage'));
|
||||
|
||||
ob_start();
|
||||
if (count($sbas_ids) > 0) {
|
||||
?>
|
||||
<form name="graphicForm" onsubmit="return(false);" method="post">
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::_common_:periodicite de la tache') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-small" type="text" name="period" value="">
|
||||
<span class="help-inline"><?php echo _('task::_common_:secondes (unite temporelle)') ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input class="formElem" type="checkbox" name="cleardoc">
|
||||
<?php echo _('task::writemeta:effacer les metadatas non presentes dans la structure') ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('Restart the task every X records') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-small" type="text" name="maxrecs" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label"><?php echo _('task::_common_:records, ou si la memoire depasse') ?></label>
|
||||
<div class="controls">
|
||||
<input class="formElem input-small" type="text" name="maxmegs" value="">
|
||||
<span class="help-inline">Mo</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
protected function retrieveSbasContent(databox $databox)
|
||||
{
|
||||
$this->dependencyContainer['exiftool.writer']->setModule(Writer::MODULE_MWG, true);
|
||||
|
||||
$connbas = $databox->get_connection();
|
||||
$subdefgroups = $databox->get_subdef_structure();
|
||||
$metasubdefs = array();
|
||||
|
||||
foreach ($subdefgroups as $type => $subdefs) {
|
||||
foreach ($subdefs as $sub) {
|
||||
$name = $sub->get_name();
|
||||
if ($sub->meta_writeable()) {
|
||||
$metasubdefs[$name . '_' . $type] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->metasubdefs = $metasubdefs;
|
||||
|
||||
$sql = 'SELECT record_id, coll_id, jeton
|
||||
FROM record WHERE (jeton & ' . JETON_WRITE_META . ' > 0)';
|
||||
|
||||
$stmt = $connbas->prepare($sql);
|
||||
$stmt->execute();
|
||||
$rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
protected function processOneContent(databox $databox, $row)
|
||||
{
|
||||
$record_id = $row['record_id'];
|
||||
$jeton = $row['jeton'];
|
||||
|
||||
$record = new record_adapter($this->dependencyContainer, $this->sbas_id, $record_id);
|
||||
|
||||
$type = $record->get_type();
|
||||
$subdefs = $record->get_subdefs();
|
||||
|
||||
$tsub = array();
|
||||
|
||||
foreach ($subdefs as $name => $subdef) {
|
||||
$write_document = (($jeton & JETON_WRITE_META_DOC) && $name == 'document');
|
||||
$write_subdef = (($jeton & JETON_WRITE_META_SUBDEF) && isset($this->metasubdefs[$name . '_' . $type]));
|
||||
|
||||
if (($write_document || $write_subdef) && $subdef->is_physically_present()) {
|
||||
$tsub[$name] = $subdef->get_pathfile();
|
||||
}
|
||||
}
|
||||
|
||||
$metadatas = new Metadata\MetadataBag();
|
||||
|
||||
if ($record->get_uuid()) {
|
||||
$metadatas->add(
|
||||
new Metadata\Metadata(
|
||||
new Tag\XMPExif\ImageUniqueID(),
|
||||
new Value\Mono($record->get_uuid())
|
||||
)
|
||||
);
|
||||
$metadatas->add(
|
||||
new Metadata\Metadata(
|
||||
new Tag\ExifIFD\ImageUniqueID(),
|
||||
new Value\Mono($record->get_uuid())
|
||||
)
|
||||
);
|
||||
$metadatas->add(
|
||||
new Metadata\Metadata(
|
||||
new Tag\IPTC\UniqueDocumentID(),
|
||||
new Value\Mono($record->get_uuid())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($record->get_caption()->get_fields() as $field) {
|
||||
|
||||
$meta = $field->get_databox_field();
|
||||
/* @var $meta \databox_field */
|
||||
|
||||
$datas = $field->get_values();
|
||||
|
||||
if ($meta->is_multi()) {
|
||||
$values = array();
|
||||
foreach ($datas as $data) {
|
||||
$values[] = $data->getValue();
|
||||
}
|
||||
|
||||
$value = new Value\Multi($values);
|
||||
} else {
|
||||
$data = array_pop($datas);
|
||||
$value = $data->getValue();
|
||||
|
||||
$value = new Value\Mono($value);
|
||||
}
|
||||
|
||||
$metadatas->add(
|
||||
new Metadata\Metadata($meta->get_tag(), $value)
|
||||
);
|
||||
}
|
||||
|
||||
$this->dependencyContainer['exiftool.writer']->reset();
|
||||
foreach ($tsub as $name => $file) {
|
||||
|
||||
$this->dependencyContainer['exiftool.writer']->erase($name != 'document' || $this->clear_doc, true);
|
||||
|
||||
try {
|
||||
$this->dependencyContainer['exiftool.writer']->write($file, $metadatas);
|
||||
|
||||
$this->log(sprintf('meta written for sbasid=%1$d - recordid=%2$d (%3$s)', $this->sbas_id, $record_id, $name), self::LOG_INFO);
|
||||
} catch (\PHPExiftool\Exception\Exception $e) {
|
||||
$this->log(sprintf('meta NOT written for sbasid=%1$d - recordid=%2$d (%3$s) because "%s"', $this->sbas_id, $record_id, $name, $e->getMessage()), self::LOG_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function flushRecordsSbas()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function postProcessOneContent(databox $databox, $row)
|
||||
{
|
||||
$connbas = $databox->get_connection();
|
||||
|
||||
$sql = 'UPDATE record SET jeton=jeton & ~' . JETON_WRITE_META . '
|
||||
WHERE record_id = :record_id';
|
||||
$stmt = $connbas->prepare($sql);
|
||||
$stmt->execute(array(':record_id' => $row['record_id']));
|
||||
$stmt->closeCursor();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*/
|
||||
public static function getDefaultSettings(Configuration $config, array $params = array())
|
||||
{
|
||||
$period = isset($params['period']) ? $params['period'] : self::MINPERIOD;
|
||||
$maxrecs = isset($params['maxrecs']) ? $params['maxrecs'] : self::MINRECS;
|
||||
$maxmegs = isset($params['maxmegs']) ? $params['maxmegs'] : self::DEFMEGS;
|
||||
|
||||
return sprintf('<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tasksettings>
|
||||
<period>%s</period>
|
||||
<maxrecs>%s</maxrecs>
|
||||
<maxmegs>%s</maxmegs>
|
||||
<cleardoc>0</cleardoc>
|
||||
</tasksettings>',
|
||||
min(max($period, self::MINPERIOD), self::MAXPERIOD),
|
||||
min(max($maxrecs, self::MINRECS), self::MAXRECS),
|
||||
min(max($maxmegs, self::MINMEGS), self::MAXMEGS)
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user