I'm running into problems trying to pass absolute URIs as parameters with clean URLs enabled.
I've got hook_menu() set up like this:
function mymodule_menu() {
return array(
'page/%' => array(
'title' => 'DBpedia Display Test',
'page callback' => 'mymodule_dbpedia_display',
'page arguments' => array(1),
),
);
}
and in the page callback:
function mymodule_dbpedia_display($uri) {
// Make an HTTP request for this URI
// and then render some things
return $output;
}
What I'm hoping to do is somehow pass full URIs (e.g. "http://dbpedia.org/resource/Coffee") to my page callback. I've tried a few things and nothing's worked so far...
http://mysite.com/page/http%3A%2F%2Fdbpedia.org%2Fresource%2FCoffee Completely breaks Drupal's rewriting
http://mysite.com/page/?uri=http%3A%2F%2Fdbpedia.org%2Fresource%2FCoffee Gives a 404
http://mysite.com/page/http://dbpedia.org/resource/Coffee Returns just "http:", which makes sense
I could probably use $_GET to pull out the whole query string, but I guess I'm hoping for a more 'Drupal' solution. Any suggestions?
I have had this problem before, trying to do the same thing (RDF browsing). I got round it by using rawurlencode and rawurldecode on the URI.
So when creating link do
l('Click Here', 'page/' . rawurlencode($uri));
and when using your $uri variable do a rawurldecode();
$uri = rawurldecode($uri);
It will give you a URI something like
http://mysite.com/page/http%253A%252F%252Fdbpedia.org%252Fresource%252FCoffee
Instead of using page/%, use page/%menu_trail. %menu_trail will pass the rest of the URL as a single string that in your example will be passed to the menu callback as $uri.
If the source of the urls is something you control, why don't you use a reversible encoding, like base64, to encode the string and therefore remove any tricky characters, then decode when you execute your menu callback. Eg:
$link = 'http://www.example.com?uri='. base64_encode($uri);
...
function mymodule_dbpedia_display($uri) {
$uri = base64_decode($uri);
// Make an HTTP request for this URI
// and then render some things
return $output;
}
This should just work; it's a known bug in Drupal. You could try the patches in that thread, but your best bet may be to just do a different encoding on top of URL encoding, as others have suggested.
It's much easier than all this so long as you get to encode your own URIs - read these docs, all secrets shall be revealed: drupal_urlencode()
Cheers
Related
I'm new in Yii2 and I'm not able to find something to do a back button in Yii2,
I found the solution in Yii1 is:
echo CHtml::link('Back',Yii::app()->request->urlReferrer);
but I'm not able to find a solution in Yii2,
can you help me?
Try:
echo \yii\helpers\Html::a( 'Back', Yii::$app->request->referrer);
Yii2 provides remember URLs functionality:
// Remember current URL
Url::remember();
// Remember URL specified. See Url::to() for argument format.
Url::remember(['product/view', 'id' => 42]);
// Remember URL specified with a name given
Url::remember(['product/view', 'id' => 42], 'product');
In the next request we can get URL remembered in the following way:
$url = Url::previous();
$productUrl = Url::previous('product');
I hope I may ask this question without going into the details of why I need to do this,
I have a route
/**
* #Route("/edit/{id}", name="my_edit_route")
*/
public function editAction()
{ /* ....... */ }
And now at some other point in time, I have a URL which was generated with this route (I only have the string, no other information is available). The string looks like this
/edit/23
Is there anyway in Symfony2, that I can provide the route name (e.g. "my_edit_route" and this URL string, and have Symfony extract the parameters. (e.g. the id=23)
p.s. I know this could be done with regex or other tools, but my actual routes in my application are more complex.
I am sure this should not be to difficult for Symfony2 to do, as it already does this each time it extracts the parameters from your URL to handle a request.
you no need to route name
$params = $this->get('router')->match('/edit/23');
that return $params as:
array(
'id' => '23',
'_controller' => 'AppBundle:Blog:show',
)
When I do a forward() in a controller, I lose my route and route_parameters.
When I have ParentAction, that does a forward to ChildAction. In Childaction I do return $this->render('myTemplate.html.twig', array()); then the request attributes get nested!
So when the template gets rendered, instead of $request['attributes']['_route_parameters'] I get $request['attributes']['request']['attributes']['_route_parameters'].
Although in ChildAction, when I do a $this->getRequest(); the hierarchie is normal.
Is this a bug, or am I doing something wrong?
The reason is that symfony doesn't assume you have the same route parameters.
So when you forward you need to re-supply the route parameters required by the new route even if they are the same.
(Incidentally you must also provide any query parameters for the new route.)
public function indexAction($param)
{
return $this->forward(
'AppBundle\\Controller\\DefaultController::otherAction',
array("someOtherParam" => $param),
$request->query->all() // Causes query string params to be copied
);
}
// This route has a different parameter.
public function otherAction($someOtherParam) ...
A possible solution would be to pass your Request as second parameter when forwarding.
$response = $this->forward('MyBundle:MyController:myAction', array('request' => $request));
Also, as forward is just a shortcut for core Symfony2 functionality, this may probably help.
In my case following code helped:
$subRequest = $this->container->get('request')->duplicate(
array(),
null,
array('topicId' => $topicId,'_controller' => 'SomeBundle:Topic:close'));
return $this->container->get('http_kernel')
->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
"Topic" is TopicController and "close" is closeAction
I have an issue with triming a field before it is saved. I wanted to use substr(), or regex() with preg_match(). I have built a Drupal 7 module, but it can't work at all. I have tried using the trim plugin in feeds tamper module, but it doesn't seem to work. The data I am using is from a feed from Google Alerts. I have posted this issue here.
This is what I have done so far, and I know my regular expression is wrong; I was trying to get it do anything, just to see if I could get it to work, but I am pretty lost on how to add this type of function to a Drupal module.
function sub_node_save() {
$url = $node->field_web_screenhot['und'][0]['url'];
$url = preg_match('~^(http|ftp)(s)?\:\/\/((([a-z0-9\-]*)(\.))+[a-z0-9]*)($|/.*$)~i',$url );
$node->field_web_screenhot['und'][0]['url'] =$url;
return ;
}
I used the Devel module to get the field.
If there's an easy way to use substr(), I would consider that or something else.
Basically, I just want to take the Google redirect off the URL, so it is just the basic URL to the web site.
Depending on your question and later comments, I'd suggesting using node_presave hook (http://api.drupal.org/api/drupal/modules!node!node.api.php/function/hook_node_presave/7) for this.
It's called before both insert (new) and update ops so you will need extra validations to prevent it from executing on node updates if you want.
<?php
function MYMODULE_node_presave($node) {
// check if nodetype is "mytype"
if ($node->type == 'mytype'){
// PHP's parse_url to get params set to an array.
$parts = parse_url($node->field_web_screenhot['und'][0]['url']);
// Now we explode the params by "&" to get the URL.
$queryParts = explode('&', $parts['query']);
$params = array();
foreach ($queryParts as $param) {
$item = explode('=', $param);
$params[$item[0]] = $item[1];
}
//valid_url validates the URL (duh!), urldecode() makes the URL an actual one with fixing "//" in http, q is from the URL you provided.
if (valid_url(urldecode($parms['q']))){
$node->field_web_screenhot['und'][0]['url'] = urldecode($parms['q']);
}
}
}
Drupal inserts a form_token as a hidden field when it renders forms. The form_token is then checked on form submission to prevent cross-site request forgery attacks. The form data that is submitted is guaranteed to have come from the original form rendered by Drupal.
However, forms using the "GET" method shouldn't need this token. All it does is lengthen and uglify the resulting URL.
Is there any way of suppressing it?
Yes, there is a way, but use it consciously (see warning below):
If you create the form yourself, adding
$form['#token'] = FALSE;
to the form definition array should prevent a token from being generated in the first place.
If you are dealing with an existing form, you can bypass the token validation process by unsetting the '#token' element on hook_form_alter:
// Example for removal of token validation from login (NOTE: BAD IDEA!)
function yourmodule_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'user_login_block') {
unset($form['#token']);
}
}
Warning: Given your question, I think there is a slight misconception concerning the difference (better, the lack of a difference) between GET and POST requests.
... on forms using the "GET" method
shouldn't need this token. All it does
is lengthen and uglify the resulting
URL.
This is wrong! GET and POST are just two different, but mostly equivalent methods of transmitting data from the client to the server. Since POST is better suited to transfer large amounts of data (or difficult formatted data), it is the established standard for submitting forms, but it is in no way safer/unsafer or more/less secure than GET requests. Both type of requests can be tampered with by malicious users in the same ways, hence both types should use the same protection mechanisms.
With a GET request, the token does exactly the same as with a POST request - it proves to the server that the submitted data comes from the same Browser on the same machine as the request he build the form for! So you should only remove it if you are sure that the request can not be misused via XSRF.
This worked for me. I had to unset all the form api elements and set the #token property to false. Notice the after_build function for unsetting the other properties.
function mymodule_form(&$form_state){
$form['name'] = array(
'#type' => 'textfield',
'#title' => 'name',
'#value' => 'name',
);
$form['#method'] = 'get';
$form['#action'] = url('someurl');
$form['submit'] = array('#type' => 'submit', '#value' => 'go');
$form['#token'] = false;
$form['#after_build'] = array('mymodule_unset_default_form_elements');
return $form;
}
function mymodule_unset_default_form_elements($form){
unset($form['#build_id'], $form['form_build_id'], $form['form_id']);
return $form;
}
The site I work on uses the Drupal 6 form API for custom search forms, so by removing the token and build id we were able to cache the results in memcache. Now we've moved to Acquia hosting, it's cached using Varnish.
To remove the form_token and form_build_id from your form and submit it as a GET request, use the following method:
<?php
function module_example_form($form_state, $form_id = NULL) {
// Form root settings.
$form = array();
// Set the submission callback for this form.
$form['#submit'][] = __FUNCTION__ . '_submit';
// Set the request method for this form to GET instead of the default
// of POST.
$form['#method'] = 'get';
// Remove unique form token so request can be cached. This is accompanied by
// code in hook_form_alter to ignore the token and remove the build_id.
$form['#token'] = FALSE;
// Submit button.
$form['go'] = array(
'#type' => 'submit',
'#value' => t('Go!'),
);
return $form;
}
/**
* Implements hook_form_alter().
*/
function module_form_alter(&$form, $form_state, $form_id) {
// Changes to the 'module_example_form' form.
if ($form_id == 'module_example_form') {
// Unset the hidden token field and form_build_id field.
unset($form['#token'], $form['form_build_id'], $form['#build_id']);
}
}
?>
I find that simply throwing away the CSRF token is not an option. We solved it using hook_theme_registry_alter() to overwrite the Drupal core theme_hidden() function so that the hidden form element 'form_token' is rendered as an <esi /> tag. The tag will cause Varnish to make a call to a PHP file which we allow to pass through the cache. This file will calculate the proper form token for the current user and will then output the HTML code for the hidden field. You can calculate this token without a Drupal bootstrap, but you will need a single DB query to fetch the *drupal_private_key* for your site, which is stored in the variable table.