Creating a client for a chat in PHP - php

I'm trying to create a PHP chat, so I have server.php that starts the server on the terminal, which is listen to client connections:
<?php
function chat_leave( $sock, $chat_id = 0 )
{
if( $chat_room_id[ $chat_id ] )
{
unset( $chat_room_id[ $chat_id ] );
return true;
}
socket_close($sock);
return false;
}
function client( $input )
{
/*
Simple php udp socket client
*/
//Reduce errors
error_reporting(~E_WARNING);
$server = '127.0.0.1';
$port = 9999;
if(!($sock = socket_create(AF_INET, SOCK_DGRAM, 0)))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg \n");
}
//Communication loop
while(1)
{
//Send the message to the server
if( ! socket_sendto($sock, $input , strlen($input) , 0 , $server , $port))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not send data: [$errorcode] $errormsg \n");
}
//Now receive reply from server and print it
if(socket_recv ( $sock , $reply , 2045 , MSG_WAITALL ) === FALSE)
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not receive data: [$errorcode] $errormsg \n");
}
return $reply;
}
}
/*
* chat_join
* a new user joins the chat
* #username: String
* #password: String
*
* add a new listener to the server
*
*/
function chat_join( $username = "", $password = "" )
{
$users = array(
"batman" => "batman123",
"robin" => "robin123",
"joe" => "joe123"
);
if( $users[$username] == $password )
{
return true;
}
return false;
}
function main()
{
$chat_room_id = array();
$username = stripslashes( $_POST['username'] );
$password = stripslashes( $_POST['password'] );
$action = stripslashes( $_POST['action'] );
$port = intval( $_POST['port'] );
$domain = stripslashes( $_POST['domain'] );
$chat_id = intval( $_POST['chat_room_id'] );
if( strcmp( $action, "login" ) == 0 )
{
$status = chat_join( $username, $password );
if( $status )
{
$chat_room_id[] = $chat_id;
echo json_encode( $status );
}
}
else if( strcmp( $action, "chat" ) == 0 )
{
$msg = stripslashes( $_POST['message'] );
// take the message, send through the client
$reply = client( $msg );
echo json_encode( $reply );
}
else if( strcmp( $action, "logout") == 0 )
{
}
else
{
echo json_encode( false );
}
return;
}
main();
?>
The function client() is the code I have from a client.php file, which when I execute on the terminal, is able to send and receive messages from the server.php. Now I would like to use my main.php file, so once the user is logged in he will send messages to the server, which will reply back the messages that user haven't seen.
When I run server.php and client.php from two different terminals, I'm able to send and receive messages, however I would like to do that using main.php, transform that reply message into a JSON object and send back to the html page where it will get appended to a textarea box.
My problem is: how can I get the reply that client.php received and send it back to the html page?
When I execute it on the terminal, I have:
Enter a message to send : hello
Reply : hello
I use AJAX to send the user input in the chat, so I wanted to be able to take that message, and send it to the server, which I started on the terminal and take the reply back and forward to the webpage and append that to the text box area.
How can I accomplish that? Should I start client.php as a service through main.php? Or should I use the client($input) function to send a message and then return what it sends, back?
However, I wanted that client to be running until the use logs out, because other clients may connect to the chat. How can I accomplish that is kind of fuzzy for me. The code in client( $input ) is the same as in client.php.

Sorry for off-topic, but if you can, it would be better to use XMPP ready solution like ejabberd server with http-bind module. Sure, there is some cons it such solution, but cons are greater. Just look in this solution, maybe it will solve your problem with low cost.
see related answer with brief desc on XMPP solution

I think I understand what's going on. Sounds like you might be missing a listener? Usually chat programs have client-side ajax that checks or "listens" for messages for a particular user at regular intervals.
For example, if someone left a message for user x in your database (or wherever you're storing messages), the you might have some javascript that calls a php script every second to see if there are any messages on the server for user x. If there are, you can echo the message or messages back and received them via your ajax callback function.
If you're familiar with jQuery, check out the $.get method: http://api.jquery.com/jQuery.get/

As i understand your question, you want to send a message from the client to the server and as soon as this message gets to the server it will reply to all clients... i'm correct???
I do some chat like using nodejs and other javascripts tech... and must say a great option here is using web sockets. Realize that browser support is limited, but since you not specified what browsers need to run this i think a great way to go.
Check this related links:
How to Use Sockets in JavaScript\HTML?
http://socket.io/
A possible way of doing that only using php + js is make some function and put in a setInterval to make request to the server every 12 seconds. I made some kind of asp chat in 2005 that uses this approach. And i must say the web socket is much better.
I don't know if that answers your question... let me know!

I developed something along these lines before using PHP and jQuery. The solution I went for was due to the restrictions on the server setup(out of my control). I used a PHP core script to create the whole layout of the page from message window to message submission box. Any user that came to the page was given a randomly generated user like user123234234 generated off a unix timestamp from the time they entered the chat page.
All messages submitted were stored in an XML file and a new XMl file was created daily. The user was kept in a message node like below with details of the user for every message using different node attributes.
The message window was refreshed every 5 seconds using jquery AJAX call to another PHP script that read in the XML that days XML file only from the time the user entered the chat page.
<messages>
<message user="user123456" ip="127.0.0.1" session="{users session ID here}" time="{unix timestamp}"><![CDATA[User message here]]></message>
</messages>
There is a lot more logic behind it but I found it the easiest to develop and maintain, I hope it help point you in the right direction. And it works on all major browsers and from IE7+.

Related

ZeroMQ send/receive on PHP works if script launched from CLI/shell but not from APACHE/web request

I'm testing ZeroMQ for PHP. My goal is to send messages to a Python script.
Everything works fine if i launch my transmission script from PHP cli
php /path/to/myscript.php
while it fails if it's a web request. I've tried executing the server script from PHP cli as above (which seems to be the more logical way) and with a web request.
I've got a Centos 7 server with PHP 7.2 and ZeroMQ 1.1.3 installed through PECL install.
I even tried launching the above command with shell_exec/exec inside the client script but it doesn't work. Connection works fine, but it doesn't send nor receive.
Client code:
$context = new ZMQContext();
// Socket to talk to server
echo "Connecting to hello world server...\n";
$requester = new ZMQSocket($context, ZMQ::SOCKET_REQ);
$currentObject = $requester->connect("tcp://localhost:5555");
for ($request_nbr = 0; $request_nbr != 10; $request_nbr++) {
printf ("Sending request %d...\n", $request_nbr);
$risSend = $requester->send("Hello", ZMQ::MODE_NOBLOCK);
print_r($risSend);
$reply = $requester->recv();
printf ("Received reply %d: [%s]\n", $request_nbr, $reply);
}
Server Code:
$context = new ZMQContext(1);
// Socket to talk to clients
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);
$responder->bind("tcp://*:5555");
while (true) {
// Wait for next request from client
$request = $responder->recv();
printf ("Received request: [%s]\n", $request);
// Send reply back to client
$responder->send("World");
}
The browser gets stuck, without any error. Even using a timeout it reaches the limit and exits but I can't get any error message.
Ok, i finally found the solution.
Thanks to #user3666197 i managed to get an error. And it was a "permission denied" error.
With CentOS (and probably all linux sytems with SELinux) you gotta add a rule for the port used by ZMQ for the webserver.
Example:
semanage port -a -t http_port_t -p tcp 5555
OBSERVATION : The browser gets stuck, without any error.
This is pretty legal state. For it to happen, it is quite enough to "miss" the arrival of the first REQ-side-already dispatched request and due to a pleasure do depend on a distributed-Finite-State-Automaton, we fall into an unsalvageable dead-lock, where the REQ-side waits for an answer, that will never arrive (see next) and the REP-side waits for a request, that will never arrive (see the REQ-side already waiting ) and such a state remains forever that.
A best next step:
In case one has never worked with ZeroMQ,
or have never met the concept of the art of Zen-of-Zero,
one may here enjoy to first look at "ZeroMQ Principles in less than Five Seconds" before diving into further details
Start
with unconditionally working archetypes - a pair of PUSH / PULL simplex-channels, that do not require a dFSA-two-step of REQ-REP-REQ-REP-REQ-REP-...-{deadlock} ... a principally unavoidable terminal state, about which one is just never sure when it happens, but it will ... at some later time :o)
Next,
may increase a robustness of the message-flow, using zmq_setsockopt( ZMQ_IMMEDIATE, 1 ) that avoids moving messages onto incomplete connections between / among peers.
Always
prefer non-blocking forms of .recv()-methods, best with a pre-test of a message-presence with a .poll()-method. Poller-class, while available in many language-bindings is not always as handy and as flexible as using explicit .poll()-method directly on a Socket-instance.
Also feel free to read more about fine-tuning the ZeroMQ tools and other implications of the Art of the Zen-of-Zero here.
A Server-side mock-up: As a { PASS | FAIL }-proof of .send()---.recv()-delivery chain works?
<?php /* Create new PUSH-ing end */
$aCTX = new ZMQContext();
try { /* Try: things may turn wreck havoc */
$PUSHer = $aCTX->getSocket(, ZMQ::SOCKET_PUSH );
echo "POSACK'd: .getSocket() was made\n";
}
catch ( ZMQSocketException $e ){
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else {
die( " - Get ERR: " . $e->getMessage() );
}
}
try { /* Try: things may turn wreck havoc */
$PUSHer->bind( "tcp://A.B.C.D:NNN" ); /* IP address to .connect() */
echo "POSACK'd: .bind() was made\n";
}
catch ( ZMQSocketException $e ){
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else {
die( " - Get ERR: " . $e->getMessage() );
}
}
$retries = 1234567;
do { /* Start a loop */
try { /* Try: to PUSH.send() */
echo "Trying to send a message #" . ( 1234568 - $retries ) . "\n";
$PUSHer->send( "This is a message", ZMQ::MODE_DONTWAIT );
echo "POSACK'd: PUSHer.send() was made\n";
}
} catch ( ZMQSocketException $e ) {
echo " NACK'd: I told you ...\n"; /* Handle with care ... */
if ( $e->getCode() === ZMQ::ERR_... ) {
echo " - Got ERR_..., read ZeroMQ API documentation for details\n";
} else { /* For all ERR_... states */
die( " - Got ERR_...: " . $e->getMessage() );
}
}
/* --------------------------------------------------------------------
Here one may add an attempt to .recv( $PULLer, ZMQ::MODE_DONTWAIT );
and test for a non-empty string returned
-------------------------------------------------------------------- */
usleep( 1 ); /* Sleep a bit between operations */
} while ( --$retries );
?>
Client-side mock-up, to test the PUSH-er lives and .send()-s
import time, datetime, zmq; print( "Thissssss Sssssssssssssssssssssssssssssssssssssssnake uses ZeroMQ ver:{0:}".format( zmq.__version__ ) )
aCtx = zmq.Context()
aPull= aCtx.Socket( zmq.PULL )
aPull.setsockopt( zmq.LINGER, 0 ) # always ... be explicit
aPull_address2c = "tcp://A.B.C.D:NNN"
M0 = "{0:} try a .connect( {1:} ), if it gets to PUSH-er side"
M1 = "{0:} try a .recv(), if it gets any message"
M2 = "{0:} got a .recv()->[[[ {1:} ]]]"
M3 = "{0:} EXC'd will gracefully release resources and terminate..."
M4 = "{0:} did"
try:
print( M0.format( datetime.datetime.isoformat( datetime.datetime.now() ),
aPull_address2c
)
)
aPull.connect( aPull_address2c );
while True:
print( M1.format( datetime.datetime.isoformat( datetime.datetime.now() ) )
m = aPull.recv( zmq.NOBLOCK ) # always ... avoid blocking waits
if ( len( m ) > 0 ):
print( M2.format( datetime.datetime.isoformat( datetime.datetime.now() ),
str( m ) # always ... fused to str()
)
)
time.sleep( 5 )
else:
time.sleep( 1 )
pass
################################################################
# Here one may add an attempt to aPush.send( M4, zmq.NOBLOCK )
# and test if the reverse path aPush->$PULLer goes well
################################################################
except:
print( M3.format( datetime.datetime.isoformat( datetime.datetime.now() ) )
finally:
aPull.close() # always ... be explicit
aCtx.term() # always ... be explicit
print( M4.format( datetime.datetime.isoformat( datetime.datetime.now() ) )

PHP socket connections: read and send data in loop

I have to make a function, in which I send a packet to server and then read data. After a while I sometimes require to send a data to server again using the same socket (it's required that I use the same one).
For some reason second send, which is after read doesn't send data (it returns correct number (not false), but server doesn't receive packet). If I create new socket and send data - it works.
Here is an example:
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '192.168.1.179', 1455);
socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
$this->socket_functions->send_message($socket,$sendMsg,$funcName);
$tmp = trim($this->socket_functions->read_packet($socket));
for($i =0; $i<10; $i++)
{
$tmp = trim($this->socket_functions->read_packet($socket));
$this->socket_functions->send_message($socket, 'AAAA', $funcName); //doesn't work
/*
///works
$socket2 = $this->socket_functions->create_socket();
$this->socket_functions->send_message($socket2, 'AAAA', $funcName);
$this->socket_functions->disconnect($socket2);
*/
}
Function create_socket does the same as first 3 lines so the connection data is the same. I just brought it out so you are able to see my configuration.
For read and write I use functions socket_send() and socket_write().
Read packet function:
$resultMsg = "";
while(strlen($currentData = socket_read($socket,256))==256)
{
$resultMsg .=$currentData;
}
$resultMsg.=$currentData;
if(strlen($resultMsg)>1 && strpos($resultMsg,'<')>0)
{
$resultMsg = substr($resultMsg,strpos($resultMsg,'<'));
}
return $resultMsg;
Sending packet:
function create_packet($msg, $type)
{
$msg = $type.$this->convert_data->IntToAsciiChars(strlen($msg)).$msg;
$msg = chr(0).$this->convert_data->IntToAsciiChars(strlen($msg)).$msg;
return $msg;
}
function send_message($socket,$msg,$type)
{
$packet = $this->create_packet($msg,$type);
$res = socket_send($socket,$packet,strlen($packet),0);
if($res === false) return false;
return true;
}
EDIT
I did more testing and found out, that this only occurs, if the server, to which I'm connected keeps sending data. As in - the server sends multiple packets in row. If I try to send packet before the server has sent all of them, the packet isn't received. Does anyone knows why is this happening? I have desktop application, which does the same thing (sends data using the same socket while server is sending data), but it works there. Is there something specific?
I finally managed to fix this. After testing I found out, if I used send n+1 times to send the message, where n is amount of times read was called , I was able to send a message then.
I really don't know why this worked - maybe someone here knows?

Good method to authenticate files to users

I'm developing an API to let my users access to files stored on another server.
Let's call my two servers, server 1 and server 2!
server 1 is the server im hosting my web site, and
server 2 is the server im storing my files!
My site is basically Javascript based one, so I will be using Javascript to post data to API when user needs to access files which are stored on server 2.
when users requests to access files, the data will be posted to API URL via Javascript! API is made of PHP. Using that PHP script(API) on server 1, I will made another request to server 2 asking for files so there will be another PHP script(API) on server 2.
I need to know how should I do this authentication between two servers as server 2 has no access to user details on server 1?
I hope to do that like this, I can use the method which is used by most payment gateways.
When API on server 2 received a request with some unique data of the user , post back those unique data through SSL to server 1 API and match them with user data in the database, then post back result through SSL to server 2 so then server 2 knows file request is a genuine request.
In this case what kind of user data/credentials server 1 API should post to server 2 and server 2 API should post back to server 1? and which user data should be matched with the data in the database? like user ID, session, cookies, ip, time stamp, ect!
Any clear and described answer would be nice! Thanks.
I would go with this:
user initiates action, javascript asks Server 1 (ajax) for request for file on Server 2
Server 1 creates URL using hash_hmac with data: file, user ID, user secret
when clicking that URL (server2.com/?file=FILE&user_id=ID&hash=SHA_1_HASH) server 2 asks server 1 for validation (sends file, user_id and hash)
server 1 does the validation, sends response to server 2
server 2 pushes file or sends 403 HTTP response
This way, server 2 only needs to consume API of server 1, server 1 has all the logic.
Pseudocode for hash and url creation:
// getHash($userId, $file) method
$user = getUser($userId);
$hash = hash_hmac('sha1', $userId . $file, $user->getSecret());
// getUrl($userId, $file) method
return sprintf('http://server2.com/get-file?file=%1&user_id=%2&hash=%3',
$userId,
$file,
$security->getHash($userId, $file)
);
Pseudocode for validation:
$hash = $security->getHash($_GET['id'], $_GET['file']);
if ($hash === $_GET['hash']) {
// All is good
}
Edit: getHash() method accepts user ID and file (ID or string, what ever suits your needs). With that data, it produces a hash, using hash_hmac method. For the secret parameter of hash_hmac function, users "secret key" is used. That key would be stored together with users data in the db table. It would be generated with mt_rand or even something stronger as reading /dev/random or using something like https://stackoverflow.com/a/16478556/691850.
A word of advice, use mod_xsendfile on server 2 (if it is Apache) to push files.
Introduction
You can use 2 simple method
Authentication Token
Signed Request
You can also combine both of them by using Token for authentication and using signature to verify integrity of the message sent
Authentication Token
If you are going to consider matching any identification in the database perhaps you can consider creating authentication token rather than user ID, session, cookies, ip, time stamp, etc! as suggested.
Create a random token and save to Database
$token = bin2hex(mcrypt_create_iv(64, MCRYPT_DEV_URANDOM));
This can be easily generated
You can guaranteed it more difficult to guess unlike password
It can easily be deleted if compromised and re generate another key
Signed Request
The concept is simple, For each file uploaded must meat a specific signature crated using a random generated key just like the token for each specific user
This can easily be implemented with HMAC with hash_hmac_file function
Combine Both Authentication & Signed Request
Here is a simple Prof of concept
Server 1
/**
* This should be stored securly
* Only known to User
* Unique to each User
* Eg : mcrypt_create_iv(32, MCRYPT_DEV_URANDOM);
*/
$key = "d767d183315656d90cce5c8a316c596c971246fbc48d70f06f94177f6b5d7174";
$token = "3380cb5229d4737ebe8e92c1c2a90542e46ce288901da80fe8d8c456bace2a9e";
$url = "http://server 2/run.php";
// Start File Upload Manager
$request = new FileManager($key, $token);
// Send Multiple Files
$responce = $request->send($url, [
"file1" => __DIR__ . "/a.png",
"file2" => __DIR__ . "/b.css"
]);
// Decode Responce
$json = json_decode($responce->data, true);
// Output Information
foreach($json as $file) {
printf("%s - %s \n", $file['name'], $file['msg']);
}
Output
temp\14-a.png - OK
temp\14-b.css - OK
Server 2
// Where to store the files
$tmpDir = __DIR__ . "/temp";
try {
$file = new FileManager($key, $token);
echo json_encode($file->recive($tmpDir), 128);
} catch (Exception $e) {
echo json_encode([
[
"name" => "Execption",
"msg" => $e->getMessage(),
"status" => 0
]
], 128);
}
Class Used
class FileManager {
private $key;
function __construct($key, $token) {
$this->key = $key;
$this->token = $token;
}
function send($url, $files) {
$post = [];
// Convert to array fromat
$files = is_array($files) ? $files : [
$files
];
// Build Post Request
foreach($files as $name => $file) {
$file = realpath($file);
if (! (is_file($file) || is_readable($file))) {
throw new InvalidArgumentException("Invalid File");
}
// Add File
$post[$name] = "#" . $file;
// Sign File
$post[$name . "-sign"] = $this->sign($file);
}
// Start Curl ;
$ch = curl_init($url);
$options = [
CURLOPT_HTTPHEADER => [
"X-TOKEN:" . $this->token
],
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_POST => count($post),
CURLOPT_POSTFIELDS => $post
];
curl_setopt_array($ch, $options);
// Get Responce
$responce = [
"data" => curl_exec($ch),
"error" => curl_error($ch),
"error" => curl_errno($ch),
"info" => curl_getinfo($ch)
];
curl_close($ch);
return (object) $responce;
}
function recive($dir) {
if (! isset($_SERVER['HTTP_X_TOKEN'])) {
throw new ErrorException("Missing Security Token");
}
if ($_SERVER['HTTP_X_TOKEN'] !== $this->token) {
throw new ErrorException("Invalid Security Token");
}
if (! isset($_FILES)) {
throw new ErrorException("File was not uploaded");
}
$responce = [];
foreach($_FILES as $name => $file) {
$responce[$name]['status'] = 0;
// check if file is uploaded
if ($file['error'] == UPLOAD_ERR_OK) {
// Check for signatire
if (isset($_POST[$name . '-sign']) && $_POST[$name . '-sign'] === $this->sign($file['tmp_name'])) {
$path = $dir . DIRECTORY_SEPARATOR . $file['name'];
$x = 0;
while(file_exists($path)) {
$x ++;
$path = $dir . DIRECTORY_SEPARATOR . $x . "-" . $file['name'];
}
// Move File to temp folder
move_uploaded_file($file['tmp_name'], $path);
$responce[$name]['name'] = $path;
$responce[$name]['sign'] = $_POST[$name . '-sign'];
$responce[$name]['status'] = 1;
$responce[$name]['msg'] = "OK";
} else {
$responce[$name]['msg'] = sprintf("Invalid File Signature");
}
} else {
$responce[$name]['msg'] = sprintf("Upload Error : %s" . $file['error']);
}
}
return $responce;
}
private function sign($file) {
return hash_hmac_file("sha256", $file, $this->key);
}
}
Other things to consider
For better security you can consider the follow
IP Lock down
File Size Limit
File Type Validation
Public-Key Cryptography
Changing Date Based token generation
Conclusion
The sample class can be extended in so many ways and rather than use URL you can consider a proper json RCP solution
A long enough, single-use, short-lived, random generated key should suffice in this case.
Client requests for a file to Server 1
Server 1 confirms login information and generates a long single-use key and sends it to the user. Server 1 keeps track of this key and matches it with an actual file on Server 2.
Client sends a request to Server 2 along with the key
Server 2 contacts Server 1 and submits the key
Server 1 returns a file path if the key is valid. The key is invalidated (destroyed).
Server 2 sends the file to the client
Server 1 invalidates the key after say 30 seconds, even if it didn't receive a confirmation request from Server 2. Your front-end should account for this case and retry the process a couple of times before returning an error.
I do not think there is a point in sending cookie/session information along, this information can be brute-forced just like the random key.
A 1024-bit long key sounds more than reasonable. This entropy can be obtained with a string of less than 200 alphanumeric characters.
For the absolute best security you would need some communication from server 2 to server 1, to double check if the request is valid. Although this communication could be minimal, its still communication and thus slows down the proces.
If you could live with a marginally less secure solution, I would suggest the following.
Server 1 requestfile.php:
<?php
//check login
if (!$loggedon) {
die('You need to be logged on');
}
$dataKey = array();
$uniqueKey = 'fgsdjk%^347JH$#^%&5ghjksc'; //choose whatever you want.
//check file
$file = isset($_GET['file']) ? $_GET['file'] : '';
if (empty($file)) {
die('Invalid request');
}
//add user data to create a reasonably unique fingerprint.
//It will mostlikely be the same for people in the same office with the same browser, thats mainly where the security drop comes from.
//I double check if all variables are set just to be sure. Most of these will never be missing.
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$dataKey[] = $_SERVER['HTTP_USER_AGENT'];
}
if (isset($_SERVER['REMOTE_ADDR'])) {
$dataKey[] = $_SERVER['REMOTE_ADDR'];
}
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$dataKey[] = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
}
if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
$dataKey[] = $_SERVER['HTTP_ACCEPT_ENCODING'];
}
if (isset($_SERVER['HTTP_ACCEPT'])) {
$dataKey[] = $_SERVER['HTTP_ACCEPT'];
}
//also add the unique key
$dataKey[] = $uniqueKey;
//add the file
$dataKey[] = $file;
//add a timestamp. Since the request will be a different times, dont use the exact second
//make sure its added last
$dataKey[] = date('YmdHi');
//create a hash
$hash = md5(implode('-', $dataKey));
//send to server 2
header('Location: https://server2.com/download.php?file='.urlencode($file).'&key='.$hash);
?>
On server 2 you will do almost the same.
<?php
$valid = false;
$dataKey = array();
$uniqueKey = 'fgsdjk%^347JH$#^%&5ghjksc'; //same as on server one
//check file
$file = isset($_GET['file']) ? $_GET['file'] : '';
if (empty($file)) {
die('Invalid request');
}
//check key
$key = isset($_GET['key']) ? $_GET['key'] : '';
if (empty($key)) {
die('Invalid request');
}
//add user data to create a reasonably unique fingerprint.
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$dataKey[] = $_SERVER['HTTP_USER_AGENT'];
}
if (isset($_SERVER['REMOTE_ADDR'])) {
$dataKey[] = $_SERVER['REMOTE_ADDR'];
}
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$dataKey[] = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
}
if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
$dataKey[] = $_SERVER['HTTP_ACCEPT_ENCODING'];
}
if (isset($_SERVER['HTTP_ACCEPT'])) {
$dataKey[] = $_SERVER['HTTP_ACCEPT'];
}
//also add the unique key
$dataKey[] = $uniqueKey;
//add the file
$dataKey[] = $file;
//add a timestamp. Since the request will be a different times, dont use the exact second
//keep the request time in a variable
$time = time();
$dataKey[] = date('YmdHi', $time);
//create a hash
$hash = md5(implode('-', $dataKey));
if ($hash == $key) {
$valid = true;
} else {
//perhaps the request to server one was made at 2013-06-26 14:59 and the request to server 2 come in at 2013-06-26 15:00
//It would still fail when the request to server 1 and 2 are more then one minute apart, but I think thats an acceptable margin. You could always adjust for more margin though.
//drop the current time
$requesttime = array_pop($dataKey);
//go back one minute
$time -= 60;
//add the time again
$dataKey[] = date('YmdHi', $time);
//create a hash
$hash = md5(implode('-', $dataKey));
if ($hash == $key) {
$valid = true;
}
}
if ($valid!==true) {
die('Invalid request');
}
//all is ok. Put the code to download the file here
?>
You can restrict access to server2. Only server1 will be able to send request to server2. You can do this by whitelisting ip of server1 on server side or using .htaccess file. In php you can do by checking request generated ip and validate it with server1 ip.
Also you can write a algorithm which generates a unique number. Using that algorithm generate a number on server1 and send it to server2 in request. On server2 check if that number is generated by algorithm and if yes then request is valid.
I'd go with a simple symetric encryption, where server 1 encodes the date and the authenticated user using a key known only by server 1 and server 2, sending it to the client who cant read it, but can send it to server 2 as a sort of ticket to authenticate himself. The date is important to not let any client use the same "ticket" over the time. But at least one of the servers must know which user have access to which files, so unless you use dedicated folders or access groups you must keep the user and file infos together.

getting return data from url

I'm trying to submit user information to a URL using GET, and then get the errors (if there any) and use them to tell the customer what went wrong. So, currently I have a form that submits this customer info into an iframe (so the page is not redirected and I can see the response from my shopping cart software). when the info is submitted, this is the response I get from the shopping cart server:
errorFound=1&responseCode=329&...etc.
I need to get this response code, and was wondering what the most simple way would be to do it. Once I get it I can tell the customer what the problem is... Should I use java to read the
data in the iframe once it loads? or can I use something like Fopen to open the URL and get the return data (can't enable fopen on my server though, but something like it?).
Java != javascript
A quick way to do it:
$errorcodes = array("329" => "Wrong blabla");
if( isset( $_GET['errorFound'] ) && isset( $_GET['responseCode'] ) ){
$errorNr = (int) $_GET['responseCode'];
$error = getErrorFromDB();
//OR
//$error = isset( $erorCodes[ $errorNr ] )? $errorcodes[ $errorNr] : false;
if( $error !== false){
exit( "<script type='text/javascript'>
alert( '".htmlspecialchars($error)."' )
</script>");
}
}
function getError( $code )
{
$code = (int) $code;
$db = getYourPdoInstance();
$q = $db->prepare("SELECT `message` FROM `errorCodes` WHERE `errorCode` = ?");
$q->execute( array( $code) );
$return = $q->fetch(2);
return isset($return['message'])?$return['message']:false;
}

PHP IRC Robot, Send Command, but now I need the bot to read the command

I have a PHP IRC Robot that I use in my channel and I need it to make OPs to specific set users in the script by me. Anyways I want the robot to check if the user is logged into NickServ to prevent any sort of fraud or anything.
Anyways, here is my connect and DO things code, followed by what I really need help with below it. All help is appreciated. :)
On Freenode, typing /NS ACC [user] will return whether or not the [user] is logged in with a numerical value, they decided 3 would be logged in. and 0-2 as some sort of not logged in.
So here is how the bot logs into my IRC channel... (feel free to join #tyreus on freenode, ask for BwaddArr (or his email))
<?php
set_time_limit(0); //Stop the script timing out
$server = "irc.freenode.net"; //server to connect to
$channel = "#tyreus"; //channel to connect to initialy
$password = "sumpass"; //password for bot to login to irc
$pass2 = "anotherpass"; //password to make the bot do stuff
$users[0] = "0"; //array of logged in users
$nickname = "Samcal"; //Set the bot's nick here
$logger = FALSE; //for the channel logger
$takeover = FALSE; //for the auto banner
$socket=fsockopen($server,'6667') ; //Connect and join the channel
stream_set_timeout($socket, 300); //Set a timeout value (so the bot quits if it's disconnected)
fwrite($socket, "NICK ".$nickname."\r\n");
fwrite($socket, "USER ".$nickname." 8 * ::\x01VERSON 1.0 Brad's bot\x01\n"); //read rfc 1459 to understand this line
while ($line=fgets($socket)) {
echo htmlentities($line)."<br>";
if (strpos($line, "433")>0) die("error nick in use"); //Quit if bot's nick is already taken (irc code 433 is received)
if (strpos($line, "004")>0) {
fwrite($socket, "JOIN ".$channel."\r\n"); //Join the channel if everything is ok (irc code 004 is received)
fwrite($socket, "NickServ IDENTIFY ".$nickname." ".$password."\r\n");
fwrite($socket, "ChanServ OP ".$channel." Samcal\r\n");
fwrite($socket, "MODE ".$channel." +v Samcal \r\n");
break;
}
}
And this is where i really need all the help! :)
if(strpos($line, "PRIVMSG ".$channel." :+oB\r\n")>0) { //Command to make the bot run the command
$name = "BwaddArr"; // my username, this can be easily changed to the other users who will need opping
$command = "NickServ ACC $name"; // the NickServ command I was talking about
$result = fwrite($socket, "$command \r\n"); // my attempt at retrieving the result
$accr = readline(strpos($line, "$result \r\n")); //part 2 of my failure to retrieve a result
$loggd = str_replace("3","three","$accr"); // replace '3' with 'three'
if($loggd != "three") { // if result is not three do below
fwrite($socket, "PRIVMSG ".$channel." :$name is not logged in. \r\n"); // write into the chat that the user is not logged in
}
if($loggd == "three") { // OP the user if they are logged in
fwrite($socket, "MODE ".$channel." +ov $name\r\n"); // sends the OPping command
}
}
?>
I assume the second snippet resides inside your while(fgets()) loop.
You won't have your result in the loop where you use fwrite() then. Either add another fgets() after
$result = fwrite($socket, "$command \r\n");
or consequently use your loop and maybe add a status flag to know how to treat the next execution of its body.
First of all, remove the password for your bot.(fixed)
Gave some tips on your IRC, good luck, you're on the right track now.
I did one, when I was young.
I used that kind of loop :
$irc = fsockopen($server, $port);
// ...
while(!feof($irc))
{
$line = fgets($irc, 2048);
// ...
// Parsing $line here
// ...
}
Hope this helps.
In your last code snippet you open your socket named $irc and write to a socket called $socket.
Either fix this or show us some more of your code where you use/introduce $socket.

Categories