this works fine:
print $cgi->header({-type => "text/html", -expires => "now"}),
$cgi->start_html({-title => "TEST PAGE",
-style => [{-type => "text/css", -src =>"one.css"},
{-type => "text/css", -src =>"calendar.css"}],
-script => [
{-type => "text/javascript", -src => "main.js"},
]}),
$cgi->start_form({-name => "test", -autocomplete => "off"});
but if instead I try:
my $html= $cgi->header({-type => "text/html", -expires => "now"}),
$cgi->start_html({-title => "TEST PAGE",
-style => [{-type => "text/css", -src =>"one.css"},
{-type => "text/css", -src =>"calendar.css"}],
-script => [
{-type => "text/javascript", -src => "main.js"},
]}),
$cgi->start_form({-name => "test", -autocomplete => "off"});
print $html;
The HTML is then displayed on the page instead of rendered? Why would saving all the HTML in a var then printing that var produce a different result than printing directly? It's difficult to capture what's different because of the subtle differences like capturing a \n\n ..
Do I have to sprint that header into the var or something?
Thanks!
Why would saving all the HTML in a var then printing that var produce a different result than printing directly?
For the same reason that
print 'foo', 'bar'; # outputs foobar
is different than
my $foo = 'foo', 'bar';
print $foo; # outputs foo
print takes a list and outputs all the elements separated by $, (undef by default).
The comma operator in scalar context evaluates its left operand, throws away the result, evaluates its right operand, and returns that value. So my $foo = 'foo', 'bar' assigns the string foo to $foo and returns the string bar.
Also note that the HTML generation functions in CGI.pm are deprecated:
HTML Generation functions should no longer be used
All HTML generation functions within CGI.pm are no longer being maintained. Any issues, bugs, or patches will be rejected unless they relate to fundamentally broken page rendering.
The rationale for this is that the HTML generation functions of CGI.pm are an obfuscation at best and a maintenance nightmare at worst. You should be using a template engine for better separation of concerns. See CGI::Alternatives for an example of using CGI.pm with the Template::Toolkit module.
These functions, and perldoc for them, are considered deprecated, they are no longer being maintained and no fixes or features for them will be accepted.
Related
I have these possible urls:
Having country at beginning:
peru/blog/search/my-search
peru/blog/tag/my-tag
peru/blog/my-blog-post
peru/blog/
peru/
Without Country at beginning:
blog/search/my-search
blog/tag/my-tag
blog/my-blog-post
blog/
/
How it works:
As I understand url management there are 2 processes:
When you write an url on the browser. In this case Yii tries to convert this url into a route and params.
When you are creating an url using Yii::$app->urlManager->createAbsoluteUrl, in example.
According to these, I am writing some rules in the urlManager, first the general config:
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => []
]
Now the rules:
'<country:peru|france>/<module:[\w\-]+>/tag/<tag:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>/search/<search:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>' => '<module>/index',
'<module:[\w\-]+>/tag/<tag:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>/search/<search:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>' => '<module>/index',
As you notice from the rules, I pass a parameter "module" in the url, and I want that one to be used as controller.
In the case of country I had to add some possible matches, if not I was not able to make it work.
With the above rules, It works when I input a "pretty" url on the browser like:
http://example.com/blog/search/my-search
But my issue starts If try to create an url:
Yii::$app->urlManager->createAbsoluteUrl(["blog/index", "module" => "blog"]
Rule: '<module:[\w\-]+>' => '<module>/index'
Url Expected: http://example.com/blog
Url Generated: http://example.com/blog?module=blog
It seems it does not fall in the rule, not sure.
If I try to create an url:
Yii::$app->urlManager->createAbsoluteUrl(['blog/index', 'module' => 'blog', 'slug' => 'my-post'])
Rule: '<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index'
Url Expected: http://example.com/blog/my-post
Url Generated: http://example.com/blog/my-post?module=blog
From these 2 cases, I notice it is adding the controller to the url
Questions:
In my rule I use I think it collides with predefined variables like: , . I have tried change it, but still same issue.
In the case of country I had to add possible options: Peru, france to make it work, if not it did not work, how can I make it work without those options?
The url match depends on the amount of query params or does it count controller and action too?
How can I make empty parameters be ignored for the rules, when creating an url?
Why is adding controller to the url?
Is the rules order correct?
I think I found a solution to all my questions:
So far I have not found predefined keywords for rules: <controller>, <action>, <module> are just name of variables, if someone knows something different, please let me know.
Yii URL manager (and probably any URL manager) can only match the amount of parameters we send and match it against rules, not the variable names, so if we send:
http://example.com/peru
http://example.com/es
Yii only understands that we are sending one parameter, so if in the rules we have:
'<language:[\w\-]*>' => 'language/index'
'<country:[\w\-]*>' => 'country/index'
Yii will use the first rule that matches, so in this case would be <language> rule which will match. Then Yii will pass a variable $language with "peru" as value to LanguageControlle, which is wrong.
So in order to help Yii we have to add patterns to help it use correct rule, we could add a pattern to match only any value with 2 characters or specific values list like:
<language:es|en> => 'language/index'
<country:[\w\-]*> => 'country/index'
In this case if we have "peru" as value, it will not match first rule, so it will use second one.
Answered above.
Ignore empty parameters, we can use + instead of * in the rules, in that way empty parameters will not match.
Remove the controller, we need to add a rule at the end:
'' => 'site/index'
Question ordering, it should start with the rules with most parameters and inside that group order them from the less generic to more generic rules.
At the end my rules are:
'<base:es|en>/<module:ideas|user|blog>/tag/<tag:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>/search/<search:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>/<slug:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>' => '<module>/index',
'<base:es|en>/<slug:contact>' => 'site/index',
'<base:es|en>' => 'site/index',
'<module:ideas|user|blog>/tag/<tag:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>/search/<search:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>/<slug:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>' => '<module>/index',
'<slug:contact>' => 'site/index',
'' => 'site/index',
I hope this saves time to someone in the future.
The problem is how you create URL. If <module> is available in route pattern (value in rules array), then you don't need to pass it manually. It will be detected from route.
Sou you should create your URLs like this:
Yii::$app->urlManager->createAbsoluteUrl(['blog/index', 'slug' => 'my-post'])
Yii::$app->urlManager->createAbsoluteUrl(['blog/index']);
I am using Yii2's pretty urls and want to play around with the rules defined in my UrlManager but not finding any documentation as to how I can define variables in the 'pattern' => 'route' rule set. Found some examples like
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
"home" => "site/index",
"login" => "site/login",
"sign-up" => "site/sign-up",
'<controller:[\w-]+>/<id:\d+>' => '<controller>/view',
],
],
But what does the :[\w-]+ or the :\d+ stand for?
What if I wanted, for example, to define a pattern to point to my action which needs two parameters
class MyController extends Controller{
...
public function actionMyAction($param1, $param2){
...
}
}
now I want my web users to type in the url bar www.mysite.com/my-controller/my-action/X-Y where X is the value of $param1 and Y is the value of $param2 and using - as a parameter separator.
Thanks.
[\w-]+ and \d+ are regular expressions, the first indicating any letter or the dash character, repeated one or more times, the section indicating numbers only, repeated one or more times.
In the rule expression, you use <variable name:regex> to put a placeholder for your route that will resolve to variables passed to your controller action.
The rule should look like this if both $param1 and $param2 are numbers.
'my-controller/my-action/<param1:\d+>-<param2:\d+>' => 'my-controller/my-action',
Swap \d for \w if you need letters.
When testing my Symfony 2.8 based webpage with Google PageSpeed Insights I am getting warned, that the HTML code is not minified.
This is true, while Assetic takes care of minifying all CSS files and JS scripts, the HTML code itself is quite dirty.
Google recommends to use HTML Minifier, but since this a JavaScript tools it cannot be used as Twig extension, filter, etc., can it?
The Twig docu of the spaceless tag makes clear, that this tag is not meant to minify HTML and furthmore:
If you want to create a tag that actually removes all extra whitespace
in an HTML string, be warned that this is not as easy as it seems to
be (think of textarea or pre tags for instance). Using a third-party
library like Tidy is probably a better idea.
But again I don't see how Tidy could be integrated into the Twig templates, etc.
So, what is the best way, to create minified HTML output with Symfony and Twig?
This is a good question and there isn't a flagship bundle but after a quick search, you have two bundle which could help you:
SemaMinifierBundle
This bundle allows you to minify in one config value all your responses (automatically on KernelResponse event) or, on demand, with a twig extension.
But this bundle is pretty old (3 years) and is not ready for Symfony3.
HtmlCompressorBundle
This bundle is a bit more recent and use the htmlcompressor library.
To achieve this several years later, i created a Subscriber on kernel.response event.
# src/Event/MinificationSubscriber.php
<?php
namespace App\Event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class MinificationSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::RESPONSE => ['onKernelResponse', -256]
];
}
public function onKernelResponse($event)
{
if (
$event->getRequestType() != HttpKernelInterface::MAIN_REQUEST
|| $event->getRequest()->get('_route') === 'admin' // don't apply on admin pages
) {
return;
}
$response = $event->getResponse();
$buffer = $response->getContent();
$replace = [
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\n([\S])/" => '$1',
"/\r/" => '',
"/\n/" => '',
"/\t/" => '',
'/ +/' => ' ',
];
if (false !== strpos($buffer, '<pre>')) {
$replace = [
'/<!--[^\[](.*?)[^\]]-->/s' => '',
"/<\?php/" => '<?php ',
"/\r/" => '',
"/>\n</" => '><',
"/>\s+\n</" => '><',
"/>\n\s+</" => '><',
];
}
$buffer = preg_replace(array_keys($replace), array_values($replace), $buffer);
$response->setContent($buffer);
}
}
Based on this post, this other one and this gist.
I wrote a small script which loops my current Jsonfile but it's not possible to append a key and value.
This is my file
[
{
"URL": "https://p59-caldav.icloud.com",
}
]
I would like to append a key and value like this
[
{
"URL": "https://p59-caldav.icloud.com",
"test": "test"
}
]
My current script setup
#!/usr/bin/env ruby
require 'rubygems'
require 'json'
require 'domainatrix'
jsonHash = File.read("/Users/ReffasCode/Desktop/sampleData.json")
array = JSON.parse(jsonHash)
File.open("/Users/BilalReffas/Desktop/sampleData.json","w") do |f|
array.each do |child|
url = Domainatrix.parse(child["URL"])
json = {
"url" => child["URL"],
"provider" => url.domain,
"service" => url.subdomain,
"context" => url.path,
"suffix" => url.public_suffix
}
f.write(JSON.pretty_generate(json))
end
end
The script overwrite my whole jsonfile...this is not what I want :/
This is untested but looks about right:
ORIGINAL_JSON = 'sampleData.json'
NEW_JSON = ORIGINAL_JSON + '.new'
OLD_JSON = ORIGINAL_JSON + '.old'
json = JSON.parse(File.read(ORIGINAL_JSON))
ary = json.map do |child|
url = Domainatrix.parse(child['URL'])
{
'url' => child['URL'],
'provider' => url.domain,
'service' => url.subdomain,
'context' => url.path,
'suffix' => url.public_suffix
}
end
File.write(NEW_JSON, ary.to_json)
File.rename(ORIGINAL_JSON, OLD_JSON)
File.rename(NEW_JSON, ORIGINAL_JSON)
File.delete(OLD_JSON)
It's important to not overwrite the original file until all processing has occurred, hence writing to a new file, closing the new and old, then renaming the old one to something safe, renaming the new to the original name, and then being able to remove the original. If you don't follow a process like that you run a risk of corrupting or losing your original data if the code or machine crashes mid-stream.
See "How to search file text for a pattern and replace it with a given value" for more information.
Probably the simplest way to use f.write would be to use it to replace the entire contents of the file. With that in mind, let's see if we can compose what we want the entire contents of the file to be, in memory, and then write it.
#!/usr/bin/env ruby
require 'rubygems'
require 'json'
require 'domainatrix'
write_array = []
jsonHash = File.read("/Users/ReffasCode/Desktop/sampleData.json")
read_array = JSON.parse(jsonHash)
read_array.each do |child|
url = Domainatrix.parse(child["URL"])
write_array << {
"url" => child["URL"],
"provider" => url.domain,
"service" => url.subdomain,
"context" => url.path,
"suffix" => url.public_suffix
}
end
File.open("/Users/BilalReffas/Desktop/sampleData.json","w") do |f|
f.write(JSON.pretty_generate(write_array))
end
Note some changes:
Fixed indentation :)
Removed some nesting
Write once with the entire contents of the file. Unless you have a really big file or a really important need for pipelined I/O this is probably the simplest thing to do.
Our client has a simple setup.
Page A has a form that submits to page B which displays the query results. Unfortunately, there is no other API or DB access to get the data.
Since we need to do this query often, we decided to automate this submission with Perl.
I've determined the form key value pairs of Page A with a sniffer and replicated the code. However, on running the program page B is throwing a HTTP 500 error with no additional meaningful explanation.
Any pointers to debug this code? Code in itself is simple:
use strict;
use warnings;
use LWP;
my $browser = LWP::UserAgent->new;
my $url = "targeturl.asp"
my $response = $browser->post( $url,
[
"HisSort" => "1",
"RTsort" => "",
"chkHisRun" => "on",
"chkRTRun" => "on",
"optAdHoc" => "on",
"optHist" => "",
"optServer" => "servername",
"optStatus" => "",
"optWhat" => "H",
"txtEnd" => "",
"txtFields" => "1,0,10,17,11,18,24,19,21,25,1",
"txtHEnd" => "11/3/2010",
"txtHStart" => "11/1/2010",
"txtServer" => "",
"txtStart" => "",
]
);
Note:
I don't have access to the source of page A or page B
Firstly, I suggest looking at WWW::Mechanize which is a friendlier wrapper around LWP. Secondly, if your HTTP client is getting 500 errors, then there should be something more meaningful in the web server error logs. And finally, as Matthew has mentioned, you need to closely examine the request being sent by the browser and work out how it differs from the request that your Perl program is sending.
Team,
This has been resolved.
It eventually turned out that the problem was not with the headers but with the key value pairs I was sending. Page B wasn't doing validations on the fields and was plugging them into a query directly.
I had to try some brute force combinations (by testing with Page A) to get to what exactly page B was expecting.
Thanks to all who volunteered to help.