0

I'm trying to make php save data on the server. Those data are generated through js script. However, I am unable to make the php create the file. The error msg I get is as follows: Warning: file_put_contents(data/) [function.file-put-contents]: failed to open stream: Is a directory in

I have checked the permissions and the php.ini for restrictions with zero success. Any ideas?

If I change the "data/" bit to "X", the server creates an empty file named X. Which seems strange. The commands used in the js script come from jsPsych.

Thanks a lot!

I append the code:

function saveData(name, data){
  var xhr = new XMLHttpRequest();

  xhr.open('POST', 'write_data.php');
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.send(JSON.stringify({filename: name, filedata: data}));
};

(...)

on_finish:

function(){
  saveData('subject-'+subject_id+'.csv', jsPsych.data.get().csv() );
}

<?php

$filename = 'data/'.$_POST['filename'];
$data = $_POST['filedata'];
file_put_contents($filename, $data);

?>
Jeroen Heier
  • 3,520
  • 15
  • 31
  • 32

3 Answers3

1

I am not an expert with Xhr & your style of doing it. I do however know jQuery, and regular JS.

Jquery method:

var postName = 'something'; // this is found with $_POST['postName'] in PHP
var postName2 = 'somethingElse'; 
$.post("path/yourFile.php", {postName:value, postName2:value}, function(data){
            if(data == 'success'){
                // complete success 
            } else {
                // assessment failed to save
                console.log(data); 
            }
        });

JS Methods:

The first thing you do, is open up your request...

var xhr= new XMLHttpRequest(); 
xhr.open("POST", "write_data.php", true);

Try this...

xhr.open("POST", "write_data.php", true);

Then you can either use this way of doing it...

xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("fname=Wubur&lname=Com");

Or the JSON way...

xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify({fname:"Harry", lname:"Potter"}));

yourFile.php (where we are POSTing to):

If you use the first method (NOT json)...

<?php 

if(isset($_POST['fname']) && isset($_POST['lname']){ // check for post param & permission to create template 
    // do stuff here... 
    echo 'success'; // if everything worked
} else {
    echo 'I need fname and lname!!!'; // no post params supplied 
}

?>

If you use JSON method...

<?php 

$data = json_decode(file_get_contents('php://input'), true);
$data2 = json_decode(file_get_contents('php://input'));
// try both, I forget which one it is...
echo "success";

?>
Nerdi.org
  • 895
  • 6
  • 13
  • Thank you! I have the structure as follows: .php is in a directory with the .html with the AJAX call and in that directory there is the "data" file where the .csv is supposed to go to. So if I got the gist of your response, I feel like the structure is set up properly. Am I right? – Petr Palíšek Apr 13 '18 at 19:03
  • I tried to change the content-type too and it didn't work :( – Petr Palíšek Apr 14 '18 at 09:27
  • You need to change the content type AND get rid of JSON stringify. On PHP do echo $_POST['filename'] – Nerdi.org Apr 14 '18 at 15:16
  • Like this? xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.send({filename: name, filedata: data}); – Petr Palíšek Apr 14 '18 at 20:50
  • I updated my answer. It has all the options. I believe you will be able to figure it out :) – Nerdi.org Apr 14 '18 at 21:13
  • You are my favourite person, thanks, will hop on it immediately. – Petr Palíšek Apr 14 '18 at 21:17
  • Ok, I did it and we definitely moved forward for which I thank you dearly :) The .php console now correctly shows the data. Only trouble now is that the file created does not have a correct name. Here's the code (I intentionally made it save to the same folder as the php to avoid trouble with the data dir): – Petr Palíšek Apr 14 '18 at 21:34
  • And I should add that printing both the "filename" and "data" shows exactly what it should. It's just that the file isn't ACTUALLY being named correctly, plus it appears some time after executing. – Petr Palíšek Apr 14 '18 at 21:40
  • It's working :) I didn't realize I should change the other part too. – Petr Palíšek Apr 14 '18 at 22:54
  • Oh awesome! Well if it helped you make sure u mark as answer(: also, I used to use same method as you. I highly recommend using jQuery $.post and $.get. a lot easier, also a lot of great options to use – Nerdi.org Apr 14 '18 at 23:00
  • Yeah, thanks for everything, I'll check the jQuery way for sure! – Petr Palíšek Apr 14 '18 at 23:02
0

My guess is $_POST['filename']; is empty. The error:

Warning: file_put_contents(data/) [function.file-put-contents]: failed to open stream: Is a directory

Is self explanatory and even shows data/. Notice the lack of file name after the "/"? Check your incoming post.

More Details

The Super Global $_POST does not have a key filename or that key is empty. This line of code $filename = 'data/'.$_POST['filename']; produces this: data/. So either $_POST['filename'] is empty or it does not exist. Use var_dump or print_r to examine $_POST and see what's in it.

gforce301
  • 2,944
  • 1
  • 19
  • 24
  • Thanks a bunch! I checked the console and it shows in "request payload" that the filedata as well as the filename is being sent correctly. – Petr Palíšek Apr 13 '18 at 18:20
  • Check your `$_POST` data in **PHP**. The error clearly shows "data/" which is indeed a directory and not a file name. – gforce301 Apr 13 '18 at 18:23
  • I'm really sorry but I'm a bit clueless on what do you mean. I suppose there is something essential eluding me. I tried something along these lines, but am still getting the same error: https://stackoverflow.com/questions/3496971/check-if-post-exists – Petr Palíšek Apr 13 '18 at 18:31
  • Try something like `print_r($_POST)` to see the exact structure of your data as it is being received by PHP. – Greg Schmidt Apr 13 '18 at 18:39
  • Thank you :). It showed an empty array (Array ( ) ). – Petr Palíšek Apr 13 '18 at 18:41
  • Right it's not showing up from your ajax call. And that is the problem. – gforce301 Apr 13 '18 at 18:42
  • Wow, thanks. I'm finally moving towards the solution, I hope. I have checked the AJAX code a few times but can't seem to find anything wrong, though. I'm sorry to be a bother but do you have any ideas for what to look? I don't see any typos or anything strange. – Petr Palíšek Apr 13 '18 at 18:55
  • @PetrPalíšek The content type of the ajax request is preventing the data from populating the super global array. https://stackoverflow.com/questions/49822905/php-fails-to-open-stream-even-with-permissions-restrictions-and-filesize-checke/49823545#answer-49823545 – War10ck Apr 13 '18 at 18:58
0

The problem seems to be based around your content type. In PHP, only a Content-Type of application/x-www-form-urlencodedor multipart/form-data populates the $_POST super global array. Since you are telling the server that you are sending the data via application/json, you need to fetch the data from the request body via:

php://input

Try this:

$params = json_decode("php://input", TRUE);
$filename = 'data/'.$params['filename'];
$data = $params['filedata'];
file_put_contents($filename, $data);
War10ck
  • 12,387
  • 7
  • 41
  • 54
  • Thank you very much! I tried the code but it didn't change anything (same error and the array is still empty) – Petr Palíšek Apr 13 '18 at 19:01
  • As seen on https://stackoverflow.com/questions/19004783/reading-json-post-using-php if you need more info OP – Nerdi.org Apr 13 '18 at 19:01
  • @PetrPalíšek Interesting. I haven't encountered that before. Are you able to verify that the data is posting correctly? Try reviewing the request payload in your browsers dev tools, typically under the _Network_ tab. You should see a request labeled: `xhr` with the content type that you set and the data being passed to this server. – War10ck Apr 13 '18 at 19:04
  • Yep, that's what is puzzling me. The request payload shows exactly what it should. – Petr Palíšek Apr 13 '18 at 19:07
  • Your code has helped me too after all :) I just didn't realize how to mirror it in the Js. Thanks! – Petr Palíšek Apr 14 '18 at 23:03