My website is dependent on unique content provided by the user's input.
So they type in, "sports," they will receive content based on sports. That is simple enough. However, once I start adding more keywords to it, it gets a bit more complicated, at least in the way I'm doing it.
I need to start constantly checking whether the user inputted data is an array or not, and manipulate the data different.
I am currently storing the user's selection using Codeigniter's session class, then retrieving and manipulating the data based on its value.
So they submit the form and my JS runs:
$('#topics_form').submit(function() {
var topic = document.getElementById('topics_filter').value
$.ajax({
type: "POST",
url: 'ajax/update_session_topic',
dataType: 'json',
data: { topic: topic },
success: function(){
load_custom_topics()
}
});
return false;
});
Then update_session_topic runs in my AJAX model
public function update_session_topic()
{
if ($this->session->userdata('active_topic') == FALSE)
{
$array['active_topic'] = $this->input->post('topic');
$this->session->set_userdata($array);
return true;
} else {
$this->page_model->add_session_topic($this->input->post('topic'));
return true;
}
}
When theres only 1 value, its no big deal.
However, when trying to add a second value...I am forced to check whether its an array or not, or make it one.
public function add_session_topic($current_filter)
{
$session = $this->session->userdata('active_topic');
if (is_array($session) == false)
{
$session = array($this->session->userdata('active_topic'));
}
foreach ($session as $keyword)
{
if ($keyword == $current_filter)
{
return false;
}
}
$session[] = $current_filter;
$active['active_topic'] = $session;
$this->session->set_userdata($active);
return true;
}
This occurs in my views as well.
Its kind of annoying, and I was hoping there was a better way to do this. Im still new to PHP/codeigniter, so I am open to anything.
Thanks!
Related
I am submitting data to a controller function via AJAX, doing what I need to do with the data, and trying to echo it back out to the ajax function.
The issue I am having, is the controller is dumping out the error message and trying to redirect me to the actual function. Obviously the function doesn't have a view, which results in a blank white screen with the response echoed out in the top left corner.
Here is the ajax:
$('#submit_new_split_promo').on('click',function(e){
e.preventDefault();
var id = $(this).data('id');
$('#d_overlay').show();
form = {};
$.each($('#promo-mail-split-add-'+id).serializeArray(),function(k,v){
form[this.name] = this.value;
});
$.ajax({
url:$('#promo-mail-split-add-'+id).attr('action'),
type:"POST",
dataType: "json",
data: form
}).done(function(result){
var res = JSON.parse(result);
if (res == 'Duplicate') {
$('#ms-promo').css('border','3px solid red');
$('#ms-promo').effect('shake');
$('#dynamodal-unique-title').text('That code has been used. Please enter a new Promo Code.');
$('#dynamodal-unique-title').text('That code has been used. Please enter a new Promo Code.').css('color','red').delay(2000).queue(function(next){
$('#dynamodal-unique-title').text('Create Mail Split Promo');
next();
});
return false;
}
$('#mail_split_promo_'+id).modal('toggle');
if (res == false) {
alert('Mail Split Promo did not save. Please try again.');
} else {
$('#add-promo-to-split-'+id).prop('disabled',true);
$('#promo-view-abled-'+id).hide();
$('#promo-view-disabled-'+id).show();
$('#promo-view-disabled-'+id).prop('disabled',false);
}
}).fail(function(){
}).always(function(){
$('#d_overlay').hide();
});
});
Here is the Controllers code
public function addpromo() {
$this->Authorization->skipAuthorization();
$this->request->allowMethod(['get','post']);
$this->autoRender = false;
$data = $this->request->getData();
$mail_split_id = $data['mail_split_id'];
$code = $data['code'];
$result = false;
$doesExist = $this->Promos->findByCode($code)->toArray();
if ($doesExist) {
$result = 'Duplicate';
}
if ($result !== 'Duplicate') {
$MailSplits = $this->getTableLocator()->get('MailSplits');
$mailSplit = $MailSplits->get($mail_split_id);
$entity = $this->Promos->newEmptyEntity();
foreach ($data as $key => $val) {
$entity->$key = $val;
}
$entity->record_count = $mailSplit->record_count;
$result = $this->Promos->save($entity);
if ($this->get_property($result,'id')) {
$promo_id = $result->id;
$MailSplits = $this->loadModel('MailSplits');
$mentity = $MailSplits->get($mail_split_id);
$mentity->promo_id = $promo_id;
$updated = $MailSplits->save($mentity);
if ($this->get_property($updated,'id')) {
$result = true;
} else {
$result = false;
}
$output = [];
exec(EXEC_PATH.'AddPromoToRecordSplits '.$promo_id,$output);
} else {
$result = false;
}
}
ob_flush();
echo json_encode($result);
exit(0);
}
The URL it is trying to redirect me to is: /promos/addpromo when I really just need to stay on the same page, which would be /mail-jobs/view
Response dumped to browser
A couple of things to note:
I have tried adding the function to the controllers policy, and actually authorizing an initialized entity. This has no effect and does not change the issue I am facing.
Something that is more frustrating, I have essentially the same code (ajax structure and controller structure) for other forms on the page, and they work just fine. The only difference seems to be any form that utilizes ajax that is on the page on render, works just fine. The ajax functions I am having an issue with, all seem to be from the forms rendered in Modals, which are different elements. Every form in a modal / element, gives me this issue and that's really the only pattern I have noticed.
Any help is greatly appreciated, I know it's an odd and vague issue.
Thank you!
I'd like to create a group chat, and would like all the messages and there matching usernames to be stored in a JSON file.
However, this looks quite hard to do without using node.js or MySQLi.
As you can see below, i can already read the JSON and display it in "chat-wrap". The problem is to add messages to the json file with PHP and/or AJAX, and update the HTML automatically.
The input is where the user types the message, and I assume i'll have to use JS to notice when ENTER is pressed, because i do not want to use a form (unless you can convince me otherwise).
My HTML:
<div class="col chat">
<div class="messages" id="chat-wrap">
<?php include "chat/chat_process.php"; ?>
</div>
<input maxlength='100' type="search" name="type_message" id="type_message" placeholder="Type a message...">
</div>
JSON example:
{
"message_list": [{
"uname": "User 1",
"text": "Hello everyone!"
},
{
"uname": "User 2",
"text": "Hey!"
},
{
"uname": "User 1",
"text": "Hello!"
}
]
}
I've already tried messing with the following code, but i'm new to JS and AJAX so ofcourse the code below didn't really work out...
$("#type_message").keypress(function (event) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == '13') {
var msg = $("#type_message").val();
if (msg.length == 0) {
alert("Enter a message first!");
return;
}
var name = 'Username';
var data = {
uname: name,
text: msg
};
$.ajax({
type: "POST",
url: "chat.php",
data: {
data: JSON.stringify(data)
},
dataType: "json",
success: function (response) {
// display chat data stored in text file
}
});
}
});
When a message is typed and entered, it should add to the JSON file and display it live on every users screen.
Please excuse me if i forgot to clarify anything, i'm kinda new to stackoverflow and i'm not sure what y'all pros expect to know...
Thanks!
I added a bit of code to your success function as a result you should be able to add the new text dynamically to your html and also saves the changes to your file messages.json.
$("#type_message").keypress(function(event) {
let keycode = event.keyCode ? event.keyCode : event.which;
if (keycode == "13") {
let msg = $("#type_message").val();
if (msg.length == 0) {
alert("Enter a message first!");
return;
}
let name = "Username";
let data = {
uname: name,
text: msg
};
currentjson.push(data); // Also added one global variable which allows you to push the new data into the old json array.
$.ajax({
type: "POST",
url: "chat/chat.php", // I changed the url slightly since i put the php files in another directory
data: {
data: JSON.stringify(currentjson)
},
dataType: "json",
success: function(response) {
$(".chat").html(""); // Reset the html of the chat
addNodes(response); // Add the new Data to the chat by calling addNodesfunction
},
error: function(err) {
console.log(err);
}
});
}
Here is the php file that saves the json :
<?php
$file = fopen('messages.json','w');
$data = $_POST['data'];
fwrite($file,$data);
fclose($file);
echo $data; // return the new data set
addNodes function :
function addNodes(messages) {
for (let message of messages) {
const chatDiv = $(".chat");
const user = document.createElement("h3");
const content = document.createElement("p");
user.textContent = message.uname;
content.textContent = message.text;
chatDiv.append(user);
chatDiv.append(content);
}
}
I also changed your json to make it a little easier to loop through : (json example)
[
{ "uname": "User 1", "text": "Hello everyone!" },
{ "uname": "User 2", "text": "Hey!" },
{ "uname": "User 1", "text": "Hello!" }
]
Finally the whole client.js code looks like this :
$(document).ready(() => {
let currentjson = undefined;
$.ajax("chat/chat_process.php", { // This gets the file the first time the user opens the page
success: function(data) {
const messages = JSON.parse(data);
currentjson = messages;
addNodes(currentjson);
},
error: function() {
alert("There was some error performing the AJAX call!");
}
});
$("#type_message").keypress(function(event) {
let keycode = event.keyCode ? event.keyCode : event.which;
if (keycode == "13") {
let msg = $("#type_message").val();
if (msg.length == 0) {
alert("Enter a message first!");
return;
}
let name = "Username";
let data = {
uname: name,
text: msg
};
currentjson.push(data); // Also added one global variable which allows you to push the new data into the old json array.
$.ajax({
type: "POST",
url: "chat/chat.php",
data: {
data: JSON.stringify(currentjson)
},
dataType: "json",
success: function(response) {
$(".chat").html(""); // Reset the html of the chat
addNodes(response); // Add the new Data to the chat by calling addNodesfunction
},
error: function(err) {
console.log(err);
}
});
}
});
});
function addNodes(values) {
for (let message of values) {
const chatDiv = $(".chat");
const user = document.createElement("h3");
const content = document.createElement("p");
user.textContent = message.uname;
content.textContent = message.text;
chatDiv.append(user);
chatDiv.append(content);
}
}
But the final tasks that remains is that to display the new data to all the users currently using the website. To be able to do that i think you can use setInterval for like every 5 seconds and call a function which will detect if messages.json was changed by any user and then updates accordingly.
I hope my answers was useful :)
I believe you can, if you register the data into a variable or a text file in the server side.
You can trigger actions using server-sent events
https://www.w3schools.com/html/html5_serversentevents.asp
PS: someone has done it here:
https://www.developphp.com/video/JavaScript/Server-Sent-Events-Simple-Chat-Application-Example
Update sessions for chat directly
Advantages: It's much faster than passing files, storing information in DB. It's far less resource intensive. It avoids a lot of middle-man systems for handling the chat. It doesn't leave you holding onto increasing amounts of data. It avoids a LOT of legal issues with holding onto user data (because you aren't).
Disadvantages: You -have- to make sure it's secure in some way that best fits your use case. Also, troubleshooting session switching if something goes wrong can sometimes be a pain in the arse. Not useful if you're wanting to sell user data.
In php, store the information in session data. Then, fire off a child process (unconnected with the current session) that loads the session of the other user, and updates the other user's session data, having each session holding a variable in their session that stores the session IDs of the other users in the chat.
Mychat.php
$message = "" // Whatever's said
$groupids = implode(",", $other_users_ids); //Whatever your group's ids are.
$_SESSION["group_chat_users"]["my_id"] = session_id();
$_SESSION["my_chat_log"][]= $message;
exec("php my_group_update.php $groupids $_SESSION["group_chat_users"]["my_id"] $message");
my_group_update.php
$groupids = explode(",", $argv[1]);
$calling_user = $argv[2];
$message = $argv[3];
foreach ($groupids as $userid){
session_start($userid);
$_SESSION["my_chat_log"][]= $message");
}
As for outputing the JSON, it's as simple as:
fetch_log.php
header('Content-Type: application/json');
echo json_encode($_SESSION["my_chat_log"]);
Letting the user have their JSON log without it ever having to touch your Harddrive (or, alternatively, you can write it to your harddrive if you prefer.)
Notice: As should go without saying (but apparently needs to be said) As always, validate your inputs. Not doing so will leave you vulnerable to injection.
Ways suggestions on ways to prevent injection:
Have $message be a temporary file name written in Mychat.php and pulled in my_group_update.php
Convert $message to a hex string in Mychat.php and converted back in my_group_update.php
Alter my_group_update to pull the message from the first user's Session before switching to other users where it gets pasted.
Alert mychat to not include any variables other than the group_id in the exec call. Then have my_group_update just take the group ID, and cycle through all the shared chat session arrays, and find all new values, and update all the chats with it <---(probably the best).
Spin up a temporary very tiny VM that only handles the 1 chat, (maybe running with alpine linux or similar for a very small size that then self-destructs when the chat finishes.) This would be much higher overhead, but way more secure than anything else you'll even consider doing.
The list goes on.
I have a registration form for my website that requires a user to fill in ~6 fields, with their email as their username on the system. When a user registers, I want to first check if they are not already a registered user in our system, and if they are, redirect them to the login page. If they are not registered, registration should proceed to the registration page.
I've been trying to do this with the following ajax code, but it doesn't work - if the user is already registered, it still proceeds to the registration page:
function Chkreg()
{
var uemail = document.registration.email;
var not_reg;
$.ajax({
async: false,
type: "POST",
url: "chkreg.php",
data : "email="+uemail.value,
dataType: "json",
success: function (data) {
var success = data['success'];
if(success == false){
var error = data['message'];
alert(error);
window.location.href="login.php";
not_reg = false;
return false;
}
if(success == true) {
not_reg = true;
return true;
}
}
});//end ajax
return not_reg:;
}//end function
The form itself is defined as follows:
`<form name='registration' method="POST" action="registration/register.php" onsubmit="return Chkreg();">`
so, a false return from the Chkreg function should not post to register.php, but Chkreg() seems to always return true.
Any ideas how to fix it, or an alternate way to do this?
Because you're doing the ajax call with async:false, you don't need the return true or return false inside of it. That could be where things are going wrong, since you are returning from the anonymous function in the ajax call, not Chkreg(). Just returning not_reg outside of the ajax call will work.
That said, I would declare not_reg = false when you initialize the var. That way it's false until proven true. Or vice-y-versa -- I can't tell because of the negation in the variable name.
Also, inside of your (success == false) if-block, you are executing
window.location.href = "login.php";
which immediately redirects the user to login.php. You may want to alter the flow entirely and change the inline js for the form's onsubmit event
onsubmit="Chkreg(); return false;"
Then, inside Chkreg(), you could submit the form with javascript if they are not a registered user already.
Also, === and !== are preferred over == and != (especially when establishing if a variable is true or false, in case your values can be interpreted as truthy).
Lastly, Developer Tools are your friend (or Firebug). What response is the server giving when chkreg.php is being requested?
Check what the actual response is with firebug (or whatever your browsers dev kit)....I would be what you want is
if (success == "false") {
I’m adding private messaging to my site. In the Recipient text field in my form, I want to suggest valid usernames when someone starts typing. After reading tutorials and studying some scripts I made the following code for suggesting usernames from my database table named users. It works but I’m not certain how correct and secure it is.
Jquery (using the Jquery UI autocomplete plugin):
$(function() {
$( "#username" ).autocomplete({ //the recipient text field with id #username
source: function( request, response ) {
$.ajax({
url: "http://localhost/mysite/index.php/my_controller/search_username",
dataType: "json",
data: request,
success: function(data){
if(data.response == 'true') {
response(data.message);
}
}
});
},
minLength: 1,
select: function( event, ui ) {
//Do something extra on select... Perhaps add user id to hidden input
},
});
});
Controller (for simplicity I did not use a model although I plan to)
function search_username()
{
$username = trim($this->input->get('term')); //get term parameter sent via text field. Not sure how secure get() is
$this->db->select('id, username');
$this->db->from('users');
$this->db->like('username', $username);
$this->db->limit('5');
$query = $this->db->get();
if ($query->num_rows() > 0)
{
$data['response'] = 'true'; //If username exists set true
$data['message'] = array();
foreach ($query->result() as $row)
{
$data['message'][] = array(
'label' => $row->username,
'value' => $row->username,
'user_id' => $row->id
);
}
}
else
{
$data['response'] = 'false'; //Set false if user not valid
}
echo json_encode($data);
}
There is one edit that I would recommend making...
I would enable XSS protection by passing a second argument TRUE to get()
$username = trim($this->input->get('term', TRUE));
You can also add more exception, if you wish that function will works only for ajax calls :
if($this->input->is_ajax_request())
{
//... process the input
}
else
{
show_404();
}
Codeigniter active record database should make your code clean of any SQL injections. And if you're not posting anything you don't need to worry about XSS.
Using this someone could get a list of all possible usernames.. but other than that I would say it's "secure" (it looks very similar to what i'm using for my site =p)
EDIT:
And if you're not posting anything you don't need to worry about XSS.
I should clarify, IF you are posting anything (displaying anything that the user enters) then you should XSS filter (which johndavidjohn's answer below me explains [just pass TRUE as 2nd param]).. I didn't quite understand what u meant in your explanation of what "term" is... If all you are doing is searching, then you do not need to XSS filter, but if a user can send/write a message (generate content that your site stores [to be displayed]) then you should XSS filter on iput.
On my website I am using ajax post request to show content around my site, this is done using this code,
$("a.contentlink").click(function(ev) {
ev.preventDefault();
$('#main_menu').hide();
var url = $(this).attr("href");
var data = "calltype=full&url="+url;
$.ajax({
url:url,
type: "POST",
data: data,
success : function (html) {
$('#left-content-holder').html(html);
}
})
});
as you can see I am passing the url into the `$_POST' and I can access this in the method the javascript calls, this method is called get_content_abstract and looks like this,
public function get_content_abstract() {
$this->load->model('content_model');
if($this->input->post('calltype') == "abstract"){
if($query = $this->content_model->get_content_by_id($this->uri->segment(3))) {
$data['abstract'] = $query;
}
$this->load->view('template/abstract', $data);
}
elseif($this->input->post('calltype') == "full") {
if($query = $this->content_model->get_content_by_id($this->uri->segment(3))) {
$data['full'] = $query;
}
$this->load->view('template/full-content', $data);
}
}
How ever I have no added a new function that will allow the user to save the content to 'bookmarking system', however in my method I cannot access the post using codeigniters $this->input-post('url') (where URL is the one of peices of data passed in the javascript), it says that the post is empty when I var dump it, this is done using this method,
public function love_this() {
die(var_dump($this->post->input('url')));
}
can anyone help as to why the post is empty in this love_this method?
Shouldn't:
public function love_this() {
die(var_dump($this->post->input('url')));
}
Actually be
public function love_this() {
die(var_dump($this->input->post('url')));
}
See:
http://codeigniter.com/user_guide/libraries/input.html