1

I'm working on a website that let's users simply save a note, to be accessed later. I'm however having quite some trouble with actually saving the note. I first had it set to automatically save on each keypress, but it's better if I have the user press on a button to save the file. What you'll also see in the code is that the note gets saved as the users IP address, when the user then visits the site again he'll see the same note (if he has the same IP again).

The error I get now when clicking the save button is:

PHP Warning:  file_put_contents() [<a href='function.file-put-contents'>function.file-put-contents</a>]: Filename cannot be empty in /home/martmart/public_html/index.php on line 41

My index.php:

<?php

$note_name = 'note.txt';
$uniqueNotePerIP = true;

if($uniqueNotePerIP){

// Use the user's IP as the name of the note.
// This is useful when you have many people
// using the app simultaneously.

if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$note_name = 'notes/'.$_SERVER['HTTP_X_FORWARDED_FOR'].'.txt';
}
else{
$note_name = 'notes/'.$_SERVER['REMOTE_ADDR'].'.txt';
}
}


if(isset($_SERVER['HTTP_X_REQUESTED_WITH'])){
// This is an AJAX request

if(isset($_POST['note'])){
// Write the file to disk
file_put_contents($note_name, $_POST['note']);
echo '{"saved":1}';
}

exit;
}

$note_content = 'Write something here :D';

if(file_exists($note_name) ){
$note_content = htmlspecialchars( file_get_contents($note_name) );
}

function saveNow() {
// Write the file to disk
file_put_contents($note_name, $_GET['note']);
echo '{"saved":1}';
}

?>

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Marty Testweb</title>
<!-- Our stylesheet -->
<link rel="stylesheet" href="assets/css/styles.css" />
<!-- A custom google handwriting font -->
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Courgette" />
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script src="assets/audiojs/audio.min.js"></script>
<script>
audiojs.events.ready(function() {
var as = audiojs.createAll();
});
</script>
</head>

<body>

<div id="pad">
<h2>Note</h2>
<textarea id="note"><?php echo $note_content ?></textarea>
</div>

<!-- Initialise scripts. -->

<script>
function saveNow()
{
alert("<?php saveNow(); ?>");
}
</script>


<button id="save" onclick="saveNow()">Save Note</button>

<!-- JavaScript includes. -->

<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="assets/js/script.js"></script>
</body>

<div id="footer">
<footer>
<a href="">
<div id="footer_right">
Version 0.1.2
</div id="footer_right">
</a>
<audio src="assets/audiojs/music.mp3" preload="auto"></audio>
<div id="footer_left">
Save function not working yet
</div id="footer_left">
</footer>
</div id="footer">
</html>

The script.js:

$(function(){

var note = $('#note');

var saveTimer,
lineHeight = parseInt(note.css('line-height')),
minHeight = parseInt(note.css('min-height')),
lastHeight = minHeight,
newHeight = 0,
newLines = 0;

var countLinesRegex = new RegExp('\n','g');

// The input event is triggered on key press-es,
// cut/paste and even on undo/redo.

note.on('input',function(e){

// Count the number of new lines
newLines = note.val().match(countLinesRegex);

if(!newLines){
newLines = [];
}

// Increase the height of the note (if needed)
newHeight = Math.max((newLines.length + 1)*lineHeight, minHeight);

// This will increase/decrease the height only once per change
if(newHeight != lastHeight){
note.height(newHeight);
lastHeight = newHeight;
}
}).trigger('input');    // This line will resize the note on page load

function ajaxSaveNote(){

// Trigger an AJAX POST request to save the note
$.post('index.php', { 'note' : note.val() });
}
});

I don't really know how to solve this, so any help is greatly appreciated. I just want to have the file save with the same name as the user's IP address, when he click on the button. Please keep in mind I'm still a big newbie with these more advanced features so please point out anything I did wrong (but also please explain it easy :) ).

Thanks for reading,

Mart.

Martyn
  • 49
  • 1
  • 7

1 Answers1

1

First of all I would suggest considering whether having the filename be the IP address is a good idea...many workplaces and other group settings share the same IP address, so any user at a workplace like that would see the note left by any other user at the same workplace.

As to your error, I think the problem may be that you didn't declare $note_name as a global variable within your function. Try changing it to this:

function saveNow() {
    global $note_name;
    // Write the file to disk
    file_put_contents($note_name, $_GET['note']);
    echo '{"saved":1}';
}

In PHP if you want to use a global variable (one that wasn't declared inside a function or class) within a function, you always have to use the global keyword as shown above. Using global variables can be avoided entirely if you structure your code a bit differently, but that's another topic.

I wonder why you didn't get a notice about it not being defined though...while you're still developing you might want to put this at the top of your code:

error_reporting(E_ALL);

P.S. Although your code will work without doing this, for security reasons it would be good to specify the JSON MIME type before outputting JSON from PHP, e.g.:

function saveNow() {
    global $note_name;
    // Write the file to disk
    file_put_contents($note_name, $_GET['note']);
    header('Content-type: application/json');
    echo '{"saved":1}';
    exit;
}
Matt Browne
  • 12,169
  • 4
  • 59
  • 75
  • Thanks that fixed the name part. Now when I run it however I get the error that: Undefined index: note in index.php I guess I have to place global for 'note' somewhere too, but where? – Martyn May 11 '13 at 03:03
  • The "undefined index" error refers to undefined array elements/keys, so actually an "undefined index" error would never be solved by adding a `global` declaration. It was probably caused by the line `$_GET['note']`; it looks like your Javascript only ever sends data via POST so you should be using `$_POST['note']` instead. – Matt Browne May 11 '13 at 03:13
  • Thanks but, used POST now, still "undefined index" error. Any solutions for that? – Martyn May 11 '13 at 03:21
  • This line in your Javascript `saveNow` function is problematic: `alert("");` I suggest reading up on how AJAX works; Javascript knows nothing about PHP. When you include the result of the PHP function from Javascript, it executes the PHP function right away, not when the Javascript function is called (and outputs it as text within the Javascript *source code*). You need to use the `success` callback option for jQuery's `$.post` method instead, to run a function that will handle the response from PHP. – Matt Browne May 11 '13 at 03:27
  • Here's the general idea, except you'd be using `$.post` instead of `$.get`: http://stackoverflow.com/a/5298493/560114 – Matt Browne May 11 '13 at 03:29
  • Aha that's really useful! Thanks for the help, I'll be probably rewriting this anyway because the IP saving structure isn't that handy. Thanks! – Martyn May 11 '13 at 03:38