I have a problem implementing an API that works with Java, but fails to work with cURL. We've gone through everything so far and there must be something that is different between the requests that Java makes and what we make.
In PHP we can get header data by looking at $_SERVER['HTTP_*'] variables and we can get request body from file_get_contents('php://input'); But we cannot get the exact data sent from user agent to client.
Is it possible to get the full request, that user agent sends, with PHP? Headers and body included? If so, then how?
The only example I found is here, but this one gets the body the way I mentioned, while it gets headers by parsing through $_SERVER, which seems like a hack since it's never 100% of what was actually sent.
All help and tips are appreciated!
for headers you can try apache_request_headers() and for body I dont know other method than file_get_contents('php://input');
Old question, but for anyone needing to do this in the future... The best (probably only) way would be to take full control of the server by being the server.
Set up a socket server listening on port 80 (if this is all you need the server to do), or any other port if 80 is not available.
That way you can capture the request completely unmodified. Examples of basic socket servers are plentiful, here is a simplified version of the latest one I implemented, which will print the full request:
<?php
//Read the port number from first parameter on the command line if set
$port = (isset($argv[1])) ? intval($argv[1]) : 80;
//Just a helper
function dlog($string) {
echo '[' . date('Y-m-d H:i:s') . '] ' . $string . "\n";
}
//Create socket
while (($sock = #socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
dlog("socket_create() failed: reason: " . socket_strerror(socket_last_error()));
sleep(1);
}
//Reduce blocking if previous connections weren't ended correctly
if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1)) {
dlog("socket_set_option() failed: reason: " . socket_strerror(socket_last_error($sock)));
exit;
}
//Bind to port
$tries = 0;
while (#socket_bind($sock, 0, $port) === false) {
dlog("socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)));
sleep(1);
$tries++;
if ($tries>30) {
dlog("socket_bind() failed 30 times giving up...");
exit;
}
}
//Start listening
while (#socket_listen($sock, 5) === false) {
dlog("socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)));
sleep(1);
}
//Makes it possible to accept several simultaneous connections
socket_set_nonblock($sock);
//Keeps track of active connections
$clients = array();
dlog("server started...");
while(true) {
//Accept new connections
while (($msgsock = #socket_accept($sock)) !== false) {
//Prevent blocking
socket_set_nonblock($msgsock);
//Get IP - just for logging
socket_getpeername($msgsock, $remote_address);
//Add new client to array
$clients[] = array('sock' => $msgsock, 'timeout' => time()+30, 'ip' => $remote_address);
dlog("$remote_address connected, client count: ".count($clients));
}
//Loop existing clients and read input
foreach($clients as $key => $client) {
$rec = '';
$buf = '';
while (true) {
//Read 2 kb into buffer
$buf = socket_read($clients[$key]['sock'], 2048, PHP_BINARY_READ);
//Break if error reading
if ($buf === false) break;
//Append buffer to input
$rec .= $buf;
//If no more data is available socket read returns an empty string - break
if ($buf === '') break;
}
if ($rec=='') {
//If nothing was received from this client for 30 seconds then end the connection
if ($clients[$key]['timeout']<time()) {
dlog('No data from ' . $clients[$key]['ip'] . ' for 30 seconds. Ending connection');
//Close socket
socket_close($client['sock']);
//Clean up clients array
unset($clients[$key]);
}
} else {
//If something was received increase the timeout
$clients[$key]['timeout']=time()+30;
//And.... DO SOMETHING
dlog('Raw data received from ' . $clients[$key]['ip'] . "\n------\n" . $rec . "\n------");
}
}
//Allow the server to do other stuff by sleeping for 50 ms on each iteration
usleep(50000);
}
//We'll never reach here, but some logic should be implemented to correctly end the server
foreach($clients as $key => $client) {
socket_close($client['sock']);
}
#socket_close($sock);
exit;
To start the server on port 8080 just run php filename.php 8080 from a shell.
These aren't "with php" but you might find them useful for your purposes nevertheless
ssldump http://ssldump.sourceforge.net/
mod_dumpio http://httpd.apache.org/docs/2.2/mod/mod_dumpio.html
mod_dumpost https://github.com/danghvu/mod_dumpost
Related
I am trying to force a php script (currently on XAMPP, soon on a dedicated server) to use a certain proxy for outgoing traffic.
On this site i found the following solution for it :
stream_context_set_default(['http'=>['proxy'=>'ip:port']]);
how do i verify that my script is actually using that proxy?
thanks in advance
You can use fsockopen for this, where you can specify a timeout.
A simple proxy list checker. You can check a list ip:port if that port is opened on that IP.
<?php
$fisier = file_get_contents('proxy_list.txt'); // Read the file with the proxy list
$linii = explode("\n", $fisier); // Get each proxy
$fisier = fopen("bune.txt", "a"); // Here we will write the good ones
for($i = 0; $i < count($linii) - 1; $i++) test($linii[$i]); // Test each proxy
function test($proxy)
{
global $fisier;
$splited = explode(':',$proxy); // Separate IP and port
if($con = #fsockopen($splited[0], $splited[1], $eroare, $eroare_str, 3))
{
fwrite($fisier, $proxy . "\n"); // Check if we can connect to that IP and port
print $proxy . '<br>'; // Show the proxy
fclose($con); // Close the socket handle
}
}
fclose($fisier); // Close the file
?>
you may also want to use set_time_limit so that you can run your script for longer.
Code taken from: http://www.php.net/manual/en/function.fsockopen.php#95605
Just for 1 proxy :
function test()
{
$fisier = fopen("bune.txt", "a"); // Here we will write the good ones
if($con = #fsockopen($IP, $port, $eroare, $eroare_str, 3))
{
fwrite($fisier, $proxy . "\n"); // Check if we can connect to that IP and port
print $proxy . '<br>'; // Show the proxy
fclose($con); // Close the socket handle
}
}
I have a CLI php script that collects user input, processes it, and returns information based on it. Currently it is only possible to use it if you SSH into the server that the PHP is on and run php scriptname.php, however, I know that PHP can create socket servers. Would it be possible, and if so how, to create a socket server that listens for a connection and once a user connects, provides a terminal-like environment for the script to run in until the user disconnects? It would be a different instance of the script for each connected user as well. No authentication would be required.
Edit: if this isn't possible with PHP, what are other options?
Edit:
Some of the code I use is below
For collecting user input:
echo "Enter a command or question... \n";
$line = $this->input();
$line = trim($line);
This calls the input function, which will use readline to get the user input and return it, and then the script interprets the input and generates a response based on it, and then will ask for more input. This script doesn't end unless you tell it to, I would like to be able to connect to it via a PHP socket server or similar so that I can send it commands without using SSH.
Edit:
So, I tried the xinetd server, and I can connect to it, but readline and many other things including the formatting that worked when accessing through SSH no longer works with telnet. Are there other ways to do this or ways to configure it to be more flexible as far as formatting and readline?
Of course it is possible. You don't need an Apache webserver, or PHP's built in web server or anything like that. I mean you could use those things, but easiest to just write a PHP script and have it listen on some port. Either adjust you script or write another one that pipes stdio between a socket and your script. Generally there are PHP wrappers for whatever system C libs or POSIX libs you would use if you were writing in C. In your case you probably want to use Sockets. There is many examples in the PHP sockets docs.
To give the jist, this is a simple PHP echo server - it just prints back anything you type. I can't remember where I got this from so sorry for lack of attibutation:
error_reporting(E_ALL);
/* Allow the script to hang around waiting for connections. Only applies to httpd module. */
set_time_limit(0);
/* Turn on implicit output flushing so we see what we're getting as it comes in. Only applies to httpd module.*/
ob_implicit_flush();
$address = '127.0.0.1';
$port = 10000;
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
if (socket_bind($sock, $address, $port) === false) {
echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
if (socket_listen($sock, 5) === false) {
echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
do {
if (($msgsock = socket_accept($sock)) === false) {
echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
break;
}
/* Send instructions. */
$msg = "\nWelcome to the PHP Test Server. \n" .
"To quit, type 'quit'. To shut down the server type 'shutdown'.\n";
socket_write($msgsock, $msg, strlen($msg));
do {
if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n";
break 2;
}
if (!$buf = trim($buf)) {
continue;
}
if ($buf == 'quit') {
break;
}
if ($buf == 'shutdown') {
socket_close($msgsock);
break 2;
}
$talkback = "PHP: You said '$buf'.\n";
socket_write($msgsock, $talkback, strlen($talkback));
echo "$buf\n";
} while (true);
socket_close($msgsock);
} while (true);
socket_close($sock);
I used #Barmar's comment to help me set up an xinetd server.
You'll want to add the script to your services file,
/etc/services:
...
myservice port/tcp # my service
and then add an xinetd configuration file, /etc/inetd.d/myservice
# default: on
# description: service script
service myservice
{
socket_type = stream
protocol = tcp
wait = no
user = gleblanc
server = /usr/bin/php
server_args = /home/service/scriptname.php
log_on_success += DURATION
nice = 10
disable = no
}
Here is the issue. I'm working on a tracking script with a China tracking unit (not important). The two files I have is as follows:
7778.php
#!/usr/bin/php -q
<?php
error_reporting(0);
set_time_limit(0);
$address = 'SERVER IP';
$port = 7778;
$q_count = 1;
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
{
echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
if (($ret = socket_bind($master, $address, $port)) < 0)
{
echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}
if (($ret = socket_listen($master, SOMAXCONN)) < 0)
{
echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}
$read_sockets = array($master);
//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while (true)
{
$changed_sockets = $read_sockets;
$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
foreach($changed_sockets as $socket)
{
if ($socket == $master)
{
if (($client = socket_accept($master)) < 0)
{
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
continue;
}
else
{
array_push($read_sockets, $client);
print "[".date('Y-m-d H:i:s')."] ".$client." CONNECTED "."(".count($read_sockets)."/".SOMAXCONN.")\r\n";
}
}
else
{
$bytes = #socket_recv($socket, $buffer, 2048, 0);
if ($bytes == 0)
{
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
if (socket_close($client))
{
print "Connection closed\r\n";
}
}
else
{
print $buffer."\r\n";
}
print "All Done\r\n";
print "---------------------------------------------------------------------------------------------------------\r\n";
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
if (socket_close($client))
{
print "Connection closed\r\n";
}
}
}
}
?>
and then
port_start.sh with code:
#!/bin/sh
cd /home/path/to/script/
if netstat -tulpn | grep 7778 > /dev/null
then
echo 7778 - Online
else
./7778.php
fi
Now what I would do to test the script is ssh onto my server, navigate to the file directory and type "./7778.php". This will then start my php file, which will open port 7778, my unit will then connect, and my script will dump the data/buffer on the screen. Even if I start the script from the .sh file by typing the following "./port_start.sh" everything works perfect. I can also use Putty and open a RAW connection to my server and the port, and it works. No how it must work is as follows. The unit will make a connection, the script will accept it and receive the data, and then close the connection. My problem occurs when I open the port by running the .sh file from my cronjob with the following code "*/1 * * * * /home/path/to/file/port_start.sh > /dev/null". It will open it, and I can verify that its open, but nothing can connect to it. Why would that be?
When working from cronjob, computer cannot locate the command program. If the program inside /home/root/bin directory, you should call it like/home/root/bin/netstat ... you can locate the progrma by running "locate netstat" and "locate grep". This may solve your problem.
Thank you so much Isa for your response. In my case this was not the problem. Everything opens and works as it should. But I have a little script to check if the port is open. My problem happened there. When I ran the script, it would keep the port open but would kill my script. That's why I could see that the port was still open but nothing would be happening.
The script I use to check the port is as follows if someone ever sits with the same problem:
$errno = "";
$errstr = "";
$fp = #fsockopen($domain, $port, $errno, $errstr, 2);
$status = "";
if (!$fp) {
$status = "<img src='red.gif' alt='Status: Down, Domain: $domain, Port: $port ($errstr)'>\n";
}
else
{
$status = "<img src='green.gif' alt='Status: Up, Domain: $domain, Port: $port'>\n";
}
#fclose($fp);
But again Isa your response made sense but didn't apply to me
I've written a database application using MySQL and PHP on the server side, and Flex on the client side. I use a php socket to have it automatically update all clients whenever changes are made to the database.
The whole system works swimmingly, but every now and then the socket seems to stop responding. The strange thing is that the connection is still good – any changes a client performs are implemented, but the socket doesn't broadcast the message. The socket file isn't throwing any errors (though when I run error_log from the socket those messages appear). Memory use of the socket doesn't change on the server, and no disconnect signal is sent. Stranger still, eventually the socket starts working again, after about half an hour or so. If I restart the socket that also solves the problem.
I'm working on a hacky solution allowing the client to restart the socket if it becomes unresponsive, but that's unsatisfying and open to mistakes. What I'd really like is to learn why this might be happening. Does the socket somehow get "saturated" after a certain number of connections? Should I be doing something to clean up the socket server? I've tried three different physical servers (one local and two online) and the same thing happens, so it's definitely me.
I feel like there's something basic that I'm doing wrong. Here's the code I'm using for the socket server (it's a slightly modified version of socket written by Raymond Fain on kirupa.com, so I've left his original comment at the top):
#!/usr/bin/php -q
<?php
/*
Raymond Fain
Used for PHP5 Sockets with Flash 8 Tutorial for Kirupa.com
For any questions or concerns, email me at ray#obi-graphics.com
or simply visit the site, www.php.net, to see if you can find an answer.
*/
//ini_set('display_errors',1);
//ini_set('display_startup_errors',1);
error_reporting(E_ALL);
ini_set('error_log', 'socket_errors.log');
ini_set('log_errors', 'On');
ini_set('display_errors', 'Off');
set_time_limit(0);
ob_implicit_flush();
error_log('testing');
$address = 'xxx.xxx.xx.xx';
$port = xxxxx;
function send_Message($allclient, $socket, $buf)
{
$buf = str_replace("\0","",$buf);
//echo "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, "<mbFeed>$buf</mbFeed>\n\0");
}
}
echo "connecting...
";
//---- Start Socket creation for PHP 5 Socket Server -------------------------------------
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
{
echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
if (($ret = socket_bind($master, $address, $port)) < 0)
{
echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}
echo 'socket bind successfull.
';
if (($ret = socket_listen($master, 5)) < 0)
{
echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}
$read_sockets = array($master);
echo "connected.";
//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while (true)
{
$changed_sockets = $read_sockets;
$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
foreach($changed_sockets as $key => $socket)
{
if ($socket == $master)
{
if (($client = socket_accept($master)) < 0)
{
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
continue;
}
else
{
array_push($read_sockets, $client);
}
}
else
{
$bytes = socket_recv($socket, $buffer, 8192, 0);
if ($bytes == 0)
{
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
}
else
{
$allclients = $read_sockets;
array_shift($allclients);
//any messages starting with ::: are not to be broadcast, and may be used for other things. This message
//usually comes from the client.
if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
else
{
//otherwise the message comes from a php file that will be closed, so the socket needs to be closed.
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
send_Message($allclients, $socket, $buffer);
}
}
}
}
}
function handleSpecial($message)
{
error_log($message);
}
?>
As the sockets in use seem to be blocking the call to socket_recv() might not return until the amount of data requested was read. And with this does not handle any other reading sockets, including the accecpting socket.
To get around this use socket_set_nonblock() to make the sockets unblocking. Please note that a call to socket_recv() on a non-blocking socket might return having read less bytes than requested, and therefore the amount of data read shall be tracked for each socket.
Like many people, I can do a lot of things with PHP. One problem I do face constantly is that other people can do it much cleaner, much more organized and much more structured. This also results in much faster execution times and much less bugs.
I just finished writing a basic PHP Socket Server (the real core), and am asking you if you can tell me what I should do different before I start expanding the core. I'm not asking about improvements such as encrypted data, authentication or multi-threading.
I'm more wondering about questions like "should I maybe do it in a more object oriented way (using PHP5)?", or "is the general structure of the way the script works good, or should some things be done different?". Basically, "is this how the core of a socket server should work?"
In fact, I think that if I just show you the code here many of you will immediately see room for improvements. Please be so kind to tell me. Thanks!
#!/usr/bin/php -q
<?
// config
$timelimit = 180; // amount of seconds the server should run for, 0 = run indefintely
$address = $_SERVER['SERVER_ADDR']; // the server's external IP
$port = 9000; // the port to listen on
$backlog = SOMAXCONN; // the maximum of backlog incoming connections that will be queued for processing
// configure custom PHP settings
error_reporting(1); // report all errors
ini_set('display_errors', 1); // display all errors
set_time_limit($timelimit); // timeout after x seconds
ob_implicit_flush(); // results in a flush operation after every output call
//create master IPv4 based TCP socket
if (!($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) die("Could not create master socket, error: ".socket_strerror(socket_last_error()));
// set socket options (local addresses can be reused)
if (!socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1)) die("Could not set socket options, error: ".socket_strerror(socket_last_error()));
// bind to socket server
if (!socket_bind($master, $address, $port)) die("Could not bind to socket server, error: ".socket_strerror(socket_last_error()));
// start listening
if (!socket_listen($master, $backlog)) die("Could not start listening to socket, error: ".socket_strerror(socket_last_error()));
//display startup information
echo "[".date('Y-m-d H:i:s')."] SERVER CREATED (MAXCONN: ".SOMAXCONN.").\n"; //max connections is a kernel variable and can be adjusted with sysctl
echo "[".date('Y-m-d H:i:s')."] Listening on ".$address.":".$port.".\n";
$time = time(); //set startup timestamp
// init read sockets array
$read_sockets = array($master);
// continuously handle incoming socket messages, or close if time limit has been reached
while ((!$timelimit) or (time() - $time < $timelimit)) {
$changed_sockets = $read_sockets;
socket_select($changed_sockets, $write = null, $except = null, null);
foreach($changed_sockets as $socket) {
if ($socket == $master) {
if (($client = socket_accept($master)) < 0) {
echo "[".date('Y-m-d H:i:s')."] Socket_accept() failed, error: ".socket_strerror(socket_last_error())."\n";
continue;
} else {
array_push($read_sockets, $client);
echo "[".date('Y-m-d H:i:s')."] Client #".count($read_sockets)." connected (connections: ".count($read_sockets)."/".SOMAXCONN.")\n";
}
} else {
$data = #socket_read($socket, 1024, PHP_NORMAL_READ); //read a maximum of 1024 bytes until a new line has been sent
if ($data === false) { //the client disconnected
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
socket_close($socket);
echo "[".date('Y-m-d H:i:s')."] Client #".($index-1)." disconnected (connections: ".count($read_sockets)."/".SOMAXCONN.")\n";
} else {
if ($data = trim($data)) { //remove whitespace and continue only if the message is not empty
switch ($data) {
case "exit": //close connection when exit command is given
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
socket_close($socket);
echo "[".date('Y-m-d H:i:s')."] Client #".($index-1)." disconnected (connections: ".count($read_sockets)."/".SOMAXCONN.")\n";
break;
default: //for experimental purposes, write the given data back
socket_write($socket, "\n you wrote: ".$data);
}
}
}
}
}
}
socket_close($master); //close the socket
echo "[".date('Y-m-d H:i:s')."] SERVER CLOSED.\n";
?>
One small thing, personally i'd create a function for outputting instead of just using echo, that way its easy to turn it off, change the format etc.. eg
function log($message = '')
{
echo '['.date('Y-m-d H:i:s').']'.$message;
}
and then you can use :
log("SERVER CREATED (MAXCONN: ".SOMAXCONN.").\n");
instead of
echo "[".date('Y-m-d H:i:s')."] SERVER CREATED (MAXCONN: ".SOMAXCONN.").\n";
Oh and be sure to use === instead of == otherwise you might get some odd results.
I'd move your switch $data into a function as that will likely expand.
Also since it looks like you're using a text based protocol, might want to explode/strtok to get the first level command and check it against an array of valid commands. Could also have an array that describes what internal function to call and use call_user_func_array to dispatch the call.