php slim detect client abort (HTTP) - php

In slim framework V3 how can I detect if the client closed the connection ?
I have tried:
ignore_user_abort(false);
and tried checking connection_status() and connection_aborted() in a loop with no luck.
php 5.6.12

It depends not from Slim but from PHP in general. PHP close connection just after execution script.
If you want create persistance connection you need to look to long polling connection.
http://phptrends.com/dig_in/php-long-polling

It seems one need to output something from php and then call ob_flush() because php only handles errors from the browser. Here's a way to do it without outputing anything, which will work fine for long-polling scenarios:
/* returns ESTABLISHED, CLOSE_WAIT, LAST_ACK, etc */
function getConnectionStatus() {
$remote_ip = $_SERVER['REMOTE_ADDR']?:($_SERVER['HTTP_X_FORWARDED_FOR']?:$_SERVER['HTTP_CLIENT_IP']);
$remote_port=$_SERVER['REMOTE_PORT'];
$cmd="netstat -tn | fgrep ' $remote_ip:$remote_port '";
$pfp=popen($cmd,"r");
$buf = fgets($pfp, 1024);
pclose($pfp);
$buf=preg_replace('!\s+!', ' ', $buf); //remove multiple spaces
$buf=trim($buf);
$buf_r=explode(" ",$buf);
if (count($buf_r)) {
$state=$buf_r[count($buf_r)-1];
return trim($state);
}
return "NOTFOUND";
}
Use it as follows:
while(...) {
/* ... longpolling check code here ...*/
if (getConnectionStatus() != "ESTABLISHED") {
break;
}
}

Related

Websocket server using php for flutter app [duplicate]

I am looking for a simple code to create a WebSocket server. I found phpwebsockets but it is outdated now and doesn't support the newest protocol. I tried updating it myself but it doesn't seem to work.
#!/php -q
<?php /* >php -q server.php */
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
$master = WebSocket("localhost",12345);
$sockets = array($master);
$users = array();
$debug = false;
while(true){
$changed = $sockets;
socket_select($changed,$write=NULL,$except=NULL,NULL);
foreach($changed as $socket){
if($socket==$master){
$client=socket_accept($master);
if($client<0){ console("socket_accept() failed"); continue; }
else{ connect($client); }
}
else{
$bytes = #socket_recv($socket,$buffer,2048,0);
if($bytes==0){ disconnect($socket); }
else{
$user = getuserbysocket($socket);
if(!$user->handshake){ dohandshake($user,$buffer); }
else{ process($user,$buffer); }
}
}
}
}
//---------------------------------------------------------------
function process($user,$msg){
$action = unwrap($msg);
say("< ".$action);
switch($action){
case "hello" : send($user->socket,"hello human"); break;
case "hi" : send($user->socket,"zup human"); break;
case "name" : send($user->socket,"my name is Multivac, silly I know"); break;
case "age" : send($user->socket,"I am older than time itself"); break;
case "date" : send($user->socket,"today is ".date("Y.m.d")); break;
case "time" : send($user->socket,"server time is ".date("H:i:s")); break;
case "thanks": send($user->socket,"you're welcome"); break;
case "bye" : send($user->socket,"bye"); break;
default : send($user->socket,$action." not understood"); break;
}
}
function send($client,$msg){
say("> ".$msg);
$msg = wrap($msg);
socket_write($client,$msg,strlen($msg));
}
function WebSocket($address,$port){
$master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
socket_bind($master, $address, $port) or die("socket_bind() failed");
socket_listen($master,20) or die("socket_listen() failed");
echo "Server Started : ".date('Y-m-d H:i:s')."\n";
echo "Master socket : ".$master."\n";
echo "Listening on : ".$address." port ".$port."\n\n";
return $master;
}
function connect($socket){
global $sockets,$users;
$user = new User();
$user->id = uniqid();
$user->socket = $socket;
array_push($users,$user);
array_push($sockets,$socket);
console($socket." CONNECTED!");
}
function disconnect($socket){
global $sockets,$users;
$found=null;
$n=count($users);
for($i=0;$i<$n;$i++){
if($users[$i]->socket==$socket){ $found=$i; break; }
}
if(!is_null($found)){ array_splice($users,$found,1); }
$index = array_search($socket,$sockets);
socket_close($socket);
console($socket." DISCONNECTED!");
if($index>=0){ array_splice($sockets,$index,1); }
}
function dohandshake($user,$buffer){
console("\nRequesting handshake...");
console($buffer);
//list($resource,$host,$origin,$strkey1,$strkey2,$data)
list($resource,$host,$u,$c,$key,$protocol,$version,$origin,$data) = getheaders($buffer);
console("Handshaking...");
$acceptkey = base64_encode(sha1($key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
$upgrade = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $acceptkey\r\n";
socket_write($user->socket,$upgrade,strlen($upgrade));
$user->handshake=true;
console($upgrade);
console("Done handshaking...");
return true;
}
function getheaders($req){
$r=$h=$u=$c=$key=$protocol=$version=$o=$data=null;
if(preg_match("/GET (.*) HTTP/" ,$req,$match)){ $r=$match[1]; }
if(preg_match("/Host: (.*)\r\n/" ,$req,$match)){ $h=$match[1]; }
if(preg_match("/Upgrade: (.*)\r\n/",$req,$match)){ $u=$match[1]; }
if(preg_match("/Connection: (.*)\r\n/",$req,$match)){ $c=$match[1]; }
if(preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$req,$match)){ $key=$match[1]; }
if(preg_match("/Sec-WebSocket-Protocol: (.*)\r\n/",$req,$match)){ $protocol=$match[1]; }
if(preg_match("/Sec-WebSocket-Version: (.*)\r\n/",$req,$match)){ $version=$match[1]; }
if(preg_match("/Origin: (.*)\r\n/",$req,$match)){ $o=$match[1]; }
if(preg_match("/\r\n(.*?)\$/",$req,$match)){ $data=$match[1]; }
return array($r,$h,$u,$c,$key,$protocol,$version,$o,$data);
}
function getuserbysocket($socket){
global $users;
$found=null;
foreach($users as $user){
if($user->socket==$socket){ $found=$user; break; }
}
return $found;
}
function say($msg=""){ echo $msg."\n"; }
function wrap($msg=""){ return chr(0).$msg.chr(255); }
function unwrap($msg=""){ return substr($msg,1,strlen($msg)-2); }
function console($msg=""){ global $debug; if($debug){ echo $msg."\n"; } }
class User{
var $id;
var $socket;
var $handshake;
}
?>
and the client:
var connection = new WebSocket('ws://localhost:12345');
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
If there is anything wrong in my code can you help me fix it? Console in Firefox says:
Firefox can't establish a connection to the server at ws://localhost:12345/.
I was in the same boat as you recently, and here is what I did:
I used the phpwebsockets code as a reference for how to structure the server-side code. (You seem to already be doing this, and as you noted, the code doesn't actually work for a variety of reasons.)
I used PHP.net to read the details about every socket function used in the phpwebsockets code. By doing this, I was finally able to understand how the whole system works conceptually. This was a pretty big hurdle.
I read the actual WebSocket draft. I had to read this thing a bunch of times before it finally started to sink in. You will likely have to go back to this document again and again throughout the process, as it is the one definitive resource with correct, up-to-date information about the WebSocket API.
I coded the proper handshake procedure based on the instructions in the draft in #3. This wasn't too bad.
I kept getting a bunch of garbled text sent from the clients to the server after the handshake and I couldn't figure out why until I realized that the data is encoded and must be unmasked. The following link helped me a lot here: (original link broken) Archived copy.
Please note that the code available at this link has a number of problems and won't work properly without further modification.
I then came across the following SO thread, which clearly explains how to properly encode and decode messages being sent back and forth: How can I send and receive WebSocket messages on the server side?
This link was really helpful. I recommend consulting it while looking at the WebSocket draft. It'll help make more sense out of what the draft is saying.
I was almost done at this point, but had some issues with a WebRTC app I was making using WebSocket, so I ended up asking my own question on SO, which I eventually solved: What is this data at the end of WebRTC candidate info?
At this point, I pretty much had it all working. I just had to add some additional logic for handling the closing of connections, and I was done.
That process took me about two weeks total. The good news is that I understand WebSocket really well now and I was able to make my own client and server scripts from scratch that work great.
Hopefully the culmination of all that information will give you enough guidance and information to code your own WebSocket PHP script.
Good luck!
Edit: This edit is a couple of years after my original answer, and while I do still have a working solution, it's not really ready for sharing. Luckily, someone else on GitHub has almost identical code to mine (but much cleaner), so I recommend using the following code for a working PHP WebSocket solution:
https://github.com/ghedipunk/PHP-Websockets/blob/master/websockets.php
Edit #2: While I still enjoy using PHP for a lot of server-side related things, I have to admit that I've really warmed up to Node.js a lot recently, and the main reason is because it's better designed from the ground up to handle WebSocket than PHP (or any other server-side language). As such, I've found recently that it's a lot easier to set up both Apache/PHP and Node.js on your server and use Node.js for running the WebSocket server and Apache/PHP for everything else. And in the case where you're on a shared hosting environment in which you can't install/use Node.js for WebSocket, you can use a free service like Heroku to set up a Node.js WebSocket server and make cross-domain requests to it from your server. Just make sure if you do that to set your WebSocket server up to be able to handle cross-origin requests.
As far as I'm aware Ratchet is the best PHP WebSocket solution available at the moment. And since it's open source you can see how the author has built this WebSocket solution using PHP.
I've searched the minimal solution possible to do PHP + WebSockets during hours, until I found this article:
Super simple PHP WebSocket example
It doesn't require any third-party library.
Here is how to do it: create a index.html containing this:
<html>
<body>
<div id="root"></div>
<script>
var host = 'ws://<<<IP_OF_YOUR_SERVER>>>:12345/websockets.php';
var socket = new WebSocket(host);
socket.onmessage = function(e) {
document.getElementById('root').innerHTML = e.data;
};
</script>
</body>
</html>
and open it in the browser, just after you have launched php websockets.php in the command-line (yes, it will be an event loop, constantly running PHP script), with this websockets.php file.
I was in your shoes for a while and finally ended up using node.js, because it can do hybrid solutions like having web and socket server in one. So php backend can submit requests thru http to node web server and then broadcast it with websocket. Very efficiant way to go.
Need to convert the the key from hex to dec before base64_encoding and then send it for handshake.
$hashedKey = sha1($key. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true);
$rawToken = "";
for ($i = 0; $i < 20; $i++) {
$rawToken .= chr(hexdec(substr($hashedKey,$i*2, 2)));
}
$handshakeToken = base64_encode($rawToken) . "\r\n";
$handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $handshakeToken\r\n";

PHP Server-Sent Events: trigger custom event from another file

I need to notify the client(s) whether some of the clients made changes on the database. I consider it to be a single-directional connection (it's only the server who sends events), so I do not need WebSockets.
The logic is as follows:
Client fetches the common API (let's say /api.php?action=add&payload=...), and with this fetch the change on DB is being made.
After mysqli_result returned true, the server-sent event should be triggered to notify other clients (or their service-workers) about DB changed.
The caveats are:
My SSE logic is placed on a separate file (/sse.php) to not make a mess in API logic and to listen to separate endpoint clientside. So I need to trigger SSE from api.php and push the result from there to all clients.
In sse.php I defined a function for pushing which takes the message from api.php as a param. Whatever I've tried, this function was never called.
I strongly want to avoid making daemons and any kind of infinite loops. But without them, the connection for the clientside listener (eventSource) closes and reopens every 3 seconds.
The current state of this all:
api.php
<?php
header("Access-Control-Allow-Origin: *");
include 'connection.php'; // mysqli credentials and connection object
include_once 'functions.php'; // logics
$action = isset($_GET['a']) ? $_GET['a'] : 'fail';
switch ($action) {
case "add":
$result = api__handle_add(); // adds data to DB and returns stringified success/failure result
require "./sse.php"; // file with SSE logic with ev__ namespace
ev__send_data($result); // this defined function should send message to clients
break;
// ...
case "testquery":
require "./sse.php";
ev__send_data("Test event!!! Ololo");
break;
case "fail": default:
header('HTTP/1.1 403 Forbidden', true, 403);
}
sse.php
<?php
header("Access-Control-Allow-Origin: *");
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
header("Connection: keep-alive");
$_fired = false; // flag checking for is anything happening right now
while (1) { // the infinite loop I strongly want to get rid of
if (!$_fired) {
usleep(5000); // nothing to send if nothing is fired, but I should keep the connection alive somehow
} else {
// here I should call 'ev__send_data($message_from_api_php)'
// thus I require this file to `api.php` and try to call 'ev__send_data' from there.
}
ob_flush();
flush();
}
function ev__send_data(string $msg) {
global $_fired;
$_fired = true;
echo "data: $msg". PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
usleep(1000);
$_fired = false;
}
The clientside implementation is typical, with onopen, onerror and onmessage handlers of eventSource. I think I don't need to take it here as it has no differences from thousands of examples I've seen here on SO and at other sources.
To conclude: I want to trigger SSE's from outside SSE-file and pass pieces of data from outside, and I want to get rid of while (1) {} and emit events only when something really happens. I've come across thousands of tutorials and SO topics, and found nothing but typical "tutorial cases" about how to send server time to the client every n seconds and stuff. And I think I don't need WebSockets (considering that my local dev environment is Win10 + XAMPP, my prod environment will be something Linux-like and I don't think I can implement my own WebSocket without third-party dependencies which I don't want to install).
Do I have any chance?
EDIT
I found a little different approach. Now my server event generation depends on boolean flags that were settled in MySQL database in separate flags table. When I need an event to be emitted, API changes definite flag (for the very this example, when one client had submitted some changes in DB, API also makes the query to flags table and sets flag DB_CHANGED to 1). And sse.php makes query to flags table each iteration of the infinite loop (every 5 seconds) and emits events depending on the flags' state, and after emitting, sets the corresponding flag to 0 via one more query. This kinda works.
Example of current sse.php:
<?php
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
require_once "connection.php"; // mysqli connection object
set_time_limit(600);
stream();
function stream() {
global $connection;
while (1) { // oh that infinite loop
$flags = []; // there will be fetched flags from DB
$flags_sqli = $connection->query("SELECT * FROM `flags`");
while ($flag = $flags_sqli->fetch_assoc()) {
$flags[$flag['key_']] = ev__h__to_bool_or_string($flag['value_']);
}
if ($flags['ON_TEST']) {
ev__send_data("Test event!!! Ololo");
ev__update_flag("ON_TEST", "0");
} elseif ($flags['ON_DB_ADD']) {
ev__handle_add();
} else {
echo PHP_EOL; // keep connection alive - push single "end of line"
}
ob_flush();
flush();
sleep(5); // interval per iteration - 5 secs
}
}
function ev__send_data(string $msg) : void {
echo "data: ".date("d-m-Y")." ".date("H:i:s").PHP_EOL;
echo "data: $msg".PHP_EOL;
echo PHP_EOL;
}
function ev__handle_add() : void {
global $connection;
$table = $connection->query('SELECT `value_` FROM `flags` WHERE `key_` = "LAST_ADDED_TABLE"')->fetch_row()[0];
$query = "SELECT * FROM `banners_".$table."` WHERE `id` = (SELECT MAX(`id`) FROM `banners_".$table."`)";
$row = $connection->query($query)->fetch_assoc();
echo "event: db_add_row".PHP_EOL;
echo 'data: { "manager": '.$row['manager_id'].', "banner_name": "'.$row['name'].'", "time": "'.date("d-m-Y").' '.date("H:i:s").'" }'.PHP_EOL;
echo PHP_EOL;
ev__update_flag("ON_DB_ADD", "0");
}
function ev__update_flag(string $key, string $value) {
global $connection;
$query = "UPDATE `flags` SET `value_` = '$value' WHERE `flags`.`key_` = '$key';";
$connection->query($query);
}
function ev__h__to_bool_or_string($value) {
return $value === "0" || $value === "1"
? boolval(intval($value))
: $value;
}
Therefore, I didn't get rid of the infinite loop. Considering that there will be a very few concurrent connections (max 3-5 sessions per one time) (when in prod), this very case should not make performance troubles. But what if it would be some kind of hard-loaded service? As an answer, I want to see optimization tips for the case of Server-Sent Events.

Running a php script via ajax, but only if it is not already running

My intention is this.
My client.html calls a php script check.php via ajax. I want check.php to check if another script task.php is already being run. If it is, I do nothing. If it is not, I need to run it in the background.
I have an idea what I want to do, but am unsure how to do it.
Part A. I know how to call check.php via ajax.
Part B. In check.php I might need to run task.php. I think I need something like:
$PID = shell_exec("php task.php > /dev/null & echo $!");
I think the "> /dev/null &" bit tells it to run in the background, but am unsure what the "$!" does.
Part C. The $PID I need as a tag of the process. I need to write this number (or whatever) to a file in the same directory, and need to read it every call to check.php. I can't work out how to do that. Could someone give me a link of how to read/write a file with a single number in to the same directory?
Part D. Then to check if the last launched task.php is still running I am going to use the function:
function is_process_running($PID)
{
exec("ps $PID", $ProcessState);
return(count($ProcessState) >= 2);
}
I think that is all the bits I need, but as you can see I am unsure on how to do a few of them.
I would use an flock() based mechanism to make sure that task.php runs only once.
Use a code like this:
<?php
$fd = fopen('lock.file', 'w+');
// try to get an exclusive lock. LOCK_NB let the operation not blocking
// if a process instance is already running. In this case, the else
// block will being entered.
if(flock($fd, LOCK_EX | LOCK_NB )) {
// run your code
sleep(10);
// ...
flock($fd, LOCK_UN);
} else {
echo 'already running';
}
fclose($fd);
Also note that flock() is, as the PHP documentation points out, portable across all supported operating systems.
!$
gives you the pid of the last executed program in bash. Like this:
command &
pid=$!
echo pid
Note that you will have to make sure your php code runs on a system with bash support. (Not windows)
Update (after comment of opener).
flock() will work on all operating systems (As I mentioned). The problem I see in your code when working with windows is the !$ (As I mentioned ;) ..
To obtain the pid of the task.php you should use proc_open() to start task.php. I've prepared two example scripts:
task.php
$fd = fopen('lock.file', 'w+');
// try to get an exclusive lock. LOCK_NB let the operation not blocking
// if a process instance is already running. In this case, the else
// block will being entered.
if(flock($fd, LOCK_EX | LOCK_NB )) {
// your task's code comes here
sleep(10);
// ...
flock($fd, LOCK_UN);
echo 'success';
$exitcode = 0;
} else {
echo 'already running';
// return 2 to let check.php know about that
// task.php is already running
$exitcode = 2;
}
fclose($fd);
exit($exitcode);
check.php
$cmd = 'php task.php';
$descriptorspec = array(
0 => array('pipe', 'r'), // STDIN
1 => array('pipe', 'w'), // STDOUT
2 => array('pipe', 'w') // STDERR
);
$pipes = array(); // will be set by proc_open()
// start task.php
$process = proc_open($cmd, $descriptorspec, $pipes);
if(!is_resource($process)) {
die('failed to start task.php');
}
// get output (stdout and stderr)
$output = stream_get_contents($pipes[1]);
$errors = stream_get_contents($pipes[2]);
do {
// get the pid of the child process and it's exit code
$status = proc_get_status($process);
} while($status['running'] !== FALSE);
// close the process
proc_close($process);
// get pid and exitcode
$pid = $status['pid'];
$exitcode = $status['exitcode'];
// handle exit code
switch($exitcode) {
case 0:
echo 'Task.php has been executed with PID: ' . $pid
. '. The output was: ' . $output;
break;
case 1:
echo 'Task.php has been executed with errors: ' . $output;
break;
case 2:
echo 'Cannot execute task.php. Another instance is running';
break;
default:
echo 'Unknown error: ' . $stdout;
}
You asked me why my flock() solution is the best. It's just because the other answer will not reliably make sure that task.php runs once. This is because the race condition I've mentioned in the comments below that answer.
You can realize it, using lock file:
if(is_file(__DIR__.'/work.lock'))
{
die('Script already run.');
}
else
{
file_put_contents(__DIR__.'/work.lock', '');
// YOUR CODE
unlink(__DIR__.'/work.lock');
}
Too bad I didn't see this before it was accepted..
I have written a class to do just this. ( using file locking ) and PID, process ID checking, on both windows and Linux.
https://github.com/ArtisticPhoenix/MISC/blob/master/ProcLock.php
I think your are really overdoing it with all the processes and background checks. If you run a PHP script without a session, then you are already essentially running it in the background. Because it will not block any other request from the user. So make sure you don't call session_start();
Then the next step would be to run it even when the user cancels the request, which is a basic function in PHP. ignore_user_abort
Last check is to make sure it's only runs once, which can be easily done with creating a file, since PHP doesnt have an easy application scope.
Combined:
<?php
// Ignore user aborts and allow the script
// to run forever
ignore_user_abort(true);
set_time_limit(0);
$checkfile = "./runningtask.tmp";
//LOCK_EX basicaly uses flock() to prevents racecondition in regards to a regular file open.
if(file_put_contents($checkfile, "running", LOCK_EX)===false) {
exit();
}
function Cleanup() {
global $checkfile;
unlink($checkfile);
}
/*
actual code for task.php
*/
//run cleanup when your done, make sure you also call it if you exit the code anywhere else
Cleanup();
?>
In your javascript you can now call the task.php directly and cancel the request when the connection to the server has been established.
<script>
function Request(url){
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
} else{
return false;
}
httpRequest.onreadystatechange = function(){
if (httpRequest.readyState == 1) {
//task started, exit
httpRequest.abort();
}
};
httpRequest.open('GET', url, true);
httpRequest.send(null);
}
//call Request("task.php"); whenever you want.
</script>
Bonus points: You can have the actual code for task.php write occasional updates to $checkfile to have a sense of what is going on. Then you can have another ajax file read the content and show the status to the user.
Lets make the whole process from B to D simple
Step B-D:
$rslt =array(); // output from first exec
$output = array(); // output of task.php execution
//Check if any process by the name 'task.php' is running
exec("ps -auxf | grep 'task.php' | grep -v 'grep'",$rslt);
if(count($rslt)==0) // if none,
exec('php task.php',$output); // run the task,
Explanation:
ps -auxf --> gets all running processes with details
grep 'task.php' --> filter the process by 'task.php' keyword
grep -v 'grep' --> filters the grep process out
NB:
Its also advisable to put the same check in task.php file.
If task.php is executed directly via httpd (webserver), it will only be displayed as a httpd process and cannot be identified by 'ps' command
It wouldn't work under load-balanced environment. [Edited: 17Jul17]
You can get an exclusive lock on the script itself for the duration of the script running
Any other attempts to run it will end as soon as the lock() function is invoked.
//try to set a global exclusive lock on the file invoking this function and die if not successful
function lock(){
$file = isset($_SERVER['SCRIPT_FILENAME'])?
realpath($_SERVER['SCRIPT_FILENAME']):
(isset($_SERVER['PHP_SELF'])?realpath($_SERVER['PHP_SELF']):false);
if($file && file_exists($file)){
//global handle stays alive for the duration if this script running
global $$file;
if(!isset($$file)){$$file = fopen($file,'r');}
if(!flock($$file, LOCK_EX|LOCK_NB)){
echo 'This script is already running.'."\n";
die;
}
}
}
Test
Run this in one shell and try to run it in another while it is waiting for input.
lock();
//this will pause execution until an you press enter
echo '...continue? [enter]';
$handle = fopen("php://stdin","r");
$line = fgets($handle);
fclose($handle);

How to lock file in PHP?

I'm trying to create a PHP file, which wouldn't run if it's already running. Here's the code I'm using:
<?php
class Test {
private $tmpfile;
public function action_run() {
$this->die_if_running();
$this->run();
}
private function die_if_running() {
$this->tmpfile = #fopen('.refresher2.pid', "w");
$locked = #flock($this->tmpfile, LOCK_EX|LOCK_NB);
if (! $locked) {
#fclose($this->tmpfile);
die("Running 2");
}
}
private function run() {
echo "NOT RUNNNING";
sleep(100);
}
}
$test = new Test();
$test->action_run();
The problem is, when I run this from console, it works great. But when I try to run it from browser, many instances can run simultaneously. This is on Windows 7, XAMPP, PHP 5.3.2. I guess OS is thinking that it's the same process and thus the functionality falls. Is there a cross-platform way to create a PHP script of this type?
Not really anything to promising. You can't use flock for that like this.
You could use system() to start another (php) process that does the locking for you. But drawbacks:
You need to do interprocess communication. Think about a way how to tell the other program when to release the lock etc. You can use stdin for messenging und use 3 constants or something. In this case it's still rather simple
It's bad for performance because you keep creating processes which is expensive.
Another way would be to start another program that runs all the time. You connect to it using some means of IPC (probably just use a tcp channel because it's cross-platform) and allow this program to manage file acces. That program could be a php script in an endless loop as well, but it will probably be simpler to code this in Java or another language that has multithreading support.
Another way would be to leverage existing ressources. Create a dummy database table for locks, create an entry for the file and then do table-row-locking.
Another way would be not to use files, but a database.
I had a similar problem a while ago.
I needed to have a counter where the number returned was unique.
I used a lock-file and only if this instance was able to create the lock-file was it allowed to read the file with the current number.
Instead of counting up perhaps you can allow the script to run.
The trick is to let try a few times (like 5) with a small wait/sleep in between.
function GetNextNumber()
{
$lockFile = "lockFile.txt";
$lfh = #fopen($lockFile, "x");
if (!$lfh)
{
$lockOkay = false;
$count = 0;
$countMax = 5;
// Try ones every second in 5 seconds
while (!$lockOkay & $count < $countMax)
{
$lfh = #fopen($lockFile, "x");
if ($lfh)
{
$lockOkay = true;
}
else
{
$count++;
sleep(1);
}
}
}
if ($lfh)
{
$fh = fopen($myFile, 'r+') or die("Too many users. ");
flock($fh, LOCK_EX);
$O_nextNumber = fread($fh, 15);
$O_nextNumber = $O_nextNumber + 1;
rewind($fh);
fwrite($fh, $O_knr);
flock($fh, LOCK_UN);
fclose($fh);
unlink($lockFile); // Sletter lockfilen
}
return $O_nextNumber;
}

How can I write to the console in PHP?

Is it possible write a string or log into the console?
What I mean
Just like in JSP, if we print something like system.out.println("some"), it will be there at the console, not at a page.
Or you use the trick from PHP Debug to console.
First you need a little PHP helper function
function debug_to_console($data) {
$output = $data;
if (is_array($output))
$output = implode(',', $output);
echo "<script>console.log('Debug Objects: " . $output . "' );</script>";
}
Then you can use it like this:
debug_to_console("Test");
This will create an output like this:
Debug Objects: Test
Firefox
On Firefox you can use an extension called FirePHP which enables the logging and dumping of information from your PHP applications to the console. This is an addon to the awesome web development extension Firebug.
http://www.studytrails.com/blog/using-firephp-in-firefox-to-debug-php/
Chrome
However if you are using Chrome there is a PHP debugging tool called Chrome Logger or webug (webug has problems with the order of logs).
More recently Clockwork is in active development which extends the Developer Tools by adding a new panel to provide useful debugging and profiling information. It provides out of the box support for Laravel 4 and Slim 2 and support can be added via its extensible API.
Using Xdebug
A better way to debug your PHP would be via Xdebug. Most browsers provide helper extensions to help you pass the required cookie/query string to initialize the debugging process.
Chrome - Xdebug Helper
Firefox - The easiest Xdebug
Opera - Xdebug
Safari - Xdebug Toggler
If you're looking for a simple approach, echo as JSON:
<script>
console.log(<?= json_encode($foo); ?>);
</script>
By default, all output goes to stdout, which is the HTTP response or the console, depending on whether your script is run by Apache or manually on the command line. But you can use error_log for logging and various I/O streams can be written to with fwrite.
Try the following. It is working:
echo("<script>console.log('PHP: " . $data . "');</script>");
As the author of the linked webpage in the popular answer, I would like to add my last version of this simple helper function. It is much more solid.
I use json_encode() to check if the variable type is unnecessary and add a buffer to solve problems with frameworks. There not have a solid return or excessive usage of header().
/**
* Simple helper to debug to the console
*
* #param $data object, array, string $data
* #param $context string Optional a description.
*
* #return string
*/
function debug_to_console($data, $context = 'Debug in Console') {
// Buffering to solve problems frameworks, like header() in this and not a solid return.
ob_start();
$output = 'console.info(\'' . $context . ':\');';
$output .= 'console.log(' . json_encode($data) . ');';
$output = sprintf('<script>%s</script>', $output);
echo $output;
}
Usage
// $data is the example variable, object; here an array.
$data = [ 'foo' => 'bar' ];
debug_to_console($data);`
Screenshot of the result
Also, a simple example as an image to understand it much easier:
$variable = "Variable";
echo "<script>console.log('$variable');</script>";
PHP and JavaScript interaction.
echo
"<div display='none'>
<script type='text/javascript'>
console.log('console log message');
</script>
</div>";
Creates a
<div>
with the
display="none"
so that the div is not displayed, but the
console.log()
function is created in javascript. So you get the message in the console.
I think it can be used --
function jsLogs($data, $isExit) {
$html = "";
$coll;
if (is_array($data) || is_object($data)) {
$coll = json_encode($data);
} else {
$coll = $data;
}
$html = "<script id='jsLogs'>console.log('PHP: ${coll}');</script>";
echo($html);
if ($isExit) exit();
}
# For String
jsLogs("Testing string"); #PHP: Testing string
# For Array
jsLogs(array("test1", "test2")); # PHP: ["test1","test2"]
# For Object
jsLogs(array("test1"=>array("subtest1", "subtest2"))); #PHP: {"test1":["subtest1","subtest2"]}
Some great answers that add more depth; but I needed something simpler and more like the JavaScript console.log() command.
I use PHP in a lot of "gathering data and turn into XML" in Ajax applications. The JavaScript console.log doesn't work in that case; it breaks the XML output.
Xdebug, etc. had similar issues.
My solution in Windows:
Setup a .txt file that is somewhat easily to get to and writable
Set the PHP error_log variable in the .ini file to write to that file
Open the file in Windows File Explorer and open a preview pane for it
Use the error_log('myTest'); PHP command to send messages
This solution is simple and meets my needs most of the time. Standard PHP, and the preview pane automatically updates every time PHP writes to it.
I find this helpful:
function console($data, $priority, $debug)
{
if ($priority <= $debug)
{
$output = '<script>console.log("' . str_repeat(" ", $priority-1) . (is_array($data) ? implode(",", $data) : $data) . '");</script>';
echo $output;
}
}
And use it like:
<?php
$debug = 5; // All lower and equal priority logs will be displayed
console('Important', 1 , $debug);
console('Less Important', 2 , $debug);
console('Even Less Important', 5 , $debug);
console('Again Important', 1 , $debug);
?>
Which outputs in console:
Important
Less Important
Even Less Important
Again Important
And you can switch off less important logs by limiting them using the $debug value.
Short and easy, for arrays, strings or also objects.
function console_log( $data ) {
$output = "<script>console.log( 'PHP debugger: ";
$output .= json_encode(print_r($data, true));
$output .= "' );</script>";
echo $output;
}
For Chrome there is an extension called Chrome Logger allowing to log PHP messages.
The Firefox DevTools even have integrated support for the Chrome Logger protocol.
To enable the logging, you just need to save the 'ChromePhp.php' file in your project. Then it can be used like this:
include 'ChromePhp.php';
ChromePhp::log('Hello console!');
ChromePhp::log($_SERVER);
ChromePhp::warn('something went wrong!');
Example taken from the GitHub page.
The output may then look like this:
function phpconsole($label='var', $x) {
?>
<script type="text/javascript">
console.log('<?php echo ($label)?>');
console.log('<?php echo json_encode($x)?>');
</script>
<?php
}
If you want write to the PHP log file, and not the JavaScript console you can use this:
error_log("This is logged only to the PHP log")
Reference: error_log
I think best solution is to use
error_log(content)
This is output
Edit 2022:
So I’ve discovered way better way and thats file_put_contents("php://stdout", content)
It writes without the logging info
There is also a great Google Chrome extension, PHP Console, with a PHP library that allows you to:
See errors and exceptions in the Chrome JavaScript console and in the notification popups.
Dump any type of variable.
Execute PHP code remotely.
Protect access by password.
Group console logs by request.
Jump to error file:line in your text editor.
Copy error/debug data to the clipboard (for testers).
Here is my solution, the good thing about this one is that you can pass as many params as you like.
function console_log()
{
$js_code = 'console.log(' . json_encode(func_get_args(), JSON_HEX_TAG) .
');';
$js_code = '<script>' . $js_code . '</script>';
echo $js_code;
}
Call it this way
console_log('DEBUG>>', 'Param 1', 'Param 2');
console_log('Console DEBUG:', $someRealVar1, $someVar, $someArray, $someObj);
Now you should be able to see output in your console, happy coding :)
Any of these two are working:
<?php
$five = 5;
$six = 6;
?>
<script>
console.log(<?php echo $five + $six ?>);
</script>
<?php
$five = 5;
$six = 6;
echo("<script>console.log($five + $six);</script>");
?>
I was looking for a way to debug code in a WordPress plugin that I was developing and came across this post.
I took the bits of code that are most applicable to me from other responses and combined these into a function that I can use for debugging WordPress. The function is:
function debug_log($object=null, $label=null, $priority=1) {
$priority = $priority<1? 1: $priority;
$message = json_encode($object, JSON_PRETTY_PRINT);
$label = "Debug" . ($label ? " ($label): " : ': ');
echo "<script>console.log('" . str_repeat("-", $priority-1) . $label . "', " . $message . ");</script>";
}
Usage is as follows:
$txt = 'This is a test string';
$sample_array = array('cat', 'dog', 'pig', 'ant', 'fly');
debug_log($txt, '', 7);
debug_log($sample_array);
If this function is used with WordPress development, the function should be placed in the functions.php file of the child theme and can then be called anywhere in the code.
Clean, fast and simple without useless code:
function consolelog($data) {
echo "<script>console.log('".$data."');</script>";
}
Short and simply with printf and json_encode:
function console_log($data) {
printf('<script>console.log(%s);</script>', json_encode($data));
}
I have abandoned all of the above in favour of Debugger & Logger. I cannot praise it enough!
Just click on one of the tabs at top right, or on the "click here" to expand/hide.
Notice the different "categories". You can click any array to expand/collapse it.
From the web page
Main features:
Show globals variables ($GLOBALS, $_POST, $_GET, $_COOKIE, etc.)
Show PHP version and loaded extensions
Replace PHP built in error handler
Log SQL queries
Monitor code and SQL queries execution time
Inspect variables for changes
Function calls tracing
Code coverage analysis to check which lines of script where executed
Dump of all types of variable
File inspector with code highlighter to view source code
Send messages to JavaScript console (Chrome only), for Ajax scripts
As of 2017, Firebug and hence FirePHP has been disabled.
I wrote some little modifications to the ChromePHP tool to allow seamless migration from FirePHP to Firebug for debugging via the console.
This article explains in clear easy steps
Migrate from FirePHP to ChromePHP in 5 minutes (without breaking existing code)
For Ajax calls or XML / JSON responses, where you don't want to mess with the body, you need to send logs via HTTP headers, then add them to the console with a web extension. This is how FirePHP (no longer available) and QuantumPHP (a fork of ChromePHP) do it in Firefox.
If you have the patience, x-debug is a better option - you get deeper insight into PHP, with the ability to pause your script, see what is going on, then resume the script.
I might be late for a party, but I was looking for an implementation of logging function which:
takes a variable number of comma separated arguments, just like javascript console.log(),
gives a formatted output (not just a serialized string),
is distinguishable from a common javascript console.log().
So the output looks like that:
(The snippet below is tested on php 7.2.11. I'm not sure about its php backward compatibility. It can be an issue for javascript as well (in a term of old browsers), because it creates a trailing comma after console.log() arguments – which is not legal until ES 2017.)
<?php
function console_log(...$args)
{
$args_as_json = array_map(function ($item) {
return json_encode($item);
}, $args);
$js_code = "<script>console.log('%c 💬 log from PHP: ','background: #474A8A; color: #B0B3D6; line-height: 2',";
foreach ($args_as_json as $arg) {
$js_code .= "{$arg},";
}
$js_code .= ")</script>";
echo $js_code;
}
$list = ['foo', 'bar'];
$obj = new stdClass();
$obj->first_name = 'John';
$obj->last_name = 'Johnson';
echo console_log($list, 'Hello World', 123, $obj);
?>
Here's a handy function. It is super simple to use, allows you to pass as many arguments as you like, of any type, and will display the object contents in the browser console window as though you called console.log from JavaScript - but from PHP
Note, you can use tags as well by passing 'TAG-YourTag', and it will be applied until another tag is read, for example, 'TAG-YourNextTag'
/*
* Brief: Print to console.log() from PHP
*
* Description: Print as many strings,arrays, objects, and
* other data types to console.log from PHP.
*
* To use, just call consoleLog($data1, $data2, ... $dataN)
* and each dataI will be sent to console.log - note
* that you can pass as many data as you want an
* this will still work.
*
* This is very powerful as it shows the entire
* contents of objects and arrays that can be
* read inside of the browser console log.
*
* A tag can be set by passing a string that has the
* prefix TAG- as one of the arguments. Everytime a
* string with the TAG- prefix is detected, the tag
* is updated. This allows you to pass a tag that is
* applied to all data until it reaches another tag,
* which can then be applied to all data after it.
*
* Example:
*
* consoleLog('TAG-FirstTag', $data, $data2, 'TAG-SecTag, $data3);
*
* Result:
* FirstTag '...data...'
* FirstTag '...data2...'
* SecTag '...data3...'
*/
function consoleLog(){
if(func_num_args() == 0){
return;
}
$tag = '';
for ($i = 0; $i < func_num_args(); $i++) {
$arg = func_get_arg($i);
if(!empty($arg)){
if(is_string($arg) && strtolower(substr($arg, 0, 4)) === 'tag-'){
$tag = substr($arg, 4);
}else{
$arg = json_encode($arg, JSON_HEX_TAG | JSON_HEX_AMP );
echo "<script>console.log('" . $tag . " " . $arg . "');</script>";
}
}
}
}
NOTE: func_num_args() and func_num_args() are PHP functions for reading a dynamic number of input arguments, and allow this function to have infinitely many console.log requests from one function call.
Though this is an old question, I've been looking for this. Here's my compilation of some solutions answered here and some other ideas found elsewhere to get a one-size-fits-all solution.
CODE :
// Post to browser console
function console($data, $is_error = false, $file = false, $ln = false) {
if(!function_exists('console_wer')) {
function console_wer($data, $is_error = false, $bctr, $file, $ln) {
echo '<div display="none">'.'<script type="text/javascript">'.(($is_error!==false) ? 'if(typeof phperr_to_cns === \'undefined\') { var phperr_to_cns = 1; document.addEventListener("DOMContentLoaded", function() { setTimeout(function(){ alert("Alert. see console."); }, 4000); }); }' : '').' console.group("PHP '.(($is_error) ? 'error' : 'log').' from "+window.atob("'.base64_encode((($file===false) ? $bctr['file'] : $file)).'")'.((($ln!==false && $file!==false) || $bctr!==false) ? '+" on line '.(($ln===false) ? $bctr['line'] : $ln).' :"' : '+" :"').'); console.'.(($is_error) ? 'error' : 'log').'('.((is_array($data)) ? 'JSON.parse(window.atob("'.base64_encode(json_encode($data)).'"))' : '"'.$data.'"').'); console.groupEnd();</script></div>'; return true;
}
}
return #console_wer($data, $is_error, (($file===false && $ln===false) ? array_shift(debug_backtrace()) : false), $file, $ln);
}
//PHP Exceptions handler
function exceptions_to_console($svr, $str, $file, $ln) {
if(!function_exists('severity_tag')) {
function severity_tag($svr) {
$names = [];
$consts = array_flip(array_slice(get_defined_constants(true)['Core'], 0, 15, true));
foreach ($consts as $code => $name) {
if ($svr & $code) $names []= $name;
}
return join(' | ', $names);
}
}
if (error_reporting() == 0) {
return false;
}
if(error_reporting() & $svr) {
console(severity_tag($svr).' : '.$str, true, $file, $ln);
}
}
// Divert php error traffic
error_reporting(E_ALL);
ini_set("display_errors", "1");
set_error_handler('exceptions_to_console');
TESTS & USAGE :
Usage is simple. Include first function for posting to console manually. Use second function for diverting php exception handling. Following test should give an idea.
// Test 1 - Auto - Handle php error and report error with severity info
$a[1] = 'jfksjfks';
try {
$b = $a[0];
} catch (Exception $e) {
echo "jsdlkjflsjfkjl";
}
// Test 2 - Manual - Without explicitly providing file name and line no.
console(array(1 => "Hi", array("hellow")), false);
// Test 3 - Manual - Explicitly providing file name and line no.
console(array(1 => "Error", array($some_result)), true, 'my file', 2);
// Test 4 - Manual - Explicitly providing file name only.
console(array(1 => "Error", array($some_result)), true, 'my file');
EXPLANATION :
The function console($data, $is_error, $file, $fn) takes string or array as first argument and posts it on console using js inserts.
Second argument is a flag to differentiate normal logs against errors. For errors, we're adding event listeners to inform us through alerts if any errors were thrown, also highlighting in console. This flag is defaulted to false.
Third and fourth arguments are explicit declarations of file and line numbers, which is optional. If absent, they're defaulted to using the predefined php function debug_backtrace() to fetch them for us.
Next function exceptions_to_console($svr, $str, $file, $ln) has four arguments in the order called by php default exception handler. Here, the first argument is severity, which we further crosscheck with predefined constants using function severity_tag($code) to provide more info on error.
NOTICE :
Above code uses JS functions and methods that are not available in older browsers. For compatibility with older versions, it needs replacements.
Above code is for testing environments, where you alone have access to the site. Do not use this in live (production) websites.
SUGGESTIONS :
First function console() threw some notices, so I've wrapped them within another function and called it using error control operator '#'. This can be avoided if you didn't mind the notices.
Last but not least, alerts popping up can be annoying while coding. For this I'm using this beep (found in solution : https://stackoverflow.com/a/23395136/6060602) instead of popup alerts. It's pretty cool and possibilities are endless, you can play your favorite tunes and make coding less stressful.
Use:
function console_log($data) {
$bt = debug_backtrace();
$caller = array_shift($bt);
if (is_array($data))
$dataPart = implode(',', $data);
else
$dataPart = $data;
$toSplit = $caller['file'])) . ':' .
$caller['line'] . ' => ' . $dataPart
error_log(end(split('/', $toSplit));
}
in start code...
error_reporting(-1);
ini_set('display_errors', 'On');
it work

Categories