I'm using PHP version 5.3.2 on both my local development server and remote web server.
I'm trying to use uploadify to upload several files to the server. In the receiving script, I would like to use data stored in the session, however because uploadify sends files to the script using flash it doesn't send the session cookie.
The workaround for this problem is to get uploadify to GET or POST the session id to the script, however I'm finding this very unreliable.
In my script I have the following:
<?php
ini_set('session.use_only_cookies', FALSE);
ini_set('session.use_trans_sid', TRUE);
session_name('SESSNAME');
session_start();
print_r($_SESSION);
The script url is something like script.php?SESSNAME=sessionid and I have tried using transparent session ids as above and also manually setting the id using session_id($_GET['SESSNAME']).
This always works when accessing the script directly with the browser and sending the current session id along, even if I manually delete the session cookie. It also always works with uploadify on my local server. However when using uploadify on the remote server, it works about 20% of the time, completely randomly. There is no pattern. It seemed to work with greater frequency when I added
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 1);
to the script, however this may have been just coincidence.
Local server info: http://www.dur.ac.uk/n.r.brook/info_local.php
Remote server info: http://www.dur.ac.uk/n.r.brook/info.php
Some speculation...
Doing some digging around and looking at the headers the script is receiving, I think I may have determined the issue.
You need to send the session id when using uploadify because flash does not send cookies when using the FileReference.upload() (I think!) method. However, as well as the session id, in load balanced environments (such as the remote server) there is also the BALANCEID cookie which determines which server the user is currently working with. Flash doesn't send this cookie so the load balancer sometimes sends the request to a different server, and on this server the session does not exist.
I have tested this behaviour by setting a session variable after I have printed the session. Doing this and repeatedly sending files exhibits the issue - at first I get an empty array, but a few repeats in the variable starts appearing.
So, if the above is all true, then my question is what can I do to get flash to send this data with the upload so the load balancer knows which server to use? Or is this a lost cause?
The answer?
After further research, I found the following post - http://swfupload.org/forum/generaldiscussion/977
This suggests there is no way cookies can be sent with FileReference.upload() and therefore uploadify cannot be used with load balanced servers if you want to use session data. However, I think I will now attempt a solution which saves data linked to the session id to a file. The uploadify receiving script can open this file and pull out the required data.
This is my first experience working with anything Flash based, it has not improved my opinion of the technology!
My solution to this problem is:
In the 'upload' page:
file_put_contents($some_folder.'/'.session_id(), serialize($just_the_vars_you_will_be_using));
In your javascript that loads uploadify:
var start = document.cookie.indexOf("PHPSESSID=");
var end = document.cookie.indexOf(";", start); // First ; after start
if (end == -1) end = document.cookie.length; // failed indexOf = -1
var cookie = document.cookie.substring(start+10, end);
$('#fileInput').uploadify({
'uploader' : 'uploadify.swf',
'script' : 'uploadify.php',
'cancelImg' : 'cancel.png',
'auto' : true,
'multi' : true,
'scriptData': { SESSID : cookie }
});
In the script that receives the files:
$vars = unserialize(file_get_contents($some_folder.'/'.$_POST['SESSID']));
If you want to write back to the 'session' in this script, at the end:
file_put_contents($some_folder.'/'.$_POST['SESSID'], serialize($vars));
As far as I know, there shouldn't be any security issues associated with this, as you will only be using a handful of variables stored in the file (I only store an incrementing value and a temporary file path). Make sure there is an index.html in $some_folder to prevent file listing.
There is a way you can use cookies when sending from flash.
Cookies is needed for php to find the session storage id. The value that is stored in the cookie is actual the session id and the cookie name is in most cases the session name.
To get the session in php can´t be done by typing $_SESSION['name'] but you can make your own session library that you include. This will let php get all of the nassery values and you can continue.
Here is a session library that I put together in php:
function SESSION_OPEN($PATH,$NAME){
global $SESSION_PATH, $SESSION_NAME;
$SESSION_PATH=$PATH;
$SESSION_NAME=$NAME;
return(true);
}
function SESSION_CLOSE(){
return(true);
}
function SESSION_GET($ID){
global $SESSION_PATH, $SESSION_NAME;
$STR_PATH="$SESSION_PATH/USES_".session_id()."_$ID";
if($RESOURCE = #fopen($STR_PATH,"r")){
$CONTENT = #fread($RESOURCE ,filesize($STR_PATH));
return($CONTENT);
}else{
return(false);
}
}
function SESSION_PUT($ID,$VALUE){
global $SESSION_PATH, $SESSION_NAME;
$STR_PATH="$SESSION_PATH/USES_".session_id()."_$ID";
if($RESOURCE = #fopen($STR_PATH,"w")){
fwrite($RESOURCE , $VALUE );
return(true);
}else{
return(false);
}
}
function SESSION_DEST($ID){
global $SESSION_PATH, $SESSION_NAME;
$STR_PATH="$SESSION_PATH/USES_".session_id()."_$ID";
return(#unlink($STR_PATH));
}
function SESSION_GC($MAX_EXECUTION){
return(true);
}
session_set_save_handler("SESSION_OPEN","SESSION_CLOSE","SESSION_GET","SESSION_PUT","SESSION_DEST","SESSION_GC");
Related
It was been a couple of days I've got an issue with php session (in cakePhp 4 project) with a redis cluster and ajax call that not save in session.
Use case :
I'm on a page with a session, session works perfectly. on this page there is à button that call an ajax action. On https://www.mywebsite.com ajax call https://www.mywebsite.com/ajaxAction (so no cross origin pb like I see a lot of time)
ajaxAction is very simple :
public function ajaxAction()
{
$this->disableAutoRender();
$treeId = (int) $this->request->getData('treeId');
var_dump($_SESSION['myArray']); // empty
$_SESSION['myArray'][$treeId] = true;
var_dump($_SESSION['myArray']); // array with the value
}
If I click to add an other $treeId in the session, the first debug is empty, and the second has only the new value.
When I check the session value in redis-cli, the value is not in the session.
If I put a sleep(1) after the $_SESSION['myArray'][$treeId] = true; the value is save in the session.
If I'm trying the same type of call with two simple php script (without cakePhp), it works perfectly....
Someone has a solution to understand the pb to find a solution ?
Is it from cakePhp ? Redis ? Ajax ?
Thanks for you're help
EDIT :
After another day of testing and searching a solution, the problem is only with cakephp. The only solution I've found is to make a usleep(100000); but it's not a solution of the problem for me....
EDIT 2 the return :
After analysing redis monitor, I could see that cakephp make two call to set the session during an ajax request. First save the new session, then save the old value of the session. It explains why with a sleep the new session is save after the old value.
Next step, undertand why cakephp make the two call of the session set (outside cakephp, there is only on cool in case of ajax request....)
I'm trying to get some values from my $_SESSION variable but it seems to be cleared everytime an AJAX request is initiated.
I have pasted the code below, any help much appreciated :
/*
* The input request from angularjs
*/
$data = file_get_contents("php://input");
$data = json_decode($data, true);
switch( strtolower($data['action']) ) {
case 'products': getAllProducts($data['fields']);
break;
default : echo json_encode(array('success' => false));
}
//fb is a firebug debug function, prints PHP vars to console.
fb($_SESSION['var'); //when loading the php file the first time $_SESSION is set
UPDATE
I'm using AngularJS for my AJAX calls, it works great but now I want to read data from my $_SESSION variable and all I get is an empty $_SESSION. Does this have anything to do with my file_get_contents("php://input");
SOLVED
I found the problem, the previous developer did not take into account that one might desire to include files from 2 levels deep :) As such, I scanned through the PHP error logs and saw that a previous script was not loading - this particular script was included with the session_start and $_SESSION variable values.
Checking the error logs will be my first priority from now on
I found the problem, the previous developer did not take into account that one might desire to include files from 2 levels deep :) As such, I scanned through the PHP error logs and saw that a previous script was not loading - this particular script was included with the session_start and $_SESSION variable values. Checking the error logs will be my first priority from now on
I have Apache set up through xampp to test a webpage to load some .php file to read a .csv file as data source to output a bar graph chart. And I encounter this error on Chrome.
Unsafe JavaScript attempt to access frame with URL file:///C:/xampp/htdocs/search/php/loader/csvFileUploader.php from frame with URL file:///C:/xampp/htdocs/search/stackedBarChart.html. Domains, protocols and ports must match.
upclick-min.js:99
i.onload_callback.i.onload_callback upclick-min.js:99
onload
I don't think this is an iframe problem like many other posts have suggested. I tested this also through firefox, it went beyond reading the php but doesn't load the .csv file from local directory.
Any suggestions?
<script>
var uploaderCSV = document.getElementById('uploaderCSV');
upclick({
element : uploaderCSV,
action : 'php/loader/csvFileUploader.php',
onstart : function(filename) {
console.log(" -- Start upload: <" + filename + "> Here");
},
oncomplete : function(response_data) {
alert(response_data);
console.log(" -- CSV file to load: ", response_data);
var n = response_data.split("|");
if (n.length > 1) {
console.log(" >> csv file loaded at[ ", n[1], " ]");
loadDayLightFactor("php/loadCSV.php", "../" + n[1]);
}
}
});
</script>
and here's the php file
<?php
// using upload at click from http://code.google.com/p/upload-at-click/
// FileData is the name for the input file
$file_result = "";
$file = $_FILES['Filedata'];
$allowedExtensions = array("csv", "txt");
$extension = end(explode(".", $file["name"]));
echo "123".$file;
?>
Your problem seems to be the URL you are trying to reach:
file:///C:/xampp/htdocs/search
This is not the way to develop on local environment.
try to access it through
http://localhost/search
I'm sure it will work better. detailed explanation below..
This is happening because of a security standard called Cross-Domain-Policy
You can not make a call (via JavaScript) to files with a URL that is different from your current URL Address.
For example:
My website's URL is foobar.com, I'm trying to send an AJAX request to barbaz.com.
I can't!
because it's not my domain. I can try sending requests to barbaz.foobar.com (using some JavaScript code).
Another scenario that will show you why this is a "must have" security standard:
Lets say that I'm logged into my bank's website using a cookie. the cookie is persistent.
I'm entering a random website X that send AJAX request to all known bank websites. If I'm still logged into my bank's website, X website can "talk" to the bank's website using my user, and do things that I'm not aware of.
This is a small example why this is very important.
I hope this was helpful.
I need to call php script from main script that will run in background (i just want to call and proceed without waiting for response)
But I need access to user session in called script
My advice is don't use default PHP session because it might be tricky working with background process .... I would recommend session_set_save_handler http://www.php.net/manual/en/function.session-set-save-handler.php for a DB bases session
There is a good example here http://www.php.net/manual/en/function.session-set-save-handler.php#96305
Call
string file_get_contents ( string $filename [, bool $use_include_path = false [, resource $context [, int $offset = -1 [, int $maxlen ]]]] )
with $maxlen =0;
In filename you can give the url. In that url pass session id and in the called script set session id using session_id() and then call session_start().
Make sure that called script returns at least 520 dummy characters using flush() and ob_flush(), so that calling script do not wait.
The whole point behind a "session" is so that a user client can connect to the server multiple times in a "state-less" fashion, yet still maintain "state" like one single connection. "Session" data is shared between multiple connections from the same user client.
When you spawn off a background process on the server, whether or not you're using PHP, the "session" no longer has any real meaning. The user might even shut his client machine off with no effect on the server background process.
With that in mind, using Cookies as suggested elsewhere is totally useless. Cookies are saved on the client machine, and the background process will have Zero access to it.
If there is client information that your background process will need, then the calling process needs to pass it to the background process somehow, either as some kind of parameter or as some kind of a data file.
I would recommend saving the "$_SESSION" variable as a Json-encoded data string to a temporary file. The background process can read that file, Json-decode it back into an array, then use it just as if it were still a $_SESSION. Then remove the temporary file.
$_COOKIE['PHPSESSID'] = 'user_session_id';//Transfer parameters through $GLOBALS['argv']
session_start();
I'm working on a major Flash project that is going to be the core content of a site.
As most of you well know, almost any site can be entirely copied by copying the cached files and the hierarchy (files and folders structure), and it would run without problems on an Apache server with PHP enabled, if used.
What I would like to know is: How to bind SWF files to run on a specific host?
The SWFs will be encrypted, so outsiders won't have access to the methods used to stop the SWF from running on a different host, question is: what method to use?
I think the solution could be hardcoding the host IP inside the SWF, so if the SWF is looking for 123.123.123.123, only a host with that IP would allow the SWF to run further.
The issue is that AS3 alone can't discover the host IP or could it if it's trying to load a resource file? Anyway, that's why I need your help.
EDIT: Ok, seems someone asked for something similar earlier: Can you secure your swf so it checks if it is running on a recognized environment?
I'll try that and see how it works, but the question is still open in case anyone has different suggestions.
I use this method to determine if I am on dev or production in my config files.
var lc:LocalConnection = new LocalConnection();
switch ( lc.domain ){
case "myDomain.com":
case "":// local file reference for dev
case "localhost":// local file reference for dev
case "dev.mydomain.com":// local file reference for dev
break;
default:
// unknown domain do crash the app here
}
One method you could try is a php script that the swf sends a request to and must receive a correct reply from before it continues to operate. Since people can't get at your server-side php, they can't get the needed code to simulate that reply.
The SWFs will be encrypted, so outsiders won't have access to the methods used to stop the SWF from running on a different host
Since the file will run on a client computer (and thus they key would have to be stored in an accessible way), this isn't really that much of a protection.
The best way would probably be to have part of the SWF-logic on the server, and not give access to that part from third party hosts (by using the crossdomain file).
Look into the idea of wrapping main inside a type of preloader, and putting main into a secure dir on the server. I cant remember how this gets around the cache problem, but it had to do with how the wrapper loads main.
Something like this:
// preloader.as (embedded in fla)
var imageLoader:Loader;
function randomNumber(low:Number=NaN, high:Number=NaN):Number
{
var low:Number = low;
var high:Number = high;
if(isNaN(low))
{
throw new Error("low must be defined");
}
if(isNaN(high))
{
throw new Error("high must be defined");
}
return Math.round(Math.random() * (high - low)) + low;
}
function loadImage(url:String):void {
imageArea.visible=false;
preloader.visible = true;
// Set properties on my Loader object
imageLoader = new Loader();
imageLoader.load(new URLRequest(url));
imageLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, imageLoading);
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
imageArea.addChild(imageLoader);
}
// DOIT!
loadImage("main.sw?"+randomNumber(1000,10000)); //NOT A TYPO!
//loadImage("main.swf"+randomNumber(1000,10000);
function imageLoaded(e:Event):void {
// Hide Preloader
preloader.visible = false;
}
function imageLoading(e:ProgressEvent):void {
// Get current download progress
var loaded:Number = e.bytesLoaded / e.bytesTotal;
// Send progress info to "preloader" movie clip
preloader.SetProgress(loaded);
}
/// this is main.sw //NOT A TYPO
<?php
// Tried this - abandoned
// session_start();
//
// if(isset($_SESSION["flash"])) {
// $referrer = $_SERVER["HTTP_REFERER"];
// $referrer = parse_url($referrer);
// if($referrer["host"] != $_SESSION["flash"]) {
// echo "Permission denied.";
// exit();
// }
// } else {
// echo "Permission denied.";
// exit();
// }
//
// unset($_SESSION["flash"]);
header("Content-type: application/x-shockwave-flash");
readfile("/secure/main.swf");
?>
// main.as
public function onCreationComplete(event:Event):void{
Security.allowDomain( "*" );
Security.loadPolicyFile( "crossdomain.xml" );
}
// crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
That should get you started. The idea here was to prevent anyone from getting main on their machine- I am not sure if it worked.
You may have a server-side page generate a key using a date-based algorithm which is passed via flash var to your swf. This way a "copied" key won't work because by that time, the valid date will have passed. From what I understand, this would essentially be like using an RSA token.
Aside from this, any security you have will also need code to be inside your SWF to validate your token. The problem here is that SWFs are known to decompile quite easily. Meaning that your code isn't safe :( You could obfuscate your AS3 in hopes to confuse any "hackers".
All in all, I've never attempted anything like this, so let us know how it goes!