$_SESSION is conflicting with $_FILES - php

I have a form that had a file type input to upload images, but it would always show up the "notice: undefined index" and I saw that the $_FILE was coming empty, but none of the answers that I found online have helped me.
I have a project where after the user registers he has to login and his first page he confirms his data and insert some new ones, one of this new ones is a picture that he can upload, as I said, my initial problem was that the $_FILES was always coming up empty, I searched online and this is a fairly common error but none of the answers have helped me, after a lot of trying I found out what the problem is, but I still have no Idea why, or how to fix it.
At the start of the page that I talked about there's this bit off code here:
if(isset($_SESSION['logado'])){
$dados = $_SESSION['dadosUsu'];
}else{
unset($_SESSION['dadosUsu']);
session_destroy();
header("Location: homeLandingPage.php");
}
to stop unnauthorized people into the page or create a variable with the user data so that it can be used to fill out some of the inputs with the info that the user had already registered.
I found that if I removed this bit off code, the $_FILES global started working and the code runned fine, but if the code was there the problems continued, I have no ideia why this is happening and I couldn't find anything online that talk about a session conflicting with the $_FILES global.
after that there's this bit of ajax:
$(function(){
$('.form').submit(function(){
$.ajax({
url: 'cod_alterarAcc.php',
type: 'POST',
data: $('.form').serialize(),
success: function(data){
if(data != ''){
$('.recebeDados').html(data);
document.getElementById('visor1').value = '<?= $dados['nomeUsu']; ?>';
document.getElementById('visor2').value = '<?= $dados['emailUsu']; ?>';
document.getElementById('visor3').value = '<?= $dados['emailUsu']; ?>';
document.getElementById('visor4').value = '';
document.getElementById('visor5').value = '';
document.getElementById('visor6').value = '';
}
}
});
return false;
});
});
I don't know if it's this but here it's the preview function that is called onChange on the input type file:
function previewImagem() {
var imagem = document.querySelector('input[name=img]').files[0];
var preview = document.querySelector('img[id=dup]');
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (imagem) {
reader.readAsDataURL(imagem);
} else {
preview.src = "";
}
}
here is the form that Im using:
<form enctype="multipart/form-data" class='form' method='post' action='cod_alterarAcc.php'>
<div id="img-perfil">
<img src="imagens/perfil.png" id="dup"/>
<label for="selecao-arquivo" class="selecionar-img">+</label>
<input id="selecao-arquivo" type="file" name="img" class="botao-img" onchange="previewImagem()" />
</div>
<label>Confirme seu nome:</label>
<input type="text" id="visor1" name="nome_usu" value="<?= $dados['nomeUsu']; ?>" />
<label>Altere seu email:</label>
<input type="email" id="visor2" name="email" value="<?= $dados['emailUsu']; ?>" />
<label>Confirme seu email:</label>
<input type="email" id="visor3" name="confirmaEmail" value="<?= $dados['emailUsu']; ?>" />
<label>Sua senha:</label>
<input type="password" id="visor4" name="senha" />
<label>Confirme sua senha:</label>
<input type="password" id="visor5" name="confirmaSenha" />
<label>Insira seu cpf:</label>
<input type="text" id="visor6" name="cpf_usu" />
<div class='recebeDados'></div>
<input type="submit" value="confirmar" />
</form>
on the cod_alterarAcc.php page has some validations using filter_input_array() and then I have this:
$extensao = strtolower(substr($_FILES['img']['name'], -4));
$novo_nome = sha1(time()) . $extensao;
$diretorio = "imgsBanco/";
$ext = strtolower(substr($_FILES['img']['name'], -3));
$tipos = array("png","jpg","gif");
$imagem = $diretorio.$novo_nome;
I have some more validation regarding the other inputs and then this, it's the first time that I use the session in this page:
if (in_array($ext, $tipos)) {
if (move_uploaded_file($_FILES['img']['tmp_name'], $imagem)) {
$codAcesso = $_SESSION['dadosUsu']['codAcesso'];
$codUsu = $_SESSION['dadosUsu']['codUsu'];
$senhaEncript = Bcrypt::hash($infoPost['senha']);
after that I do an update on everything in the database, including the image url which is the $imagem variable, after that I only look at the session one more time to send the user to another page depending on it's user type.
I've also tested for most of the possibilities in here Why would $_FILES be empty when uploading files to PHP? and it didn't worked
Like I said, apparently the only thing that it's messing with the $_FILES it's that part where I use the session on the first page, if someone could help me fix this problem and explain why it's happening in the first place I would appreciate it a lot.

It seems that the default action of the form is conflicting with your AJAX, but if you want to use only AJAX in uploading your file then you want to prevent the default action of the form. Your AJAX request should be look like this.
$('.form').submit(function(e){
e.preventDefault(); // Preventing the default action of the form
var formData = new FormData(this); // So you don't need call serialize()
$.ajax({
url: 'cod_alterarAcc.php',
type: 'POST',
data: formData,
success: function (data) {
if(data != ''){
$('.recebeDados').html(data);
document.getElementById('visor1').value = '<?= $dados['nomeUsu']; ?>';
document.getElementById('visor2').value = '<?= $dados['emailUsu']; ?>';
document.getElementById('visor3').value = '<?= $dados['emailUsu']; ?>';
document.getElementById('visor4').value = '';
document.getElementById('visor5').value = '';
document.getElementById('visor6').value = '';
}
},
cache: false,
contentType: false,
processData: false
});
});
also put your form into FormData and specify your ajax request type.
EDIT
Try to confirm if PHP able to get the data with
print_r($_POST);
print_r($_FILES);
And in your AJAX success function
console.log(data);
EDIT
Forgot to put the parameter e on form.submit

Related

Unable to validate CSRF at controller in codeIgniter with ajax

I am new to CSRF and codeigniter. However, I have referred so many solution here and after applying I am able to go some extent but unable to validate the CSRF at controller end. I am getting the error
The action you have requested is not allowed.
I am posting my entire code here. Though I am using this for registration but I am not using Form to submit the request but with the help of ajax.
Config
$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrfName';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
View
I am not going to post All the fields but few. Firstname, lastname, email, password.. etc are there
<?php
$csrf = array(
'csrfName' => $this->security->get_csrf_token_name(),
'csrfHash' => $this->security->get_csrf_hash()
);
?>
<input type="hidden" class="csrfName" value="<?php echo $csrf['csrfName'];?>" />
<input type="hidden" class="csrfHash" value="<?php echo $csrf['csrfHash'];?>" />
<div class="row">
<div id="join_btn" onclick="email_signup('joinBox')">SIGN UP</div>
</div>
JS
There are other fields as well but i am posting here important one
var csrfValue = $(".csrfHash").val();
var csrfName = $(".csrfName").val();
var callParameters = "call=email_signup&csrfHash="+csrfValue+"&csrfName="+csrfName;
$.ajax({
url:ajaxcalls.php,
data:callParameters,
type:"POST",
cache:false,
dataType:"json",
success: function(resp){
}
});
Controller
function email_signup($params){
$csrfName = $this->security->get_csrf_token_name();
$csrfHash = $this->security->get_csrf_hash();
$result['flag'] = "success";
echo json_encode($result);
}
Well, it's because you're doing it all wrong.
Mistake 1:
Your type="hidden" input elements have no name=... attributes.
Mistake 2:
The input element that holds the csrfName i.e (name="<?php echo $csrf['csrfName'];?>") expects a csrfHash as it's value=....
In addition, both the csrfName and csrfHash need to be defined in one input HTML element. Not two.
Cross-site request forgery (CSRF)
So:
<!-- Instead of: -->
<input type="hidden" class="csrfName" value="<?php echo $csrf['csrfName'];?>" /> ❌
<input type="hidden" class="csrfHash" value="<?php echo $csrf['csrfHash'];?>" /> ❌
<!-- Use this: -->
<input type="hidden" name="<?php echo $csrf['csrfName'];?>" class="csrfName" value="<?php echo $csrf['csrfHash'];?>" /> ✅
Suggestions
Since you're using jQuery already, to prepare your POST data, the .serializeArray() method would sound sufficient instead of manually building 'query strings'. i.e:
// ...
let $formData = $("form").serializeArray()
// ...
You can then append any extra data you intend to pass along with the HTML form elements if you wish..i.e:
// ...
let $formData = $("form").serializeArray()
$formData.push({name: 'call', value: 'email_signup'})
$.ajax({
// ...
data: $formData,
// ...
});
Alternatively, you can build the POST data using FormData().
If you choose this option, don't forget to add processData: false and contentType: false to your $.ajax({...}) object argument. i.e:
let $formData = new FormData($("form").get(0))
$formData.append('call', 'email_signup')
$.ajax({
// ...
data: $formData,
processData: false,
contentType: false,
// ...
});
If you are using Codeigniter vertion 3.0, add this in config:
$config['csrf_regenerate'] = FALSE;

Code Igniter Bonfire ajax request 500 internal server error

So I am trying to submit just an email address using ajax to get people to register and I have no idea why I am getting a 500 internal server error. I am new to ajax calls.
I have tried to follow the following tutorial: http://www.youtube.com/watch?v=TZv5cgua5f0
However I have done as they have said and still if I do a post with values I do not get to the desired controller method. If I do add data to the post then I get an internal server error.
javascript:
$('#email_submit').click(function()
{
var form_data =
{
users_email: $('#users_email_address').val()
};
$.ajax
({
url: 'http://localhost/myZone/NewsLetter/submit',
type: 'POST',
data: form_data,
success: function(msg)
{
alert(msg);
}
});
return false;
});
HTML
<div id="email_newsletter_signup" class="ajax_email_block_signup" >
<h3>Sign up to the newsletter:</h3>
<?php echo form_error('signup_email','<div id="email_error" class="error">','</div>');?>
<h3>email: <input id="users_email_address" type="email" name="signup_email" value="<?php echo set_value('signup_email'); ?>" placeholder="Your email"/> </h3>
<input id="email_submit" type="submit" name="submit"/>
</div>
contoller
public function index()
{
Assets::add_module_js('newsletter','email.js');
//If included will be added
Template::set_block('email_block','email_block');
Template::render();
}
public function submit($email)
{
$success = $this->newsletter_model->set_unverified_email($email);
// if($success === FALSE)
// {
// Template::set_block('newsletter_error','newsletter_error');
// }
// else
// {
// Template::set_block('newsletter_success','newsletter_success');
// }
// Template::render();
return;
}
I have a breakpoint inside the submit and it just wont be hit when I do a post
Thanks
Found my solution. Nothing to do with bonfire but with the codeigniter. It was the CSRF token.
Here is an excellent post about sorting the issue:
http://aymsystems.com/ajax-csrf-protection-codeigniter-20
add csrf token to data before posting
$.ajax({
type: "POST",
url: url,
data: {'<?php echo $this->security->get_csrf_token_name(); ?>':'<?php echo $this->security->get_csrf_hash(); ?>'}
})
csrf token needs to be send along every request so it needs to be specified by the above echo statements

Uploading a file with jQuery [duplicate]

This question already has answers here:
jQuery Ajax File Upload
(27 answers)
Closed 9 years ago.
I've a question about file uploading with Ajax. How to submit file with $.ajax()
without a special js-plugin?:
<form action="javascript:return false;">
<input type="text" id="name" />
<input type="file" id="myfile" />
<input type="button" id="submitbutton" value="submit" />
</form>
This is a jQuery small code:
<script type="text/javascript">
$(document).ready(function() {
$('#submitbutton').click(function() {
$.ajax({
type: 'POST',
dataType: 'json',
enctype: 'multipart/form-data',
url: 'upload.php',
async: false,
data: {
'name': $('#name').val(),
'myfile': $('#myfile').val()
},
success: function(data) {
alert(data.msg);
}
});
});
});
</script>
And upload.php file:
<?php
$name = isset($_POST['name']) ? $_POST['name'] : '';
if (isset($_FILES) && isset($_FILES["file"])) {
$files = $_FILES['file'];
$error = isset($files["error"]) ? $files["error"] : '';
$fname = isset($files["name"]) ? $files["name"] : '';
$type = isset($files["type"]) ? $files["type"] : '';
$size = isset($files["size"]) ? $files["size"] : '';
$tmp_name = isset($files["tmp_name"]) ? $files["tmp_name"] : '';
return array('msg' => "Hello, $name! \nYour file data:\nErr: $error, Name: $fname, Type: $type, Size: $size, Tmp: $tmp_name");
}
echo json_encode(array('msg' => 'create image'));
?>
Other option is using iframe, this is a tutorial for doing this;
Files cannot be uploaded via ajax. You may want to checkout the Form Plugin which does support file uploads: http://jquery.malsup.com/form/
If you expect to get this working cross browser, than you can't do that with AJAX only. (But it is ok for you that this will work not in all browsers, you may take a look how to upload files with XMLHttpRequest and jquery here)
As for me, the best would be to use jQuery Forms plugin.
Another option is to do the same thing that plugin does manually.
It will be something like below:
var ifrm = $("<iframe>", {id:"tmp_upload_frame"}).onload(function() {
// do something when response is returned
}).hide();
$("body").append(ifrm);
$("form").prop("target", "tmp_upload_frame")
.prop("enctype","multipart/form-data")
.submit();
But as for me, Forms plugin is much better as it has an interface very similar to ajax interface and does a lot of dirty work for you (like retrieving response from iframe) for you.

Ajax Post Type will not send data to php page

I have the following form for users to reset their password it is within the file forgotten.php in the root directory.
<form id="pass_form" action="" method="post" name="pass_form">
<label>Username:</label>
<input type="text" class="blank" name="name" id="name" value="Trader Username" data-default="Trader Username" data-message="Please enter your username..."> *<br>
<input class="sub-btn" type="submit" value="Submit">
</form>
I would like to post the username to inc/sendreset.php so I have the following Ajax in js/scripts.js
$("#pass_form").validator({
offset: [0, 354],
position: 'center left',
messageClass: 'conerror'
}).submit(function(e) {
if (!e.isDefaultPrevented()) {
var form = $(this);
var serdata = form.serialize();
$.ajax({
type: "POST",
url: "sendreset",
data: serdata,
cache: false,
success: function (html) {
log('inside ajax sendreset', this, arguments);
$('#pass_form').fadeOut(400,function(){
if (html=="0") {
} else {
$('#pass_form').html('<p>The password reset instructions have been sent. Please check your email.</p>');
}
$('#pass_form').fadeIn();
});
},
error: function (err) {
log('error inside ajax sendreset', this, arguments);
}
});
//$('#pass_form').fadeOut(400);
e.preventDefault();
}
});
However it does not seem to post the username into the file. The inc/sendreset.php is as follows
<?php
require_once('./library.php');
require_once('./PHPMailer/class.phpmailer.php');
$Trader = new CompanyTrader();
$resetdata = $Trader->resetTrader($_POST['name']);
print_arr($resetdata);
//more php which isn't relevant
?>
I know the file inc/sendreset.php works as when I the file to use $_GET['name'] and i use inc/sendreset.php?name=username the array is returned for the relevant user. It does not work from forgotten.php using Ajax though. Please help!
i really think this is wrong:
url: "sendreset",
try with an relative or absolute url like http://mysite.com

strange behavior while including a class in php

I'm experiencing a strange behavior with PHP. Basically I want to require a class within a PHP script. I know it is straight forward and I did it before but when I do so, it change the behavior of my jquery (1.8.3) ajax response. I'm running a wamp setup and my PHP version is 5.4.6.
Here is a sample as for my index.html
head (omitting the jquery js include)
<script>
$(document).ready(function(){
$('#submit').click(function(){
var action = $('#form').attr('action');
var form_data = {
fname: $('#fname').val(),
lname: $('#lname').val(),
phone: $('#phone').val(),
email: $('#email').val(),
is_ajax: 1
};
$.ajax({
type: $('#form').attr('method'),
url: action,
data: form_data,
success: function(response){
switch(response){
case 'ok':
var msg = 'data saved';
break;
case 'ko':
var msg = 'Oops something wrong happen';
break;
default:
var msg = 'misc:<br/>'+response;
break;
}
$('#message').html(msg);
}
});
return false;
});
});
</script>
body
<div id="message"></div>
<form id="form" action="handler.php" method="post">
<p>
<input type="text" name="fname" id="fname" placeholder="fname">
<input type="text" name="lname" id="lname" placeholder="lname">
</p>
<p>
<input type="text" name="phone" id="phone" placeholder="phone">
<input type="text" name="email" id="email" placeholder="email">
</p>
<input type="submit" name="submit" value="submit" id="submit">
</form>
And as for the handler.php file:
<?php
require('class/Container.php');
$filename = 'xml/memory.xml';
$is_ajax = $_REQUEST['is_ajax'];
if(isset($is_ajax) && $is_ajax){
$fname = $_REQUEST['fname'];
$lname = $_REQUEST['lname'];
$phone = $_REQUEST['phone'];
$email = $_REQUEST['email'];
$obj = new Container;
$obj->insertData('fname',$fname);
$obj->insertData('lname',$lname);
$obj->insertData('phone',$phone);
$obj->insertData('email',$email);
$tmp = $obj->give();
$result = $tmp['_obj'];
/*
Push data inside array
*/
$array = array();
foreach($result as $key => $value){
array_push($array,$key,$value);
}
$xml = simplexml_load_file($filename);
// check if there is any data in
if(count($xml->elements->data) == 0){
// if not, create the structure
$xml->elements->addChild('data','');
}
// proceed now that we do have the structure
if(count($xml->elements->data) == 1){
foreach($result as $key => $value){
$xml->elements->data->addChild($key,$value);
}
$xml->saveXML($filename);
echo 'ok';
}else{
echo 'ko';
}
}
?>
The Container class:
<?php
class Container{
private $_obj;
public function __construct(){
$this->_obj = array();
}
public function addData($data = array()){
if(!empty($data)){
$oldData = $this->_obj;
$data = array_merge($oldData,$data);
$this->_obj = $data;
}
}
public function removeData($key){
if(!empty($key)){
$oldData = $this->_obj;
unset($oldData[$key]);
$this->_obj = $oldData;
}
}
public function outputData(){
return $this->_obj;
}
public function give(){
return get_object_vars($this);
}
public function insertData($key,$value){
$this->_obj[$key] = $value;
}
}
?>
The strange thing is that my result always fall under the default switch statement and the ajax response fit both present statement. I noticed then if I just paste the Container class on the top of the handler.php file, everything works properly but it kind of defeat what I try to achieve.
I tried different way to include the Container class but it seem to be than the issue is specific to this current scenario.
I'm still learning PHP and my guess is that I'm missing something really basic. I also search on stackoverflow regarding the issue I'm experiencing as well as PHP.net, without success.
Regards,
My guess is that you have white space at the end of your class file, which is causing the output to be ' ok' instead of 'ok'. This can be the result of using certain applications to edit your files, or accidentally adding a space after the closing ?>. Try removing the closing ?> in your php class all together. This is not only allowed (php will automatically end processing at the end of the file anyways), but often encouraged in many style guides to prevent exactly the kind of thing that you are describing.
Another thing I usually do for this type of situation, is instead of returning a plain string, I return a json string, which jQuery will automatically turn into a javascript object for you. This would also prevent, or at least let you know right away that you are having the above type of problem.
so php would echo like this:
exit( json_encode( array( 'status' => 'ok' ) ) );
and jQuery would receive like this:
$.ajax({
type: $('#form').attr('method'),
url: action,
data: form_data,
dataType: 'json',
success: function(response){
switch(response.status){
case 'ok':
var msg = 'data saved';
break;
case 'ko':
var msg = 'Oops something wrong happen';
break;
default:
var msg = 'misc:<br/>'+response;
break;
}
$('#message').html(msg);
}
});
Note the added dataType parameter in the ajax call, as well as using response.status to check the status property that we created in PHP.
This also allows you to return more than one value in your response. You can build the object or array however you like on the PHP side, and you would basically receive the same as a javascript object on the javascript side.

Categories