php code like transaction in database? - php

I have certain code that I want to be run by only one user at a time. I don't want to make son complex lock/session relied system, I just wish to delay the users request our to return some message to try again.
The code is actually ssh/powershell connection so I want to isolate it.
It's there any handy way to do that??
I forgot mention it's laravel/php code.

You need to acquire a "lock" of some sort. If there is no lock, no one is accessing anything. If there is a lock, someone is accessing something and the rest should wait. The easiest way is to implement this using files and acquiring an exclusive lock. I'll post an example class (untested) and example usage. You can derive a working example using the sample code that follows:
class MyLockClass
{
protected $fh = null;
protected $file_path = '';
public function __construct($file_path)
{
$this->file_path = $file_path;
}
public function acquire()
{
$handler = $this->getFileHandler();
return flock($handler, LOCK_EX);
}
public function release($close = false)
{
$handler = $this->getFileHandler();
return flock($handler, LOCK_UN);
if($close)
{
fclose($handler);
$this->fh = null;
}
}
protected function acquireLock($handler)
{
return flock($handler, LOCK_EX);
}
protected function getFileHandler()
{
if(is_null($this->fh))
{
$this->fh = fopen($this->file_path, 'c');
if($this->fh === false)
{
throw new \Exception(sprintf("Unable to open the specified file: %s", $this->file_path));
}
}
return $this->fh;
}
}
Usage:
$lock = new MyLockClass('/my/file/path');
try
{
if($lock->acquire())
{
// Do stuff
$lock->release(true);
}
else
{
// Someone is working, either wait or disconnect the user
}
}
catch(\Exception $e)
{
echo "An error occurred!<br />";
echo $e->getMessage();
}

Related

Check if the files have been uploaded to server with php slim 3

Hi have the following code in slim to save file
I want to make sure the files have been uploaded to the server and only then to return true. or false
how can I do that with Slim or PHP?
Result of file log always null for nonreason and the file are being uploaded
public function saveFiles(Array $files, $location) {
try
{
/** #var UploadedFileInterface $file */
foreach ($files as $file) {
$fileLog = $file->moveTo($location . DIRECTORY_SEPARATOR . $file->getFilename());
}
return true;
}
catch(\Exception $e) {
throw new Exception($e->getMessage());
According to slim implementaion of this PSR, it always throws exception if something went wrong while file is being uploaded.
I don't know whether you throw another Exception for a reason, but you can process it something like:
public function saveFiles(Array $files, $location) {
$result = true;
foreach ($files as $file) {
try {
$fileLog = $file->moveTo($location . DIRECTORY_SEPARATOR . $file->getFilename());
} catch(\Exception $e) {
// Exception on file uploading happened, but
// we still continue loading other files
$result = false;
// Or just `return false;` if you don't want
// to upload other files if exception happened
// return false;
}
}
return $result;
}
Of course, this method can be extended to collect exceptions' messages and return them.

How to check if sqlite database file is writable by the web process in my Yii2 application?

I am developing an Yii2 application and at times, the Sqlite3 file which I use for database, becomes "read only" (due to other stuff happening on the server) and users are getting nasty PHP exception errors instead of a nicely displayed error message.
I am trying to use the "beforeSave()" function to check if the databse is writable, but I don't know the best way to check if the web process (www-data) has write access to it.
Anyone any ideas?
I have the following two functions in my base model:
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
// Check if database is writable
if($this->attemptDBWrite())
return true;
else
{
\Yii::$app->getSession()->setFlash('error', 'Database is not writable by the application user');
return false;
}
} else {
return false;
}
}
And the "attemptDBWrite()" function:
public function attemptDBWrite()
{
try {
$connection = \Yii::$app->db;
// SOME CODE NEEDED HERE TO CHECK <<<=========
} catch (\yii\db\Exception $e) {
\Yii::$app->getSession()->setFlash('error', var_dump($e));
return false;
}
}
public function attemptDBWrite()
{
try {
$connection = \Yii::$app->db;
if (is_writable($database_source_path)) {
return false;
}
} catch (\yii\db\Exception $e) {
\Yii::$app->getSession()->setFlash('error', var_dump($e));
return false;
}
}
$database_source_path - is path of sqlite database file

Exceptions handler

I have to develop an exception handler that should handle like 5 different type of exceptions. Let's call them simply Ex1, Ex2, Ex3...
I though of doing a single class called ExHandler which will be instantiated like this:
...
} catch (Ex1 $e) { $h = new ExHandler($e); $h->render(); }
catch (Ex2 $e) { $h = new ExHandler($e); $h->render(); }
catch (Ex3 $e) { $h = new ExHandler($e); $h->render(); }
...
And inside ExHandler manage each different Exception differently using $e instance of Ex1, $e instance of Ex2, $e instance of Ex3...
But It doesn't seems a very good practice to me. Is it good? Is there any other way of doing this?
Should I create an Ex1Handler, Ex2Handler, Ex3Handler...? My S.O.L.I.D spirit tells me something is just wrong here. What is it?
I need to note before I answer this, that procedural programmers will look at this and think it's dumb :) but I can live with that, this is assuming an OOP application with HTML templating that outputs after the output_buffer is cleaned.
I always create a try/catch block encompassing the majority of my code in one call usually at the point where I start requiring other files as well as starting an output_buffer whilst in development.
ob_start();
try {
switch($appPage) {
case('work'):
require_once('im_bored_at_work.php');
break;
case('home'):
require_once('im_a_little_less_bored_at_home.php');
break;
default:
require_once('on_the_fence.php');
}
} catch (Exception $e) {
// Handle exception caught and apply formatting
}
$devOut = ob_get_contents();
ob_end_flush();
To give an example how I would handle the multiple exceptions you need to catch with a custom class
class CustomExceptionHandler extends Exception {
private $msg;
private $code;
private $otherVars;
public function __construct($msg,$code=0,$otherDebugVar=null){
$this->msg = $msg != null ? $msg : "An unknown exception was thrown";
$this->code = $code;
$this->otherVars = $otherDebugVar;
parent::__construct($msg,$code);
}
public function getOtherVars() {
return $this->otherVars;
}
}
The idea is to just keep the custom information within the exception object, and when you rethrow the exception at the end of a try/catch block as a standard exception you include the formatted custom message, it shouldn't really matter now which Exception handler picked up the original exception as all the info you will need will come downstream and be caught in the original try / catch block.
class BasicTemplate {
private $template;
private $path;
private $contents;
public function __construct($template, $path) {
$this->template = $template;
$this->path = $path;
$this->buildTemplate();
}
private function buildTemplate() {
if ($contents = #file_get_contents($this->path . $this->template)) {
$this->contents = $contents;
} else {
$e = new CustomExceptionHandler("Message",2,$this->path . $this->template);
// Do whatever else you want to do with custom exception handling class
throw $e;
}
}
}
Now you need to catch your exception and rethrow it:
try {
$html = new BasicTemplate($temp,$path);
} catch {CustomExceptionHandler $e) {
throw new Exception("Message: {$e->getMessage()} Other Info: {$e->getOtherVars()}",$e->getCode());
}
That's the rough idea anyhow, hope it helps.

PHP fopen succeeding for one script but not another

My following method uses an array of data $FDFData to create an FDF file:
public function writeFDFFile($FDFData) {
$fdf_file = time().'.fdf';
$fdf = $this->createFDF(PDF_FORM, $FDFData);
// write the file out
if($fp=fopen($fdf_file,'w')) {
fwrite($fp,$fdf,strlen($fdf));
} else {
throw new Exception('Unable to create file: '.$fdf_file);
}
fclose($fp);
return $fdf_file;
}
One of my scripts runs absolutely fine:
require_once('PDFPrinter.php');
try {
$printer = new PDFPrinter();
$FDFData = $printer->assembleFDFData(9);
$fdf_file = $printer->writeFDFFile($FDFData);
$printer->downloadFile($fdf_file);
}catch(Exception $e) {
echo $e->getMessage();
}
but I can't get my test code to run because I get a:
Unexpected PHP error [fopen(1315558352.fdf) [<a href='function.fopen'>function.fopen</a>]: failed to open stream: Permission denied]
error thrown:
require_once(dirname(__FILE__) . '/simpletest/autorun.php');
require_once(dirname(__FILE__) . '/../PDFPrinter.php');
class PDFPrinterTest extends UnitTestCase {
private $printer;
private $FDFData;
function setUp() {
$this->printer = new PDFPrinter();
$this->FDFData = $this->printer->assembleFDFData(5);
}
function testException() {
try {
$this->printer->writeFDFFile($this->FDFData);
$this-assertTrue(true);
} catch(Exception $e) {
$this->assertTrue(false);
}
}
}
Both scripts are run in directories with the correct permissions. I am running my test scripts through the browser as well, so it's not that I have a different environment.
I'm stuck as to how to proceed to find the issue really.
My directory structure:
HOME - PDFPrinter.php
|
-----tests - PDFPrinterTest.php
|
------simpletest - autorun.php
Any suggestions as to how I could find the issue?
Many thanks
Update
I have tried changing my test class so that the only test function in there is:
function testWrite() {
try {
$name = "testing.txt";
if($fp=fopen($name, 'w')) {
fwrite($fp, "Blah");
} else {
throw new Exception("Nope.");
}
$this->pass("All good");
} catch(Exception $e) {
$this->fail("Not good");
}
}
but the exception is still thrown with the warning.
Yet a very simple script run from the same directory works fine:
$name = "Test.txt";
if($fp=fopen($name, 'w')) {
fwrite($fp, "Working");
} else {
throw new Exception("Nope.");
}
fclose($fp);
that will actually create and write to the file.
Finally found the solution which was that the file name needed to be the full absolute address in order for it to work in both scripts for some reason. This was suggested in one of the answers for this SO question which I quote below:
Use fopen($_SERVER['DOCUMENT_ROOT'].'test.txt','a+');
so for my code, I have used:
if($fp=fopen($_SERVER['DOCUMENT_ROOT'].$name, 'w')) {
fwrite($fp, "Working");
}
In your test
fwrite("Blah");
should be
fwrite($fp, "Blah");
I'm not sure what the problem in the original code is though.
failed to open stream: Permission denied
There is one important programmer's skill every developer ought to master.
Here it is:
To trust your eyes
If your PHP telling you that permission is denied - so it is. Just doble-check it. It is not a big deal yet noone can do it for you.

PHP Exceptions in Classes

I'm writing a web application (PHP) for my friend and have decided to use my limited OOP training from Java.
My question is what is the best way to note in my class/application that specific critical things failed without actually breaking my page.
My problem is I have an Object "SummerCamper" which takes a camper_id as it's argument to load all of the necessary data into the object from the database. Say someone specifies a camper_id in the query string that does not exist, I pass it to my objects constructor and the load fails. I don't currently see a way for me to just return false from the constructor.
I have read I could possibly do this with Exceptions, throwing an exception if no records are found in the database or if some sort of validation fails on input of the camper_id from the application etc.
However, I have not really found a great way to alert my program that the Object Load has failed. I tried returning false from within the CATCH but the Object still persists in my php page. I do understand I could put a variable $is_valid = false if the load fails and then check the Object using a get method but I think there may be better ways.
What is the best way of achieving the essential termination of an object if a load fails? Should I load data into the object from outside the constructor? Is there some sort of design pattern that I should look into?
Any help would be appreciated.
function __construct($camper_id){
try{
$query = "SELECT * FROM campers WHERE camper_id = $camper_id";
$getResults = mysql_query($query);
$records = mysql_num_rows($getResults);
if ($records != 1) {
throw new Exception('Camper ID not Found.');
}
while($row = mysql_fetch_array($getResults))
{
$this->camper_id = $row['camper_id'];
$this->first_name = $row['first_name'];
$this->last_name = $row['last_name'];
$this->grade = $row['grade'];
$this->camper_age = $row['camper_age'];
$this->camper_gender = $row['gender'];
$this->return_camper = $row['return_camper'];
}
}
catch(Exception $e){
return false;
}
}
A constructor in PHP will always return void. This
public function __construct()
{
return FALSE;
}
will not work. Throwing an Exception in the constructor
public function __construct($camperId)
{
if($camperId === 1) {
throw new Exception('ID 1 is not in database');
}
}
would terminate script execution unless you catch it somewhere
try {
$camper = new SummerCamper(1);
} catch(Exception $e) {
$camper = FALSE;
}
You could move the above code into a static method of SummerCamper to create instances of it instead of using the new keyword (which is common in Java I heard)
class SummerCamper
{
protected function __construct($camperId)
{
if($camperId === 1) {
throw new Exception('ID 1 is not in database');
}
}
public static function create($camperId)
{
$camper = FALSE;
try {
$camper = new self($camperId);
} catch(Exception $e) {
// uncomment if you want PHP to raise a Notice about it
// trigger_error($e->getMessage(), E_USER_NOTICE);
}
return $camper;
}
}
This way you could do
$camper = SummerCamper::create(1);
and get FALSE in $camper when the $camper_id does not exist. Since statics are considered harmful, you might want to use a Factory instead.
Another option would be to decouple the database access from the SummerCamper altogether. Basically, SummerCamper is an Entity that should only be concerned about SummerCamper things. If you give it knowledge how to persist itself, you are effectively creating an ActiveRecord or RowDataGateway. You could go with a DataMapper approach:
class SummerCamperMapper
{
public function findById($id)
{
$camper = FALSE;
$data = $this->dbAdapter->query('SELECT id, name FROM campers where ?', $id);
if($data) {
$camper = new SummerCamper($data);
}
return $camper;
}
}
and your Entity
class SummerCamper
{
protected $id;
public function __construct(array $data)
{
$this->id = data['id'];
// other assignments
}
}
DataMapper is somewhat more complicated but it gives you decoupled code which is more maintainable and flexible in the end. Have a look around SO, there is a number of questions on these topics.
To add to the others' answers, keep in mind that you can throw different types of exceptions from a single method and handle them each differently:
try {
$camper = new SummerCamper($camper_id);
} catch (NoRecordsException $e) {
// handle no records
} catch (InvalidDataException $e) {
// handle invalid data
}
Throwing an exception from the constructor is probably the right approach. You can catch this in an appropriate place, and take the necessary action (e.g. display an error page). Since you didn't show any code, it's not clear where you were catching your exception or why that didn't seem to work.
try {
$camper = new SummerCamper($id);
$camper->display();
} catch (NonexistentCamper $ex) {
handleFailure($ex);
}

Categories