On the page, there will be several posts by a user. Each post has an id # to identify it which is used when editing or deleting the post. With blade, I can make it so that hidden ID div only shows up when the authenticated user is on their own profile (since only they are allowed to edit or delete the posts).
However, I also have a liking feature that also uses that hidden ID div. I don't want someone to view the page source, change the ID, then click the like button. Is there a way to include the ID in the view, but not allow it to be changed?
I could try do to some validation on each like such as match the user, body, time posted, and ID and if that doesn't match then throw an error. Curious if there's a better way.
View:
<div class="post-like">
Like
</div>
Controller:
The $postId is that hidden ID div
public function getLike($postId)
{
$post = Post::find($postId);
if (!$post) {
return redirect()->back();
}
if (Auth::user()->hasLikedPost($post)) {
return redirect()->back();
}
$like = $post->likes()->create([]);
Auth::user()->likes()->save($like);
return redirect()->back();
}
It's not wise expose users' ID like this, but if you really need it, Laravel provides a way to handle users' action authorization. It can be done using either policies or model scopes.
Alternatively, you can ignore those authorizations and use UUID instead ID.
There is a nice package that handles it for you. Basically you'll just need to add a new field to the users' table.
In my applications I use both of them.
If I understand your question correctly, here's one idea: you can hide the actual post ID by concatenating your ID with some server-side only "key" and hashing.
For example:
In your app.php you add something like "post_mask_key" => "super_secret_123456"
...and in your code, something like:
$maskedPostId = sha1(\Config::get("app.post_mask_key") . $postId);
Then, share $maskedPostId with your view, which will be embedded into the HTML. The user can try to change it but when it is submitted, you can re-generate the hash easily (since you know both the key and ID server side) and compare the two.
Note: this approach is cryptographically weak but should be sufficient for masking a non-critical item like a post ID.
Related
I'm implementing a "Clone" button in my application, which should allow to perform the following:
create a copy of the chosen model;
redirect to the create view, whose form field should be populated with the cloned model's data;
allow the user edit some fields;
save the new model.
So far, my ModelController#clone method is:
$newModel = $existingModel->replicate();
$newModel->title = "Copy of ".$existingModel->title;
$newModel->created_at = now() // not sure if necessary, or if it'll be changed once the model is stored in the database
return redirect(route('models.create')); // I know this doesn't do what I need
As it is, obviously, nothing gets passed to the create view, but I can't find any clue on how to do that.
I have tried adding ->withInput(compact($newModel)) to the redirect() call, but I don't see the field being populated.
In the models.create view, I have set up the form field to use the old(...) data, if available.
This answer is almost what I need, but it would imply changing every field to check if there is some sort of input other than the old session data, like this:
<input [other attributes omitted] value="{{ $newModel['title'] ?? old('title') }}">
Is it the right way to do so, or is there a quicker/more standardized way of proceeding?
you could overriding the session old input data by:
Session::put('_old_input', $newModel);
and then just render the old() in form inputs
In laravel 5.8, I have have 2 type of url.
/news/{category} - > send to news controller index action, if have category bind
/news/{news} - > send to news controller details action, if have news bind
Another case abort with 404.
How can i solve this problem?
In Laravel and almost all frameworks and routing systems I'm aware of, the Route and Controller/Action relationship is 1:1. Each route can only have one controller or action to handle it.
If I understand your question correctly, you have a single route pattern of /news/{parameter}, and you want one of three things to happen:
{parameter} contains a valid Category slug. Retrieve the category and display the appropriate view.
{parameter} contains a valid Article (details) slug. Retrieve the article and display the appropriate view.
{parameter} does not contain a valid category or article slug, and thus is not found. Return a 404 error.
You'll still need only a single controller action, but you can separate the logic to make it easy to understand:
routes/web.php:
Route::get('/news/{param}', 'NewsController#index');
app/Http/Controllers/NewsController (with pseudo code):
class NewsController extends Controller
{
public function index(string $param)
{
if ($category = Category::whereSlug($param)->first()) {
// Return your category view.
}
if ($article = Article::whereSlug($param)->first()) {
// Return your article view.
}
\abort(404);
}
}
I would personally recommend against sharing a common URL structure for two different entity types like this. It opens the possibility for name conflicts (a Category and Article have the same slug) and can make the user experience confusing. (It might hurt search engine optimizations or results, also, but that's just speculation - I don't have anything to confirm or deny that.)
Basically I have an anchor tag (update) that gets the id of the request in the table and load the update view getting all the request details
<i class="fa fa-eye"></i> Update
This is then received in my method
public function update_request_view($idx)
{
//some code here to load the view and get details
}
The url then becomes http://localhost/dashboard/staff/request/update_request_view/48
Now when I try to save the update that I make using another method
public function update()
{
$idx = $this->uri->segment(5);
}
My $idx variable is empty. When I use $this->uri->segment(4), I get update_request_view.
I dont wanna use hidden fields since it will cause lots of security issues and also when I will be able to work this out i will encrypt the id. Why is my $this->uri->segment(5) empty and how do I get it?
Most likely, if I understand you correctly, it is because the update function is a separate page than http://localhost/dashboard/staff/request/update_request_view/48. So CI doesn't see any of the previous url variables. You can either submit to update/{$id} (action url) or you can use a hidden field; it is no less safer than using an id in the url as that can be just as easily manipulated with a change to the form action.
That being said, if you are really concerned about security you should restrict access to particular users for a given record using some sort of ACL.
is there a way to customize Laravel 5 resource URLs ?
For example, change user/1/edit to user/edit.
That's because I don't want anybody to see the id in the URL. I think it is database information and shouldn't be revealed.
The point is that I want to do this without changing my routes. On the other hands I want to do this by using resource routes I have and not by adding some new routes to them , as you know when you define a resource route in your project it automatically adds some predefined routes to the route table and you are forced to use them in the way they are. For example you have to send a GET request to user/{user} for showing the user. Now I want to have a URL like user/{username} for doing this without adding a new route, IS THAT EVEN POSSIBLE?
if there is a way for achieving this I appreciate it if you share it here.
Thanks a lot
Since in most cases id is an auto incremented value and guessable, better you can use any other unique column of users table here, e.g username and then using that column instead of id in resource controller. Suppose you've an unique username column in your table So, if you use that instead of id your call to user edit will be like:
{!! route('user.edit', $user->username) !!} // let's say username is shahrokhi
which is equivalent to
user/shahrokhi/edit
Now for example, in your resource controller to edit a user details code may be like:
public function edit($username)
{
$user = User::where('username', '=', $username)->firstOrFail();
// rest of your code goes here
}
And so on for other methods.
So I'm trying to extend the Blog tutorial adding some comments:
Post hasMany Comments
I want to display the add comment form in the same view as the 'post view'. Thing is I don't know the best way to get this approach. I thought about three ways:
Creating a function in Comments Controller to handle the data.
Creating a function in Post Controller to handle the data.
Deal with the data in the same function that deals with the post views.
The main problem with the two first 'solutions' is that the validation errors doesn't show up in the form unless I do some messy hacking of saving the invalidated field in a session variable and then parsing the variable on the beforeFilter callback, like this:
function beforeFilter () {
if ($this->Session->check('comment_error')) {
$this->Post->Comment->validationErrors = $this->Session->read('comment_error');
$this->Session->delete('comment_error');
}
}
What I basically do is adapt the invalidated fields to the actual view and allow it to show properly. This works really well, but it seems so ugly to me. What would be the best approach?
Another related question: should a controller reflect a view? I mean on that example, I thought about only having a Comment Model and dealing with all the data in the controller where's the form to add a comment (even though it's in the Post Controller).
Sounds like you're looking for the Mutlivalidatable behaviour: http://bakery.cakephp.org/articles/dardosordi/2008/07/29/multivalidatablebehavior-using-many-validation-rulesets-per-model
This allows you to define more than 1 validation ruleset per model. Use your controller to determine which one to apply upon posting something.
P.S. I have only ever used this on a Cake 1.3 project, not sure if it'll work on 2.0.
I see it this way:
Under every post there is an input box "Add comment" with a button to submit.
After submitting some text a form redirects to comments_controller where the comment is saved with this post_id, body, author, date etc.
After the comment is saved and all the logic is done it takes you back to the post.
Under each post there are all related comments displayed (having the same post_id sorted by date or whatever).