📄 demo.pl.txt
字号:
#!/usr/bin/perl -wuse strict;use WWW::Curl::Easy; # Needed for HTTP transactions.use URI::Escape; # Needed for uri_escape().use CGI qw(:standard); # Needed for parsing GET/POST params.use XML::Parser; # Needed for parsing XML.# Our Google Base API developer key.my $developerKey = "REPLACE WITH YOUR DEVELOPER KEY";# Parsed recipe entries from a query.my @parsedEntries;# Are we currently parsing an XML ENTRY tag?my $foundEntry;# Current XML element being processed.my $curElement;# Types of cuisine the user may select when inserting a recipe.my @cuisines = ('African', 'American', 'Asian', 'Caribbean', 'Chinese', 'French', 'Greek', 'Indian', 'Italian', 'Japanese', 'Jewish', 'Mediterranean', 'Mexican', 'Middle Eastern', 'Moroccan', 'North American', 'Spanish', 'Thai', 'Vietnamese', 'Other');# Returns the URI of this script.sub getSelfURI { return 'http://' . $ENV{"SERVER_NAME"} . $ENV{"SCRIPT_NAME"};}# Removes whitespace from the start and end of a string.sub trim { my($string) = @_; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string;}# Creates the XML content used to insert a new recipe.sub buildInsertXML { my $result = "<?xml version='1.0'?>" . "\n"; $result .= "<entry xmlns='http://www.w3.org/2005/Atom'" . " xmlns:g='http://base.google.com/ns/1.0'>" . "\n"; $result .= "<category scheme='http://base.google.com/categories/itemtypes'" . " term='Recipes'/>" . "\n"; $result .= "<title type='text'>" . param('recipe_title') . "</title>" . "\n"; $result .= "<g:cuisine>" . param('cuisine') . "</g:cuisine>" . "\n"; $result .= "<g:item_type type='text'>Recipes</g:item_type>" . "\n"; $result .= "<g:cooking_time type='intUnit'>" . param('cooking_time_val') . " " . param('cooking_time_units') . "</g:cooking_time>" . "\n"; $result .= "<g:main_ingredient type='text'>" . param('main_ingredient') . "</g:main_ingredient>" . "\n"; $result .= "<g:serving_count type='number'>" . param('serves') . "</g:serving_count>" . "\n"; $result .= "<content>" . param('recipe_text') . "</content>" . "\n"; $result .= "</entry>" . "\n"; return $result;}# Creates the XML content used to perform a batch delete.sub buildBatchDeleteXML { my $counter = 0; my $result = '<?xml version="1.0" encoding="UTF-8"?>' . "\n"; $result .= '<feed xmlns="http://www.w3.org/2005/Atom"' . "\n"; $result .= ' xmlns:g="http://base.google.com/ns/1.0"' . "\n"; $result .= ' xmlns:batch="http://schemas.google.com/gdata/batch">"' . "\n"; for my $key (param()) { if (index($key, "link_") == 0) { $counter++; $result .= '<entry>' . "\n"; $result .= '<id>' . param($key) . '</id>' . "\n"; $result .= '<batch:operation type="delete"/>' . "\n"; $result .= '<batch:id>' . $counter . '</batch:id>' . "\n"; $result .= '</entry>' . "\n"; } } $result .= '</feed>' . "\n"; return $result;}# Callback function that's fired as cURL objects receive chunks of# content data from the server.sub writeCallback { my ($data, $pointer) = @_; push @{$pointer}, $data; return length($data);}# Callback function that's fired as cURL objects receive chunks of# header data from the server. Since we don't need to do anything# with the headers for this application, this callback function# just returns the length of the data it received.sub headerCallback { my($data, $pointer) = @_; return length($data);}# Exchanges the given single-use token for a session# token using AuthSubSessionToken, and returns the result.sub exchangeToken { my $token = shift; my $curl = new WWW::Curl::Easy; my @body; my @authHeader = ("Authorization: AuthSub token=\"" . $token . "\""); $curl->setopt(CURLOPT_URL, "https://www.google.com/accounts/AuthSubSessionToken"); $curl->setopt(CURLOPT_FAILONERROR, 1); $curl->setopt(CURLOPT_WRITEFUNCTION, \&writeCallback ); $curl->setopt(CURLOPT_HEADERFUNCTION, \&headerCallback ); $curl->setopt(CURLOPT_FILE, \@body); $curl->setopt(CURLOPT_FOLLOWLOCATION, 1); $curl->setopt(CURLOPT_HTTPHEADER, \@authHeader); my $result = $curl->perform(); if ($result > 0) { return 0; } else { # Extract everything to the right of the equals sign in # the response "Token=..." my @splitStr = split(/=/, $body[0]); return trim($splitStr[1]); }}# Performs a query for all of the user's items using the# items feed, then parses the resulting XML with the# startElement, endElement and characterData functions# (below).sub getItems { my $token = shift; my $curl = new WWW::Curl::Easy; my @body; my @authHeader = ( 'Content-Type: application/atom+xml', 'Authorization: AuthSub token="' . trim($token) . '"', 'X-Google-Key: key=' . $developerKey ); $curl->setopt(CURLOPT_URL, "http://www.google.com/base/feeds/items?"); $curl->setopt(CURLOPT_FAILONERROR, 1); $curl->setopt(CURLOPT_WRITEFUNCTION, \&writeCallback ); $curl->setopt(CURLOPT_HEADERFUNCTION, \&headerCallback ); $curl->setopt(CURLOPT_FILE, \@body); $curl->setopt(CURLOPT_FOLLOWLOCATION, 1); $curl->setopt(CURLOPT_HTTPHEADER, \@authHeader); my $result = $curl->perform(); if (!$result) { my $parser = new XML::Parser(Handlers => {Start => \&handleXMLstart, End => \&handleXMLend, Char => \&handleXMLchar}); $parser->parse(join("", @body)); }}# Inserts a new recipe by performing an HTTP POST to the# items feed.sub postItem { my $curl = new WWW::Curl::Easy; my @body; my @authHeader = ( 'Content-Type: application/atom+xml', 'Authorization: AuthSub token="' . param('session_token') . '"', 'X-Google-Key: key=' . $developerKey ); $curl->setopt(CURLOPT_URL, "http://www.google.com/base/feeds/items"); $curl->setopt(CURLOPT_READFUNCTION, \&buildInsertXML); $curl->setopt(CURLOPT_INFILESIZE, length(buildInsertXML())); $curl->setopt(CURLOPT_UPLOAD, 1); $curl->setopt(CURLOPT_CUSTOMREQUEST, "POST"); $curl->setopt(CURLOPT_FAILONERROR, 1); $curl->setopt(CURLOPT_WRITEFUNCTION, \&writeCallback ); $curl->setopt(CURLOPT_HEADERFUNCTION, \&headerCallback ); $curl->setopt(CURLOPT_FILE, \@body); $curl->setopt(CURLOPT_FOLLOWLOCATION, 1); $curl->setopt(CURLOPT_HTTPHEADER, \@authHeader); my $result = $curl->perform(); return $result;}# Updates an existing recipe by performing an HTTP# PUT on its feed URI.sub updateItem { my $curl = new WWW::Curl::Easy; my @body; my @authHeader = ( 'Authorization: AuthSub token="' . param('session_token') . '"', 'X-Google-Key: key=' . $developerKey, 'Content-Type: application/atom+xml' ); my $feedURL = param('link'); chomp $feedURL; $curl->setopt(CURLOPT_URL, $feedURL); $curl->setopt(CURLOPT_READFUNCTION, \&buildInsertXML); $curl->setopt(CURLOPT_INFILESIZE, length(buildInsertXML())); $curl->setopt(CURLOPT_UPLOAD, 1); $curl->setopt(CURLOPT_CUSTOMREQUEST, "PUT"); $curl->setopt(CURLOPT_FAILONERROR, 1); $curl->setopt(CURLOPT_WRITEFUNCTION, \&writeCallback ); $curl->setopt(CURLOPT_HEADERFUNCTION, \&headerCallback ); $curl->setopt(CURLOPT_FILE, \@body); $curl->setopt(CURLOPT_VERBOSE, 1); $curl->setopt(CURLOPT_FOLLOWLOCATION, 1); $curl->setopt(CURLOPT_HTTPHEADER, \@authHeader); my $result = $curl->perform(); return $result;}# Deletes a recipe by performing an HTTP DELETE# on its feed URI.sub deleteItem { my $curl = new WWW::Curl::Easy; my $feedURL = param('link'); my @body; my @authHeader = ( 'Authorization: AuthSub token="' . param('session_token') . '"', 'X-Google-Key: key=' . $developerKey ); chomp $feedURL; $curl->setopt(CURLOPT_URL, $feedURL); $curl->setopt(CURLOPT_CUSTOMREQUEST, "DELETE"); $curl->setopt(CURLOPT_FAILONERROR, 1); $curl->setopt(CURLOPT_WRITEFUNCTION, \&writeCallback ); $curl->setopt(CURLOPT_HEADERFUNCTION, \&headerCallback ); $curl->setopt(CURLOPT_FILE, \@body); $curl->setopt(CURLOPT_FOLLOWLOCATION, 1); $curl->setopt(CURLOPT_HTTPHEADER, \@authHeader); my $result = $curl->perform(); return $result;}# Deletes all recipes by performing an HTTP POST to the# batch URI.sub batchDelete { my $curl = new WWW::Curl::Easy; my @body; my @authHeader = ( 'Content-Type: application/atom+xml', 'Authorization: AuthSub token="' . param('session_token') . '"', 'X-Google-Key: key=' . $developerKey ); $curl->setopt(CURLOPT_URL, "http://www.google.com/base/feeds/items/batch"); $curl->setopt(CURLOPT_READFUNCTION, \&buildBatchDeleteXML); $curl->setopt(CURLOPT_INFILESIZE, length(buildBatchDeleteXML())); $curl->setopt(CURLOPT_UPLOAD, 1); $curl->setopt(CURLOPT_CUSTOMREQUEST, "POST"); $curl->setopt(CURLOPT_FAILONERROR, 1); $curl->setopt(CURLOPT_WRITEFUNCTION, \&writeCallback ); $curl->setopt(CURLOPT_HEADERFUNCTION, \&headerCallback ); $curl->setopt(CURLOPT_FILE, \@body); $curl->setopt(CURLOPT_FOLLOWLOCATION, 1); $curl->setopt(CURLOPT_HTTPHEADER, \@authHeader); my $result = $curl->perform(); return $result;}# Callback function that's fired by the Expat XML parser on parsing# a start tag.sub handleXMLstart { my($parser, $elem, %attrs) = @_; $curElement = lc($elem); if ($curElement eq "entry") { $foundEntry = 1; push(@parsedEntries, {}); } elsif ($foundEntry && $curElement eq "link") { $parsedEntries[$#parsedEntries]{$attrs{"rel"}} = $attrs{"href"}; }}# Callback function that's fired by the Expat XML parser on parsing# an end tag.sub handleXMLend { my($parser, $elem) = @_;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -