In codeigniter or restful structure, the page can be route to through the URI
For example, if I would like to look at the item list of id: 1 , then I just need to create a path like that:
domain.com/item/view/1
And in controller
function view() {
$id = $this->uri->segment(3);
//database get data and return view...
}
This should be the standard way to implement restful structure. However, when in the member system, and the item id is dependent to the user, how can I protect the link?
So that other user can not brute force to try different ID and read the other member item.
One approach is just compare the user_id and item_id in each function. But if the system is large that means I need to compare in each function and that is a lot of coding and checking .
Are there any smarter way to reduce the overhead / coding ?
Thanks
There is no way to protect URL's. Someone could simply change the number in the URL and fetch different data. If the ID is sensitive, you would not want to pass the information through the URL.
One option is to encrypt the ID being passed in the URL (ex: 29 could be encrypted so it appears as 'S84jG483dJd').
The ID could also be passed through using the code-igniter session library or even with flash data (stored for one request). This way if the ID's are sensitive, the likelihood of anyone altering them would be slim (enable session cookie encryption in CI for more security).
However, if the information is that sensitive, I would always have checks in place before the database is fetched and shown to the user. It is always good practice to code with your users worst intentions in mind!
In domain.com/item/view/1, always stands for base_url/controller/Method
so if you create controller (item), then function (view).
class Item extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
public function view($id)
{
//so in $id it will assign the 3rd value to it.
$new_id = $id;
echo $new_id;
}
Related
I'm currently creating an app with Codeigniter and i came up with this issue (and it's not the first time to be honest).
What i want is to set a value in a global variable in function "foo()" and the access it through function "bar" (which is called through ajax call from client side).
In short, i want this variable to be full when the user has visited the page (sth like a session).
Here's an example code of my controller and what i'm trying to achieve:
class Groups extends CI_Controller{
private $page_id;
public function foo($slug = FALSE){
$this->load->model('some_model');
$info = $this->some_model->get_info($slug);
$this->page_id = $info['page_id'];
}
public function bar(){
$this->load->model('some_model');
$info = $this->some_model->get_some_other_info($this->page_id);
//Some code in here
}
}
Any suggestions or best practices on achieve that?
I've tried searching the internet on that but i couldn't find something to start with. So if you have any suggestions on where to look at, feel free to do it!
Thanks
If i understand it right you will have 2 calls. One will be at page load where you want to store something and after that there will be an ajax call that will retrieve what you have stored. Because the 2 script loads are different you can only do it by storing the data to one of them: database/session/cookie/html session or localstorage.
Can't say anything about best practice because i dont know what you want to store and for how long so need a bit more info about your code (im guessing you want to store the "page_id"?).
I'm working on an application written in PHP. I decided to follow the MVC architecture.
However, as the code gets bigger and bigger, I realized that some code gets duplicated in some cases. Also, I'm still confused whether I should use static functions when quering the database or not.
Let's take an example on how I do it :
class User {
private id;
private name;
private age;
}
Now, inside this class I will write methods that operate on a single user instance (CRUD operations). On the other hand, I added general static functions to deal with multiple users like :
public static function getUsers()
The main problem that I'm facing is that I have to access fields through the results when I need to loop through users in my views. for example :
$users = User::getUsers();
// View
foreach($users as $user) {
echo $user['firstname'];
echo $user['lastname'];
}
I decided to do this because I didn't feel it's necessary to create a single user instance for all the users just to do some simple data processing like displaying their informations. But, what if I change the table fields names ? I have to go through all the code and change those fields, and this is what bothers me.
So my question is, how do you deal with database queries like that, and is it fine to use static functions when querying the database. And finally, where is it logical to store those "displaying" functions like the one I talked about ?
Your approach seems fine, howerver I would still use caching like memcached to cache values and then you can remove static.
public function getUsers() {
$users = $cacheObj->get('all_users');
if ($users === false) {
//use your query to grab users and set it to cache
$users = "FROM QUERY";
$cacheObj->set('all_users', $users);
}
return $users;
}
(M)odel (V)iew (C)ontroller is a great choice choice, but my advice is look at using a framework. The con is they can have a step learning curve, pro is it does a lot of heavy lifting. But if you want to proceed on your own fair play, it can be tough to do it yourself.
Location wise you have a choice because the model is not clearly define:
You'll hear the term "business logic" used, basically Model has everything baring views and the controllers. The controllers should be lean only moving data then returning it to the view.
You model houses DB interaction, data conversions, timezone changes, general day to day functions.
Moudle
/User
/Model
/DB or (Entities and Mapper)
/Utils
I use Zend and it uses table gateways for standard CRUD to avoid repetition.
Where you have the getUsers() method you just pass a array to it, and it becomes really reusable and you'd just have different arrays in various controller actions and it builds the queries for you from the array info.
Example:
$data = array ('id' => 26)
$userMapper->getUsers($data);
to get user 26
enter code here
$data = array ('active' => 1, 'name' => 'Darren')
$userMapper->getUsers($data);`
to get active users named Darren
I hope this help.
I am currently building a web app which has two models, Donor and Donation Models respectively. It has multiple user roles. When the staff user first registers a donor, I want him to be redirected to another form which allows him to fill in the Donation details(the donor is registered once the first donation is successful).
Firs of all, should I create a donation controller, from which I would redirect the user using:
return $this->redirect(array('controller'=>'donations','action'=>'add'));
For the above to work, it requires me to save the newly registered donor's id in a session like so :
$this->Session->write('id', $this->Donor->id);
So the user is redirected to 'donations/add' in the url, and this works fine.. However I think this has some flaws. I was wandering whether I should create another action inside the Donor controller called 'add_donation', which will have its respective 'View'. The idea is to be able to form a url of the sort : 'donors/add_donation/4' (4 being the donor_id ! )
This URL follows this construct: 'controller/action/id'
If anyone could shed some light on best practices, or describe any caveats to my solution(the former, using session etc.) , please do help a brother out! Ill be deeply indebted to you! Thanks in advance!
After you saved the data you can do this in the DonorsController:
$this->redirect(array(
'controller' => 'donations',
'action' => 'add',
$this->Donor->getLastInsertId()
));
There is no need to return a redirect, it's useless because you get redirected. Notice that we pass the last inserted record id as get param in the redirect. The redirect method of the controller calls by default _stop() which calls exit().
CakePHP3: There is a discussion about changing that default behavior in 3.0. Looks like in CakePHP 3.0 the redirect() won't exit() by default any more.
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
I would not use the session here, specially not by saving it to a totally meaningless and generic value named "id". If at all I would use always meaningful names and namespaces, for example Donor.lastInsertId as session key.
It's not always clear where to put things if they're related but the rule of thumb goes that things should go into the domain they belong to, which is pretty clear in this case IMHO.
Edit:
Leaving this edit here just if someone else needs it - it does not comply with the usage scenario of the asker.
If you have the user logged in at this stage, modify the add function to check if the userId passed is the same as the one logged in:
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
if ($this->Auth->user('id') != $donorId) {
throw new InvalidArgumentException();
}
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
You can use also the same controller using more models with uses.
Or you can also to ask to another controller with Ajax and morover to get response with Json.
I am writing a small framework where my goal is to make it easy for my developers to set up a redirect to the details page of a resource after adding/inserting one.
Ordinarily this would be as easy as PDO::lastInsertID(), but I am using more than just the ID to identify the resource, I am also using a formatted version of the resource's name/title.
For example a new tournament might be called "Test Tournament" and therefore it's resource URI will be domain.com/tournament/328-test-tournament.
So when I redirect after inserting, I need to redirect to '328-test-tournament' and not just '328'. This is by design for URL integrity purposes. I don't want people accessing individual resources with mis-matched IDs and titles.
So that said, after I insert, I would like to be able to automatically return not just the ID, but the entire data set for what I entered, so that I can then format the title and redirect.
I could do this in the controller:
$this->TournamentModel->insert();
$id = PDO::lastInsertID();
$title = my_title_formatting_function($_POST['title']);
#header("Location: domain.com/tournament/{$id}-{$title}");
But I want a solution that's slightly more elegant like this:
$id = $this->TournamentModel->lastInsert();
Where lastInsert is actually a public method in the core model by retrieving not just the id of the last insert, but the entire row. I would then handle the title formatting and id concatenation right there.
Does something like this exist? Or at the very least is there a PDO method that returns the table that was inserted into so that I could construct a query using the table name and the id?
Check Doctrine or Propel.
They are two very famous Object Relational Mapper's, which have as base PDO.
ORM's can do what you asked, and have lots of other features you will enjoy, check it up.
Does a 'title' not belong to a Tournament object? i.e.
class TournamenentModel {
private $id;
private $title;
public function setTitle($title) {
$this->title = $title;
}
public function getTitleFormatted() {
return my_title_formatting_function($this->title);
}
}
in which case, your insert method might look something like
PDO::save(array('title' => $this->title));
and your workflow would be along the lines of:
$tournament = new TournamentModel();
$tournament->setTitle($_POST['title']);
$tournament->insert();
$title = $tournament->getTitleFormatted();
#header("Location: domain.com/tournament/{$id}-{$title}");
The title is persisted in memory until you release the object, there is no need to save and then retrieve it from a database?
I’m trying to better understand what the best method would be to persist data between requests in this scenario (using Zend Framework):
Say I have an Events controller and the default (index) view displays any existing Announcements (if there are any), and a link to Add a new Announcement (Both Event and Announcement are arbitrary objects). I’m trying to retrieve the eventId so I can associate the new Announcement with it when saving it to the database. Compositionally, an Event consists of 0 to many Announcements. From my limited understanding of the Zend Framework, I see two main options.
Option one: Make the URL something like ‘/event/addAnnouncement/eventId/5’, which makes retrieving the eventId easy via route/path parameters.
Option two: In the indexAction of the controller, save the eventId to a session variable, which can then be retrieved in the addAnnouncementAction of the Event controller. This way the Add Announcement link would simply be ‘/event/addAnnouncement/’.
Can anyone shed some light on which of these two ways is better, or if there is another way I’m not aware of?
As always, any help is much appreciated. Thanks.
The question to ask yourself is, how long do you need to persist the data? If you only need to save the data to pass it to the next action you can use POST or GET, the GET would pass through the url and the POST would not(typically).
The example you presented would suggest that you need to persist the data just long enough to validate, filter and process the data. So you would likely be very satisfied passing the few pieces of data around as parameters(POST or GET). This would provide the temporary persistence you need and also provide the added benefit of the data expiring as soon as a request was made that did not pass the variables.
A quick example (assume your form passes data with the POST method):
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost()){
$data = $form->getValues();//filtered values from form
$model = new Appliction_Model_DbTable_MyTable();
$model->save($data);
//but you need to pass the users name from the form to another action
//there are many tools in ZF to do this with, this is just one example
return $this->getHelper('Redirector')->gotoSimple(
'action' => 'newaction',
array('name' => $data['name'])//passed data
);
}
}
if you need to persist data for a longer period of time then the $_SESSION may come in handy. In ZF you will typically use Zend_Session_Namespace() to manipulate session data.
It's easy to use Zend_Session_Namespace, here is an example of how I often use it.
class IndexController extends Zend_Controller_Action {
protected $_session;
public function init() {
//assign the session to the property and give the namespace a name.
$this->_session = new Zend_Session_Namespace('User');
}
public function indexAction() {
//using the previous example
$form = new Application_Form_MyForm();
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost()){
$data = $form->getValues();//filtered values from form
//this time we'll add the data to the session
$this->_session->userName = $data['user'];//assign a string to the session
//we can also assign all of the form data to one session variable as an array or object
$this->_session->formData = $data;
return $this->getHelper('Redirector')->gotoSimple('action'=>'next');
}
}
$this->view->form = $form;
}
public function nextAction() {
//retrieve session variables and assign them to the view for demonstration
$this->view->userData = $this->_session->formData;//an array of values from previous actions form
$this->view->userName = $this->_session->userName;//a string value
}
}
}
any data you need to persist in your application can sent to any action, controller or module. Just remember that if you resubmit that form the information saved to those particular session variables will be over written.
There is one more option in ZF that kind of falls between passing parameters around and storing data in sessions, Zend_Registry. It's use is very similar to Zend_Session_Namespace and is often used to save configuration data in the bootstrap (but can store almost anything you need to store) and is also used by a number of internal Zend classes most notably the flashmessenger action helper.
//Bootstrap.php
protected function _initRegistry() {
//make application.ini configuration available in registry
$config = new Zend_Config($this->getOptions());
//set data in registry
Zend_Registry::set('config', $config);
}
protected function _initView() {
//Initialize view
$view = new Zend_View();
//get data from registry
$view->doctype(Zend_Registry::get('config')->resources->view->doctype);
//...truncated...
//Return it, so that it can be stored by the bootstrap
return $view;
}
I hope this helps. Pleas check out these links if you have more questions:
The ZF Request Object
Zend_Session_Namespace
Zend_Registry
Option 1 is better, although in your example this is not a POST (but it could be done with a POST).
The problems with option 2 are:
If a user had multiple windows or tabs open at the same time, relating to different events, how would you track which event ID should be used?
If a user bookmarked the add event page and came back later, the session var may not be set
Option 2 is also a little more complicated to implement, and adds a reliance on sessions.