Setting a route depending on a String in the URL with Symfony - php

I am pretty new to Symfony.
I need to check if an URL contains a certain word, which can be in any order, and if it has, it will be redirected to a certain page.
For example www.example.com/mystring/, www.example.com/content/mystring or www.example.com/001/content/mystring/ should redirect you to www.example.com/mystring because it contains mystring in the URL
This could be easy:
$routes->add('mystring', '/mystring/')
->controller([MyStringController::class, 'show'])
;
$routes->add('mystring', '{number}/{content}/mystring')
->controller([MyStringController::class, 'show'])
;
Etc etc the problem is that mystring could be anywhere in the URL.
I already have a workaround in the controller that will redirect you if the string, however I would like a clean solution in the Routing file.
So the question is:
Is there any way to set a route depending if a URL contains certain string that can be anywhere and in any order?

Theoretically, yes. A route placeholder usually isn't allowed to contain a /, because it makes things more difficult. However, there are ways to allow it. BUT, there are other problems arising, unless that additional magic string always takes priority over anything else that happens.
To allow a slash inside a placeholder, this is possible with this: https://symfony.com/doc/current/routing/slash_in_parameter.html
so essentially to add a slash, you'd have a route with
'/{url}', and requirement 'url' => '.+'
now, just a '.+' is not enough for your purpose though. I'm not absolutely certain about escaping in this case, but it would probably be something like
'url' => '.*\bmystring\b.*'
if \b is allowed, this means it's a word boundary (which is probably what you want).
otherwise '(.+/)*mystring(.+/|$)+' should do the trick
Also, you shouldn't name multiple routes the same ... also, this kind of route definition won't give you the other placeholders you have ...
If your special route should extend only existing routes, though, you should probably find a way to cycle through existing routes and add your magic string. But that's a different question ;o)

Related

Laravel - Proper way to support a URL piece that might have a slash in it?

I've defined a route in web.php that looks like this:
Route::delete('/app/charges-for-order/{orderId}', 'AppController#deleteOrderCharges');
It seems to work well apart from when orderId has a forward slash in it. Eg 11/11.
Naturally my first port of call was to generate the url in the frontend using encodeURIComponent:
/app/charges-for-order/${encodeURIComponent(orderId)} (in javascript)
Which produces the url /app/charges-for-order/11%2F11, replacing the forward slash with %2F -- however, this is giving me a 404, as if Laravel is still seeing %2F as a forward slash for routing purposes.
How can I allow orderId to have (encoded) forward slashes and still be part of the URL like that? Is there some alternate encoding scheme that Laravel will respect in this context?
Use where() clause in route file. Which allows you to use RegEx in the file.
->where('orderId', '^[0-9/]+$'); # or
->where('orderId', '[0-9/]+'); # this
Read - Regular Expression Constraints
IMPORTANT: Do not use ->where('orderId', '.*') or ->where('orderId', '.') any cost.
Side Note: I'm not debugging the DELETE route works or not, just testing whether you can pass params. As well, if you found extensive RegEx, use it. I used this for testing purposes, but still, it does the job
I tested with http://127.0.0.1:8090/app/charges-for-order/11/11 in my local, and the result was
I assume you are using Apache as HTTP server? At least Apache is by default decoding %2F behind your back: https://httpd.apache.org/docs/2.4/mod/core.html#allowencodedslashes
Changing this might be a bad idea, so I would suggest you would change your route to match all:
Route::delete('/app/charges-for-order/{orderId}', 'AppController#deleteOrderCharges')
->where('orderId', '.+');
I ended up just changing the methods in question to accept query parameters or post data instead, I was having trouble with the other answers.

The # sign in Laravel web.php route files

What exactly the '#' sign stand for in laravel route file web.php
Ex: Route::get('/', 'HomeController#index');? please don't tell me what this code does I already know that. but the question is why the # sign??
The'#' sign is not a method but the index is. so what is name of this # sign and what exactly it does? I'm just curious to know why??? the # sign.
The comments have mostly covered it, but I will add a few notes, because I think its an interesting question.
Technical usage
We can see by looking at the source, it's simply a good ol' fashioned explode statement, splitting the Controller from the method:
Proceeding comment
If the binding has an # sign, we will assume it's being used to delimit
the class name from the bind method name. This allows for bindings
to run multiple bind methods in a single class for convenience.
$segments = explode('#', $binding);
On a technical front, the "why" as mentioned by #JeffLambert is that any character that isn't a valid character for a class or method name, would work as a delimiter.
Non Technical
As mentioned by #aynber, you would need to ask the developers to get a concrete guess. However I will hazard a (very reasonable) guess:
# is commonly used in editors to mark a method. For example, in sublime, open the command panel and type # and it will show you a list of all methods in the current class/file:
I would also argue that it reads quite naturally. Use controller "at" this method.

laravel. Replace %20 in url

I have simple problem, I have to replace %20 and other crap from URL. At the moment it looks like this http://exmaple/profile/about/Eddies%20Plumbing. As you can see it's profile link.
Yes I could add str_replace values before every hyperlink, but I have like 10 of them and I think it's bad practice. Maybe there is better solution? What solution would you use? Thanks.
That is not crap, that is a valid unicode representation of a space character. And it's encoded because it's one of the characters that are deemed unsafe by RFC1738:
All unsafe characters must always be encoded within a URL. For
example, the character "#" must be encoded within URLs even in
systems that do not normally deal with fragment or anchor
identifiers, so that if the URL is copied into another system that
does use them, it will not be necessary to change the URL encoding.
So in order to have pretty URLs, you should avoid using reserved and unsafe characters which need encoding to be valid as part of a URL:
Reserved characters: $ & + , / : ; = ? #
Unsafe characters: Blank/empty space and < > # % { } | \ ^ ~ [ ] `
Instead replace spaces with dashes, which serve the same purpose visually while being a safe character, for example look at the Stack Overflow URL for this question. The URL below looks just fine and readable without spaces in it:
http://exmaple/profile/about/eddies-plumbing
You can use Laravel's str_slug helper function to do the hard work for your:
str_slug('Eddies Plumbing', '-'); // returns eddies-plumbing
The str_slug does more that replace spaces with dashes, it replaces multiple spaces with a single dash and also strips all non-alphanumeric characters, so there's no reliable way to decode it.
That being said, I wouldn't use that approach in the first place. There are two main ways I generally use to identify a database entry:
1. Via an ID
The route path definition would look like this in your case:
/profiles/about/{id}/{slug?} // real path "/profiles/about/1/eddies-plumbing"
The code used to identify the user would look like this User::find($id) (the slug parameter is not needed, it's just there to make the URL more readable, that's why I used the ? to make it optional).
2. Via a slug
The route path definition would look like this in your case:
/profiles/about/{slug} // real path "/profiles/about/eddies-plumbing"
In this case I always store the slug as a column in the users table because it's a property relevant to that user. So the retrieval process is very easy User::where('slug', $slug). Of course using str_slug to generate a valid slug when saving the user to the database. I usually like this approach better because it has the added benefit of allowing the slug to be whatever you want (not really needing to be generated from the user name). This can also allow users to choose their custom URL, and can also help with search engine optimisation.
The links are urlencoded. Use urldecode($profileLink); to decode them.
I am parsing the url tha i got in this way ->
$replacingTitle = str_replace('-',' ',$title);
<a href="example.com/category/{{ str_slug($article->title) }}/" />
In your view ...
{{$comm->title}
and in controller using parsing your url as
public function showBySlug($slug) {
$title = str_replace('-',' ',$slug);
$post = Community::where('title','=',$title)->first();
return view('show')->with(array(
'post' => $post,
));
}

Matching a complicated route with a regular expression

I'm currently working on a request router for a large PHP based website that I'm working on, but I'm getting stuck trying to use a custom form of expression for my routes.
While I know there are pre-made alternatives and routers that could make my life easier, and would have the same features (in fact, I've been looking at their source code to try and solve this), I'm still a programming student and learning how to create my own can only be a good thing!
Examples:
Here's an example of one of my route expressions:
<protocol (https?)>://<wildcard>.example.com/<controller>/{<lang=en (en|de|pl)>/}<name ([a-zA-Z0-9_-]{8})>
This could match either of these equally well:
http://www.example.com/test/en/hello_123
https://subdomain.example.com/another_test/hello_45
Returning me a nice, handy array like this (for the latter):
array(
'protocol' => 'http',
'wildcard' => 'subdomain',
'controller' => 'another_test',
'lang' => 'en',
'name' => "hello_45"
)
I can also include an array in the first place, with default values that would be overridden by the values found by the router. So, for example, I could leave out the <controller> variable and just write test instead, and then use the array, adding "controller"=>"test".
Here's the rules:
If there's no match, there's no match. Variables have to exist, and if they don't, the route is skipped. Goodbye. Optional sections don't have to exist, luckily.
Anything between <> is a variable. Escaped \<\> are ignored, even when between. The area matching in the URL should be saved to the result array, with the variable name as the key.
Curly braces {} mark a section as optional, and can never be inside a variable <>. Anything between them can be ignored in the target - however, if there is a default value specified for any variables in between, that variable must be added to the result array, using the name as the key, and with the default value as the value. Escaped braces are ignored.
A variable doesn't have to have a default value, but if you add one, it needs to be after an =, like <name=default>.
Regex rules can be added, separated by a space after the name or default value, and encased in brackets (). Escaped brackets are ignored, of course.
Lastly, you can just put Regex rules, in brackets, anywhere, if you don't mind matching anything and not getting a result. So, I could just replace <controller> with ([\/]+), but then I'd have to use the array to set a value for it instead.
What I've Tried:
I've been reading the source code of every Router I can find.
So far, I've done a couple of nasty little regular expressions, but I realised I was confused completely about how to conglomerate them and extend them.
This matches the brackets, ignoring escaped ones: {([^{\\]*(?:\\.[^}\\]*)*)}
This matches a variable, with or without the default value: <([^<\\]*(?:\\.[^>\\]*)*)(?:=?([^<>\\]*))>
This is a kind of unholy hell, the like of which made me write this post: <([^<\\]*(?:\\.[^>\\]*)*)(?:=?([^<>\\]*))(?: ?)(\([^{}<>\(\)\\]+\))?>
(It does, however, match the variables and the Regex sections.)
Can anybody give me any hints, or even example source code from libraries that offer similar functionality? And if this is really near impossible to code myself, is there a library good enough to use?
If you are trying to match the domain, this regex101 demo should match those portions with the individual sections named.
On the other hand, if you are trying to match the route expression, this other regex101 demo is able to parse the tokens you specified so far.
I may have missed some specifications, but you can always leave feedback and explain where it falls short (or even update the regex on that site itself and save a newer version).

Zend Routing -- Grabbing Variables from URL with Ampersands and not Slashes - Tapjoy

I'm currently creating attempting to integrate with the Tapjoy API with their callback URL request which comes in this form:
<callback_url>?snuid=<user_id>&currency=&mac_address=<mac_address>&display_multiplier=<display_multiplier>
However, using ZF1 --
the Zend_Controller_Router_Route seems to be dependent on the variable separation being delimited by slashes and not ampersands.
Here is my current Route code
> $router->addRoute( 'api-tapjoy', new Zend_Controller_Router_Route('api/tapjoy?snuid=:snuid&mac_address=:&mac_address&display_multiplier....etc.etc,
array('controller'=>'api', 'action' =>'tapjoy')));
Whenever I remove the ampersands and initial question mark and replace them with slashes it works. How can I properly receive the HTTP Request whilst using ampersands?
Looks like I figured it out. It has nothing to do with ampersands and slashes, etc. but rather that my Route wasn't created properly.
I was thrown off by this documentation on ZF1's website about routers:
The first parameter in the Zend_Controller_Router_Route constructor is
a route definition that will be matched to a URL. Route definitions
consist of static and dynamic parts separated by the slash ('/')
character. Static parts are just simple text: author. Dynamic parts,
called variables, are marked by prepending a colon to the variable
name: :username.

Categories