<?php 
 
namespace JLaso\ToolsLib; 
 
/** 
 * Both main classes must extends from this one, in order to have in one place all the stuff related with 
 * the status control file 
 */ 
abstract class CommonAbstract 
{ 
    const STATUS_FILE = "status.pid"; 
 
    /** @var  string */ 
    protected $dataFolder; 
    /** @var bool  */ 
    protected $debug; 
    /** @var  string */ 
    protected $file; 
    /** @var  string */ 
    protected $task; 
    /** @var string  */ 
    protected $oldFile; 
 
    protected $handle = null; 
 
    const DONT_UNLOCK = true; 
 
    /** 
     * CommonAbstract constructor. 
     * @param string $task 
     * @param bool $debug 
     * @internal param string $dataFolder 
     */ 
    public function __construct($task, $debug = false) 
    { 
        $this->task = $task; 
        $this->dataFolder = dirname(dirname(__FILE__)).'/data'; 
        $this->debug = $debug; 
        if (!file_exists($this->dataFolder)) { 
            mkdir ($this->dataFolder, 0777); 
        } 
        $this->file = $this->dataFolder.'/'.$task.'-'.self::STATUS_FILE; 
        $this->oldFile = $this->dataFolder.'/'.$task.'-'.self::STATUS_FILE.'.old'; 
    } 
 
    /** 
     * @return string 
     */ 
    public function getStatusFile() 
    { 
        return $this->file; 
    } 
 
    /** 
     * @return bool 
     */ 
    public function existsStatusFile() 
    { 
        return file_exists($this->file); 
    } 
 
    /** 
     * the mechanism of control of the task process is the status file, to notice to subsequents calls that 
     * the process is started already have to create this file, and on it is written the status of the 
     * different tasks 
     */ 
    public function touchStatusFile() 
    { 
        if (file_exists($this->oldFile)){ 
            rename($this->oldFile, $this->file); 
        }else { 
            touch($this->file); 
        } 
        chmod($this->file, 0777); 
    } 
 
    /** 
     * get (in raw) the content of the status file 
     * 
     * @return string 
     */ 
    public function getStatusFileContent($dontUnlock = false) 
    { 
        if ($this->handle == null){ 
            $this->lockStatusFile(true); 
        } 
        $content = fread($this->handle, filesize($this->file)); 
        if (!$dontUnlock){ 
            $this->unlockStatusFile(); 
        } 
        return $content; 
    } 
 
    public function lockStatusFile($read = true) 
    { 
        $this->handle = fopen($this->file, "r+"); 
        while (!flock($this->handle, LOCK_EX | LOCK_NB)){ usleep(rand($read ? 100 : 1000,$read ? 500 :1500)); } 
    } 
 
    public function unlockStatusFile() 
    { 
        flock($this->handle, LOCK_UN); 
        fclose($this->handle); 
        $this->handle = null; 
    } 
 
    /** 
     * saves into the status file the content passed 
     * 
     * @param string $content 
     */ 
    public function putStatusFileContent($content) 
    { 
        if ($this->handle == null){ 
            $this->lockStatusFile(); 
        } 
        ftruncate ($this->handle, 0); 
        fwrite($this->handle, $content); 
        fflush($this->handle); 
        usleep(1000); 
        $this->unlockStatusFile(); 
    } 
 
    /** 
     * when the main process finish have to call this method in order to allow subsequents calls, 
     * be in mind that the status file is the mechanism that allow this system to know if the task 
     * large process is still running or not 
     */ 
    public function freeStatusFile() 
    { 
        unlink($this->file); 
    } 
 
    /** 
     * In the even the main process hangs it must call this in order to allow next process calls. 
     */ 
    public function hangOn() 
    { 
        if ($this->existsStatusFile()) { 
            @unlink($this->oldFile); 
            rename($this->file, $this->oldFile); 
            chmod($this->file, 0777); 
        } 
    } 
}
 
 |