#!/usr/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
use URI::Escape;
use XML::Parser;
use HTML::Entities;
# Perl sample code for Copyscape Premium API
#
# Compatible with Perl 5.8.8 or later
#
# You may install, use, reproduce, modify and redistribute this code, with or without
# modifications, subject to the general Terms and Conditions on the Copyscape website.
#
# For any technical assistance please contact us via our website.
#
# 22-May-2013: First version
#
# Copyscape (c) Indigo Stream Technologies 2013 - http://www.copyscape.com/
#
#
# Instructions for use:
#
# 1. Set the constants COPYSCAPE_USERNAME and COPYSCAPE_API_KEY below to your details.
# 2. Call the appropriate API function, following the examples below.
# 3. The API response is in XML, which in this sample code is parsed and returned as an XML tree.
# 4. To run the examples provided, please change the value of the next line to 1:
use constant COPYSCAPE_RUN_EXAMPLES => 0;
# Error handling:
#
# * If a call failed completely (e.g. LWP::UserAgent failed to connect), functions return undef.
# * If the API returned an error, the response XML tree will contain an 'error' element.
# A. Constants you need to change
use constant COPYSCAPE_USERNAME => "your-copyscape-username";
use constant COPYSCAPE_API_KEY => "your-copyscape-api-key";
use constant COPYSCAPE_API_URL => "http://www.copyscape.com/api/";
# B. Functions for you to use (all accounts)
sub copyscape_api_url_search_internet
{
my ($url, $full) = @_;
$full = 0 if not defined $full;
return copyscape_api_url_search($url, $full, "csearch");
}
sub copyscape_api_text_search_internet
{
my ($text, $encoding, $full) = @_;
$full = 0 if not defined $full;
return copyscape_api_text_search($text, $encoding, $full, "csearch");
}
sub copyscape_api_check_balance
{
return copyscape_api_call("balance");
}
# C. Functions for you to use (only accounts with private index enabled)
sub copyscape_api_url_search_private
{
my ($url, $full) = @_;
$full = 0 if not defined $full;
return copyscape_api_url_search($url, $full, "psearch");
}
sub copyscape_api_url_search_internet_and_private
{
my ($url, $full) = @_;
$full = 0 if not defined $full;
return copyscape_api_url_search($url, $full, "cpsearch");
}
sub copyscape_api_text_search_private
{
my ($text, $encoding, $full) = @_;
$full = 0 if not defined $full;
return copyscape_api_text_search($text, $encoding, $full, "psearch");
}
sub copyscape_api_text_search_internet_and_private
{
my ($text, $encoding, $full) = @_;
$full = 0 if not defined $full;
return copyscape_api_text_search($text, $encoding, $full, "cpsearch");
}
sub copyscape_api_url_add_to_private
{
my ($url, $id) = @_;
my %params = ("q",$url);
$params{"i"} = $id if defined $id;
return copyscape_api_call("pindexadd", \%params);
}
sub copyscape_api_text_add_to_private
{
my ($text, $encoding, $title, $id) = @_;
my %params = ("e"=>$encoding);
$params{"a"} = $title if defined $title;
$params{"i"}=$id if defined $id;
return copyscape_api_call("pindexadd", \%params, $text);
}
sub copyscape_api_delete_from_private
{
my $handle = $_[0];
my %params = ("h",defined $handle ? $handle : "");
return copyscape_api_call("pindexdel", \%params);
}
# D. Functions used internally
sub copyscape_api_url_search
{
my ($url, $full, $operation) = @_;
$full = 0 if not defined $full;
$operation = "csearch" if not defined $operation;
my %params = ("q"=>$url,"c"=>$full);
return copyscape_api_call($operation, \%params);
}
sub copyscape_api_text_search
{
my ($text, $encoding, $full, $operation) = @_;
$full = 0 if not defined $full;
$operation = "csearch" if not defined $operation;
my %params = ("e"=>$encoding,"c"=>$full);
return copyscape_api_call($operation, \%params, $text);
}
sub copyscape_api_call
{
my ($operation, $params, $postdata) = @_;
$params = () if not defined $params;
my $uri = COPYSCAPE_API_URL . "?u=" . uri_escape(COPYSCAPE_USERNAME) . "&k=" . uri_escape(COPYSCAPE_API_KEY) . "&o=" . uri_escape($operation);
while((my $key, my $value) = each %{$params})
{
$uri .= "&" . $key . "=" . $value;
}
my $ua = new LWP::UserAgent;
my $req = new HTTP::Request((defined $postdata ? "POST" : "GET"), $uri);
if(defined $postdata)
{
$req->content_type("application/x-www-form-urlencoded");
$req->content($postdata);
}
my $res = $ua->request($req);
return undef if ($res->is_error);
my $parser = XML::Parser->new( Style => 'Tree' );
return $parser->parse($res->content);
}
sub copyscape_title_wrap
{
my $title = $_[0];
return "".$title.":
";
}
sub copyscape_node_wrap
{
my $tree = $_[0];
return "
" . copyscape_node_recurse(@{$tree}) . "
";
}
sub copyscape_node_recurse
{
my ($tag, $content, $depth) = @_;
$depth = 0 if not defined $depth;
my $ret = "";
if (ref $content)
{
$ret .= "\t"x($depth/2)."$tag: ";
for (my $i = 1; $i < $#$content; $i += 2)
{
$ret .= copyscape_node_recurse(@$content[$i],@$content[$i+1],$depth+1);
}
}
else
{
$ret .= encode_entities($content);
}
return $ret;
}
# E. Some examples of use
print "content-type: text/html\n\n";
return if not COPYSCAPE_RUN_EXAMPLES;
my $exampletext = "We hold these truths to be self-evident, that all men are created equal, that they are endowed by their ".
"Creator with certain unalienable rights, that among these are Life, Liberty, and the pursuit of Happiness. That to ".
"secure these rights, Governments are instituted among Men, deriving their just powers from the consent of the ".
"governed. That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to ".
"alter or to abolish it, and to institute new Government, laying its foundation on such principles and organizing ".
"its powers in such form, as to them shall seem most likely to effect their Safety and Happiness. Prudence, indeed, ".
"will dictate that Governments long established should not be changed for light and transient causes; and ".
"accordingly all experience hath shown, that mankind are more disposed to suffer, while evils are sufferable, than ".
"to right themselves by abolishing the forms to which they are accustomed. But when a long train of abuses and ".
"usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is ".
"their right, it is their duty, to throw off such Government, and to provide new Guards for their future security. ".
"Such has been the patient sufferance of these Colonies; and such is now the necessity which constrains them to ".
"alter their former Systems of Government. The history of the present King of Great Britain is a history of ".
"repeated injuries and usurpations, all having in direct object the establishment of an absolute Tyranny over these ".
"States. To prove this, let Facts be submitted to a candid world. He has refused his Assent to Laws, the most ".
"wholesome and necessary for the public good. ".
"We, therefore, the Representatives of the United States of America, in General Congress, Assembled, ".
"appealing to the Supreme Judge of the world for the rectitude of our intentions, do, in the Name, and by Authority ".
"of the good People of these Colonies, solemnly publish and declare, That these United Colonies are, and of Right ".
"ought to be free and independent states; that they are Absolved from all Allegiance to the British Crown, and that ".
"all political connection between them and the State of Great Britain, is and ought to be totally dissolved; and ".
"that as Free and Independent States, they have full Power to levy War, conclude Peace, contract Alliances, ".
"establish Commerce, and to do all other Acts and Things which Independent States may of right do. And for the ".
"support of this Declaration, with a firm reliance on the Protection of Divine Providence, we mutually pledge to ".
"each other our Lives, our Fortunes, and our sacred Honor.";
print copyscape_title_wrap("Response for a simple URL Internet search");
print copyscape_node_wrap(copyscape_api_url_search_internet("http://www.copyscape.com/example.html"));
print copyscape_title_wrap("Response for a URL Internet search with full comparisons for the first two results");
print copyscape_node_wrap(copyscape_api_url_search_internet("http://www.copyscape.com/example.html", 2));
print copyscape_title_wrap("Response for a simple text Internet search");
print copyscape_node_wrap(copyscape_api_text_search_internet($exampletext, "ISO-8859-1"));
print copyscape_title_wrap("Response for a text Internet search with full comparisons for the first two results");
print copyscape_node_wrap(copyscape_api_text_search_internet($exampletext, "ISO-8859-1", 2));
print copyscape_title_wrap("Response for a check balance request");
print copyscape_node_wrap(copyscape_api_check_balance());
print copyscape_title_wrap("Response for a URL add to private index request");
print copyscape_node_wrap(copyscape_api_url_add_to_private("http://www.copyscape.com/example.html"));
print copyscape_title_wrap("Response for a text add to private index request");
my $tree = copyscape_api_text_add_to_private($exampletext, "ISO-8859-1", "Extract from Declaration of Independence", "EXAMPLE_1234");
print copyscape_node_wrap($tree);
my ($tag, $content) = @{$tree};
my $handle = "";
for (my $i = 1; $i < $#$content; $i += 2)
{
$handle = @{@$content[$i+1]}[2] if @$content[$i] eq "handle";
}
print copyscape_title_wrap("Response for a URL private index search");
print copyscape_node_wrap(copyscape_api_url_search_private("http://www.copyscape.com/example.html"));
print copyscape_title_wrap("Response for a delete from private index request");
print copyscape_node_wrap(copyscape_api_delete_from_private($handle));
print copyscape_title_wrap("Response for a text search of both Internet and private index with full comparisons for the first result (of each type)");
print copyscape_node_wrap(copyscape_api_text_search_internet_and_private($exampletext, "ISO-8859-1", 1));