Showing posts with label libraries. Show all posts
Showing posts with label libraries. Show all posts

Tuesday, September 15, 2015

Free opensource geocoder and webservices for geonames and openstreetmap data Share on facebookShare on twitterShare on printMore Sharing Services

Free, open source, and ready to use geocoder and geolocalisation webservices

Gisgraphy : Easy geocoding for humans !

Since 2006, Gisgraphy has been a free, open source framework (except the Address parser that is not open source) that offers the ability to do geolocalisation and geocoding via Java APIs or REST webservices. Because geocoding is nothing without data, Gisgraphy provides an easy-to-use importer that will automatically download and import the necessary (free) data to your local database (OpenStreetMap, GeoNames and Quattroshapes : more than 100 million entries). You can also add your own data with the Web interface or the import connectors provided. Gisgraphy is production ready, and has been designed to be scalable (load balanced), high performance and is able to be used in other languages other than just Java : results can be output in XML, JSON, PHP, Python, Ruby, YAML, GeoRSS, or Atom. some popular GPS tracking System (OpenGTS or Traccar ) also includes a Gisgraphy client. Gisgraphy is a framework - as a result, it's flexible and powerful enough to be used in a lot of different use cases. read more
Try it ▸▸    Get started ▸▸ 

What's new :

  • Gisgraphy V 4.0 is out! It now manages house numbers, has 100% more data, better relevance, country codes are not required anymore, and SOOOOO much more.
  • Gisgraphy is candidate for the Dataconnexions competition, launched by the French government via the ETALAB mission. The goal is to promote the use of open data and encourage projects that use it.
  • To follow the one version / per year (and after more than one year of development), I am proud to announce that the Version 3.0 of Gisgraphy is now available. It is a major version where a LOT of functionalities have been added. See Why you should update... You can try it here.
  • Read more news

Webservices overview :

All the webservices are world wide (243 countries) and support pagination. Actually, there are 6 (web) services, and all are available for free athttp://services.gisgraphy.com. We also provide some HTML pages that uses the webservices under the hood. Below is a summary for each webservice:
  • Geocoding

    Provide an Address, structured or not, and get it's GPS position in 243 countries.
  • Reverse geocoding 

    Provide a GPS position and get the corresponding address
  • Street search / tracking

    Find streets and associated information for a given GPS point (and an optional name). It is very useful for tracking software like Open GTS or Traccar, but there are a lot of other use cases.
  • Find nearby

    Find places, streets or whatever you want around a GPS point for a given radius. Results can be sorted by distance.
  • Fulltext search / Autocompletion

    For a given text and an optional GPS point, find places, POIS, cities, streets, zip codes,... with information (coordinates, states, population, elevation, alternate names in many languages). Auto completion, location bias, spellchecking, all words required or not...
  • Address parser

    Divide a single address (as a string) into its individual component parts : house number, street type (directional, street, ..), street name, unit (apt, building, ...), zipcode, state, country, city.
Gisgraphoid logoGisgraphoidGisgraphoid is a library to do geocoding on your Android mobile phone or tablet with the same Geocoder API as Google but with Gisgraphy. Runs on all Android versions, free, no Google API needed by the device, no API key, no limit. You can display the result on OpenStreetMap or Google Maps (Google API key required)
leaflet logo Plugins
2 Leaflet plugins are availables to use the webservices directly on a map :Geocoding : It allows you to add a geocoding input with autocompletion on a leaflet map. It wraps the Gisgraphy js API.
 Reverse geocoding : It reverse geocodes when you rightclick on the map. It is an example and you can personalize it.

Openstreetmap data extract by country

Gisgraphy wants to simplify access to the OpeStreetMap data. The model of the OpenStreetMap data is in XML or PBF and is not simple to manage. To simplify this, we have :
  • Extracted all the streets(76 million), cities (4.3 million cities / 216,000 shapes), Points of interest (7 million), and house numbers(34 million) for all 240 countries and put it in a CSV/TSV format.
  • Split the main PBF file for each country.
  • Extracted the shape of more than 160,000 cities and localities from Quatroshapes with their associated geonames Id

All those files are freely available on our download server.. In addition to the native OpenStreetMap data, some pre-calculated fields (length, middle point) are added...Read more

A little bit further...

  • Importers from geonames CSV files. Just give the country(ies) you wish to import and / or the placetypes, and Gisgraphy downloads the files and imports them with all the alternate names (optional) and syncs the database with a fulltext search engine
  • All OpenStreetMap data is processed in CSV format (view data)
  • Importers for OpenStreetMap data in CSV (view data)
  • Importers for Quattroshapes data in CSV (view data)
  • Leaflet plugins
  • WorldWide geocoding / WorldWide reverse geocoding / street search WebServices;
  • REST WebService
  • Several output formats supported : XML, JSON, PHP, Ruby, Python, Atom, RSS / GeoRSS
  • Full text search (based on Lucene / Solr with default filters optimized for city search (case insensitive, separator characters stripping, ..) via an Java API or a webservice
  • Find nearby function (with limits, pagination, restrict to a specific country and/or language and other useful options) via a Java API or a Web Service
  • An admin / back office with statistics interface
  • Fully replicated / scalable / high performance / cached services
  • Search for ZIPcode name, IATA, ICAO
  • Internationalized (with support of Cryllic, Arabic, Chinese,... alphabet)
  • Dojo widgets / prototype / Ajax to ease search but can be use it even if javascript is not enabled on the client side
  • Opensearch module
  • Platform / language independent
  • Provides all the countries flags in svg and png format
  • ...http://www.gisgraphy.com/ https://github.com/gisgraphy/gisgraphy#leaflet-plugins

Taking screenshots of websites in PHP

Taking screenshos of websites is not a frequent requirement for developers but can come handy on many occasions. Although there are some nice solutions on the web, a particular one I found very good is wkhtmltoimage.
wkhtmltoimage is a simple shell utility which can be used to convert html to images using the webkitrendering engine, and qt.

Installation

To get started we need to first download and install the shell program wkhtmltoimage. Select the appropriate binaries for your platform. As I’m using Ubuntu 10, I downloaded the complied binary ‘wkhtmltoimage-0.10.0_rc2-static-i386.tar.bz2′. Extract it to a appropriate folder and you are ready to go.

Getting your first snapshot

The simplest way to get a snapshot of a url is through the following:
wkhtmltoimage http://www.bbc.com bbc.jpg
This will fetch the www.bbc.com index page and save it as a jpg image. Below are a few websites rendered using the wkhtmltoimage tool.

Customizing the output

wkhtmltoimage comes with a plethora of options, a few are shown below, more options can be found in the documentation.
The default output quality of the program is set to ’94’ which can make the size of some images a lot bigger, but you can change it to your liking using the below option.
wkhtmltoimage --quality 50 http://www.bbc.com bbc.jpg
Also by default all the images on a page are rendered in the final image, but you can disable images in the final screen-shot using the following:
wkhtmltoimage --no-images http://www.bbc.com bbc.jpg
You can also set the output height and width of the image (in pixels) as below.
wkhtmltoimage --height 600 --width 1800 http://www.bbc.com bbc.jpg
or crop the image to a specified size;
wkhtmltoimage --crop-h 300 --crop-w 300 --crop-x 0 --crop-y 0 
       www.bbc.com bbc.jpg
Sometimes the JavaScript on the webpage you are rendering can cause problems during rendering, preventing the program from saving the screenshot or causing a huge delay. In such cases you can ask wkhtmltoimage to not run JavaScript on the page while rendering.
wkhtmltoimage --disable-javascript http://www.bbc.com bbc.jpg

Using with PHP

Although this is not a pure PHP solution for taking screen shots, you can wrap the final command in ashell_exec function or download the ‘snappy’ PHP5 wrapper from below. The original library is locatedhere, but as the source keeps changing the examples given here do not work, so use the library given below.
Download Snappy
Downloads : 7047 / File size : 4.2 kB
shell_exec('./wkhtmltoimage --quality 50 http://www.bbc.com bbc.jpg');
Below is a short code using ‘snappy’ to take a screen-shot of bbc.com.
<?php
 
/* Tested on Ubuntu 10.0.4, requires PHP 5.3  */
 
namespace Knplabs\Snappy;
 
require_once('Knplabs/Snappy/Media.php');
require_once('Knplabs/Snappy/Image.php');
 
/* 'wkhtmltoimage' executable  is located in the current directory */
$snap = new Image('./wkhtmltoimage');
 
/* Displays the bbc.com website index page screen-shot in the browser */
header("Content-Type: image/jpeg");
$snap->output('http://www.bbc.com');
 
?>
and with a few options added…
<?php
 
/* Tested on Ubuntu 10.0.4, requires PHP 5.3  */
 
namespace Knplabs\Snappy;
 
require_once('Knplabs/Snappy/Media.php');
require_once('Knplabs/Snappy/Image.php');
 
$options = array('zoom' => 0.5, 'no-images' => true);
 
/* 'wkhtmltoimage' executable  is located in the current directory */
$snap = new Image('./wkhtmltoimage-i386',$options);
 
/* Displays the bbc.com website index page screen-shot in the browser */
header("Content-Type: image/jpeg");
$snap->output('http://www.bbc.com');
 
?>
In my opinion you should play with the shell program first till you get to know the complete options and only than use the ‘snappy’ PHP wrapper.
In closing here is the snapshot of my site ,rendered at 50% quality (click to zoom).
Happy rendering!! http://www.codediesel.com/php/taking-screenshots-of-websites-in-php/

Amazon Advertising API BrowseNodes

Amazon uses a hierarchy of nodes to organize its various items. Each node represents a collection of items, such as Harry Potter books, not the items themselves. Browse node IDs are positive integers that uniquely identify product collections, for example, Literature & Fiction: (17), Medicine: (13996), Mystery & Thrillers: (18), Nonfiction: (53), Outdoors & Nature: (290060). Amazon uses over 120,000 browse node IDs in the US locale alone.
The BrowseNodes tool automatically gets all the child BrowseNodes and their names. The program recursively traverses the BrowserNode hierarchy and returns all the BrowseNodes and their respective names. You can display the nodes on the console or save it to a CSV file. You can also include the library in your existing projects to process BrowseNodes.

Library Usage

The library is easy to use, and requires PHP and CURL installed on your system. The download includes a sample file with which you can immediately test the code. The sample file is shown below.
<?php
 
/* Example usage of the Amazon Product Advertising API */
include("amazon_api_class.php");
 
$public_key     = "YOUR-AMAZON-PUBLIC-KEY";
$private_key    = "YOUR-AMAZON-SECRET-KEY";
$region         = "com"; // or "CA" or "DE" etc.
 
$obj = new AmazonProductAPI($public_key, $private_key, $region);
 
/* Display the BrowseNodes to the console */
$obj->setMedia("display");
 
$obj->getBrowseNodes("1266092011");
 
?>
Before you begin to use the library, you need to enter your Amazon security credentials as shown above. Also in the ‘aws_signed_request.php’ file you will need to enter your Amazon Associate ID, as it is now mandatory. Find the following line in the file and add your Associated ID.
/* aws_signed_request.php */
.
.
$params["AssociateTag"]     = 'YOUR-ASSOCIATES-ID-HERE';
.
That is it. Now you are ready to get the BrowserNodes from Amazon. You can display the BrowserNodes on you console/browser or save it directly to a CSV file. For that you have to use the ‘setMedia’ method. Both example are shown below.

Display the BrowseNodes on the console

<?php
 
/* Example usage of the Amazon Product Advertising API */
include("amazon_api_class.php");
 
$public_key     = "YOUR-AMAZON-PUBLIC-KEY";
$private_key    = "YOUR-AMAZON-SECRET-KEY";
$region         = "com"; // or "CA" or "DE" etc.
 
$obj = new AmazonProductAPI($public_key, $private_key, $region);
 
/* Display the BrowseNodes to the console */
$obj->setMedia("display");
 
$obj->getBrowseNodes("1266092011");
 
?>
You enter the parent browsenode in the ‘getBrowseNodes’ method, after which the function recursively retrieves all the children nodes. To get started, you can find all the top browsenode values here, or you can get it from the Amazon link itself.
The output of the above is shown below. The output is indented so that you can visualize the hierarchy of the nodes.
Television & Video : AV Receivers & Amplifiers : 3213035011
Television & Video : Blu-ray Players & Recorders : 3213025011
      Blu-ray Players & Recorders : Blu-ray Recorders : 3213026011
      Blu-ray Players & Recorders : Blu-ray Players : 352697011
Television & Video : DVD Players & Recorders : 3213027011
      DVD Players & Recorders : DVD Players : 1036922
      DVD Players & Recorders : DVD Recorders : 1036920
Television & Video : DVD-VCR Combos : 886258
Television & Video : HD DVD Players : 352696011
Television & Video : Televisions : 172659
Television & Video : Home Theater Systems : 281056
.
.
The format of each line is given below.

Saving the BrowseNodes to a CSV

The following code shows how to save the browsenodes to a CSV file.
<?php
 
/* Example usage of the Amazon Product Advertising API */
include("amazon_api_class.php");
 
$public_key     = "YOUR-AMAZON-PUBLIC-KEY";
$private_key    = "YOUR-AMAZON-SECRET-KEY";
$region         = "com"; // or "CA" or "DE" etc.
 
$obj = new AmazonProductAPI($public_key, $private_key, $region);
 
/* Write the BrowseNodes to a CSV file */
$obj->setMedia("csv", "./nodes.csv");
 
$obj->getBrowseNodes("1266092011");
 
?>
The code saves all the browsenodes in a CSV file, after which you can use it with Excel or a simple text editor. A sample CSV ouput is shown below. The format is the same as the one given above.
"PlayStation 3","All Games","14210861"
"PlayStation 3","Action","14210761"
"Action","Fighting","14210981"
"Action","Military & Espionage","14210821"
"Action","Shooter","14210841"
"PlayStation 3","Adventure","14210851"
"PlayStation 3","Arcade","14210911"
"PlayStation 3","Board Games","14210921"

Changing Locales

Amazon being a world-wide venture the Product Advertising API operates in the following locales:
CA
CN
DE
ES
FR
IT
JP
UK
US
You can use different locale code to get the BrowseNodes for different regions. You set the locale parameter using the ‘$region’ variable; for example:
$region = "com"; // or "CA" or "DE" etc.

Getting the parent node details

You can also get information about a nodes parent node using the ‘getParentNode’ method.
<?php
 
/* Example usage of the Amazon Product Advertising API */
include("amazon_api_class.php");
 
$public_key     = "YOUR-AMAZON-PUBLIC-KEY";
$private_key    = "YOUR-AMAZON-SECRET-KEY";
$region         = "com"; // or "CA" or "DE" etc.
 
$obj = new AmazonProductAPI($public_key, $private_key, $region);
 
print_r($obj->getParentNode("14210821"));
 
?>
One other useful method you can use it ‘getNodeName’. This allows you to get the name of a given node id. This can be useful if you have a nodeid but need to gets it name.
<?php
 
/* Example usage of the Amazon Product Advertising API */
include("amazon_api_class.php");
 
$public_key     = "YOUR-AMAZON-PUBLIC-KEY";
$private_key    = "YOUR-AMAZON-SECRET-KEY";
$region         = "com"; // or "CA" or "DE" etc.
 
$obj = new AmazonProductAPI($public_key, $private_key, $region);
 
echo $obj->getNodeName("14210821");
 
?>
Note: Some categories contain hundreds to thousands of BrowserNodes, retreiving them can take some time and could trigger a PHP timeout error. To avoid this set PHP timeout to a large number as given below.
<?php
 
set_time_limit(10000); 
 
/* Example usage of the Amazon Product Advertising API */
include("amazon_api_class.php");
.
.
?>
Download code files
Downloads : 2703 / File size : 3.1 kB http://www.codediesel.com/libraries/amazon-advertising-api-browsenodes/

Period: Time range API for php

Date/time programming is one of the tricky aspects of software development. Although inherently not complex in itself, coding date/time algorithms can be a subtle source of bugs. Especially in web development a feature such as payment subscription processing that ranges from days to weeks to months can get complex quickly. Also such kind of scenarios require additional features like auto renewal, scheduled email alerts to subscribers etc. Such kind of features require good date/time handling algorithms and libraries that handle such chores are always welcome.

One such library I encountered recently is Period. The library helps resolve many recurrent issues around time range selection and usage.
Period lets you easily works with time ranges – creating a time range, comparing between ranges, checking if a range falls withing another range etc.

Installation

You need PHP >= 5.3.0 to use Period but the latest stable version of PHP is recommended. Period is available on Packagist and can be installed using Composer.
composer require league/period
You can also install the library as a standalone by downloading the zip an including it in your project.

Creating a Period

To start using the Period class the first task you have to do is create a Period object. The default way to instantiate a new Period is with the Period constructor –
Period::__construct($start, $end)
Both $start and $end parameters represent the period endpoints as DateTime objects. The $start represents the starting endpoint. The $end value represents the ending endpoint. $end must be greater or equal to $start or the instantiation will throw a LogicException error. $start point is included in the period while the $end point is excluded from the period.
You can instantiate the Period object like the following.
$period = new Period('2014-10-01 00:00:00', '2014-10-04 12:30:10');
OR
$start  = new Datetime('2014-10-01 00:00:00');
$end    = new Datetime('2014-10-04 12:30:10');
 
$period = new Period($start, $end);
You can either pass a time string as shown in the example above or pass a DateTime object. When you pass a string they are automatically converted to a DateTime object before processing.
Once you have instantiated Period object you can access its properties using various getter methods.
Period::getStart();
$startp = $period->getStart();
This will return the following DateTime object.
DateTime Object
(
    [date] => 2014-10-01 00:00:00
    [timezone_type] => 3
    [timezone] => UTC
)
Period::getEnd();
$endp = $period->getEnd();
This will return the following DateTime object.
DateTime Object
(
    [date] => 2014-10-04 12:30:10
    [timezone_type] => 3
    [timezone] => UTC
)
Period::getDuration($get_as_seconds = false);
$duration  = $period->getDuration();
This will return the following Period duration as a DateInterval object.
DateInterval Object
(
    [y] => 0
    [m] => 0
    [d] => 3
    [h] => 12
    [i] => 30
    [s] => 10
    [invert] => 0
    [days] => 3
)
Passing a ‘true’ parameter to the above method returns the period in seconds.
$duration  = $period->getDuration(true);
This will return the following (in seconds).
304210

Creating different period bocks

In the above examples we have created a period using 2 parameters, a start and end endpoints. However you can also quickly create various periods using some pre-built named constructors.
Period::createFromWeek($year, $week)
Returns a Period object with a duration of 1 week for a given year and week.
The $year parameter is a valid year;
The $week parameter is a selected week (between 1 and 53) according to the ISO8601 date and time standard;
//this period represents the 3rd week of 2014
$period = Period::createFromWeek(2014, 3);
You can now use the various methods on this period as done in the previous section, a example using ‘getStart’ is given below.
$start = $period->getStart();
This will return the following.
DateTime Object
(
    [date] => 2014-01-13 00:00:00
    [timezone_type] => 3
    [timezone] => UTC
)
Period::createFromMonth($year, $month);
Returns a Period object with a duration of 1 month for a given year and month.
The $year parameter is a valid year;
The $month parameter is a selected month (between 1 and 12);
//this period represents the month of October 2014
$period = Period::createFromMonth(2014, 10);
One important point should be mentioned here. When we use the ‘getEnd’ method on any period object, it returns the end point of the period, which as mentioned at the start of the post, is excluded from the period. The actual endpoint is ‘one less’ than the returned value. or example for the above ‘createFromMonth’ method the actual last day is ’31 Oct 2014′, but ‘getEnd’ returns ‘1st Nov 2014′. So keep this in mind while programming. This can lead to subtle bugs.
// returns DateTime 2014-11-01 00:00:00
$end = $period->getEnd();
Period::createFromQuarter($year, $quarter);
Returns a Period object with a duration of 3 months for a given year and quarter.
The $year parameter is a valid year;
The $quarter parameter is a selected quarter (between 1 and 4);
//this period represents the second quarter of 2013
$period = Period::createFromQuarter(2013, 2);
Period::createFromSemester($year, $semester);
Returns a Period object with a duration of 6 months for a given year and semester.
The $year parameter is a valid year;
The $semester parameter is a selected semester (between 1 and 2);
//this period represents the first semester of 2013
$period = Period::createFromSemester(2013, 1);
Period::createFromYear($year);
Returns a Period object with a duration of 1 year for a given year.
The $year parameter is a valid year;
//this period represents the year 1973
$period = Period::createFromYear(1973);
Period::createFromDuration($start, $duration);
Returns a Period object which starts at $start with a duration equals to $duration. This a generic way to create periods.
The $start represents the starting included endpoint expressed as DateTime object.
The $duration parameter is a DateInterval object;
$period = Period::createFromDuration('2012-04-01 08:30:25', '1 DAY');
$alt    = Period::createFromDuration('2012-04-01 08:30:25', new DateInterval('P1D'));
$other  = Period::createFromDuration(new DateTime('2012-04-01 08:30:25'), 86400);

Comparing time periods

An important element in creating time periods is the ability to compare them. The following methods help you compare different Period objects according to their endpoints or durations. Let us see how to compare using endpoints. The following tells whether two Period objects shares the same endpoints.
$orig  = Period::createFromMonth(2014, 2); // Feb 2014
$alt   = Period::createFromMonth(2014, 4); // Apr 2014
$other = Period::createFromDuration('2014-02-01', '1 MONTH');
 
$orig->sameValueAs($alt);   //return false
$orig->sameValueAs($other); //return true
In the above example both $orig and $other have the same endpoint – 2014-03-01 00:00:00.
The following example calculates whether two Period objects overlap each other or not.
$orig  = Period::createFromMonth(2014, 3);
$alt   = Period::createFromMonth(2014, 4);
$other = Period::createFromDuration('2014-03-15', '3 WEEKS');
 
$orig->overlaps($alt);   //return false
$orig->overlaps($other); //return true
$alt->overlaps($other);  //return true
In the above example the $orig Period overlaps the $other Period, although the 3 week of $other spills in the 4th month. A graphical representation is given below. A Period does not have to 100% overlap or cover another Period, a partial overlap qualifies.
period1
The following example tells if a Period contains a particular date.
$period = Period::createFromMonth(2014, 4);
$period->contains('2014-04-15');   //returns true;
Also the following code make it explicityle clear as mentioned above that a Period endpoint is not included the Period.
$period = Period::createFromMonth(2014, 4);
$period->contains($period->getEnd());  //returns false;
Another important method is to find differences between 2 Periods. The durationDiff method returns a difference between 2 Period objects, returning a DateInterval object.
$period    = Period::createFromMonth(2014, 1);
$altPeriod = Period::createFromMonth(2014, 3);
$diff = $period->durationDiff($altPeriod); // returns a DateInterval object
You can also return the difference in seconds.
$period    = Period::createFromMonth(2014, 1); // Jan 2014
$altPeriod = Period::createFromMonth(2014, 3); // Mar 2014
$diff_as_seconds = $period->durationDiff($altPeriod, true);
//$diff_as_seconds represents the interval expressed in seconds
The above example returns a difference of ‘0’ seconds as the month of January and March contains the same number of days and hence the difference will be ‘0’. However with the next example the difference will be ‘86400’ (1 day) seconds as April has 1 day less than January.
$period    = Period::createFromMonth(2014, 1); // Jan 2014
$altPeriod = Period::createFromMonth(2014, 4); // April 2014
$diff_as_seconds = $period->durationDiff($altPeriod, true);
//$diff_as_seconds represents the interval expressed in seconds
The final few methods that aid in comparing duration are given below. The first iscompareDuration. Compare two Period objects according to their duration.
Period::compareDuration(Period $period)
– Return 1 if the current object duration is greater than the submitted $period duration;
– Return -1 if the current object duration is less than the submitted $period duration;
– Return 0 if the current object duration is equal to the submitted $period duration;
$orig  = Period::createFromDuration('2014-01-01', '1 MONTH');
$alt   = Period::createFromDuration('2014-01-01', '1 WEEK');
$orig->compareDuration($alt);  //return 1
$alt->compareDuration($orig);  //return -1
To ease the method usage you can rely on the following alias methods which return boolean values:
Period::durationGreaterThan(Period $period)
Period::durationLessThan(Period $period)
Period::sameDurationAs(Period $period)
$orig  = Period::createFromDuration('2014-01-01', '1 MONTH');
$alt   = Period::createFromDuration('2014-01-01', '1 WEEK');
$other = Period::createFromDuration('2015-01-01', '1 MONTH');
 
$orig->durationGreaterThan($alt); //return true
$orig->durationLessThan($alt);    //return false
 
$alt->durationGreaterThan($other); //return false
$alt->durationLessThan($other);    //return true
 
$orig->sameDurationAs($other);    //return true
$orig->sameValueAs($other);       //return false
//the duration between $orig and $other are equals but not the endpoints!!

Modifying Periods

You can modify, add, merge Period objects. Note that Period object is an immutable value object so any change to its property returns a new Period object rather than changing the original.
Period::add($interval)
Returns a new Period object by adding an interval to the current ending excluded endpoint. The $interval parameter is expressed as a DateInterval object.
$period    = Period::createFromMonth(2014, 1);
$newPeriod = $period->add('2 WEEKS');
 
// $period->getStart() 2014-01-01 00:00:00
// $newPeriod->getStart() 2014-01-01 00:00:00
 
// $period->getEnd() 2014-02-01 00:00:00
// $newPeriod->getEnd() 2014-02-15 00:00:00
Period::sub($interval)
Returns a new Period object by substracting an interval to the current ending excluded endpoint. The $interval parameter is expressed as a DateInterval object.
$period    = Period::createFromMonth(2014, 3);
$newPeriod = $period->sub('2 WEEKS');
// $period->getStart() equals $newPeriod->getStart();
 
// $period->getStart() 2014-01-01 00:00:00
// $newPeriod->getStart() 2014-01-01 00:00:00
 
// $period->getEnd() 2014-02-01 00:00:00
// $newPeriod->getEnd() 2014-01-18 00:00:00
Period::merge(Period $period[, Period $…])
Merges two or more Period objects by returning a new Period object which encloses all the submitted objects.
$period = Period::createFromMonth(2014, 3); // March 2014
$alt    = Period::createFromMonth(2014, 5); // May 2014
$newPeriod = $period->merge($alt); // March 2014 to May 2014
 
// $period->getStart() 2014-03-01 00:00:00
// $newPeriod->getStart() 2014-03-01 00:00:00
 
// $period->getEnd() 2014-04-01 00:00:00
// $newPeriod->getEnd() 2014-06-01 00:00:00
 
// $newPeriod->getDuration(true) 7948800 ( 3months )
In the above example we have created 2 Periods, each of 1 month , March and May. When we merge the Periods the middle days are automatically added to the merged Period. In the above example the merged Period will also contain the month of April.
Period::intersect(Period $period)
Computes the intersection between two Period objects and returns a new Period object. Before getting the intersection, make sure the Period object at least overlaps.
$period    = Period::createFromDuration(2012-01-01, '2 MONTHS');
$altPeriod = Period::createFromDuration(2012-01-15, '3 MONTHS');
if ($period->overlaps($altPeriod)) {
    $newPeriod = $period->insersect($altPeriod);
    //$newPeriod is a Period object 
}
The following figure give a visual idea of the process.
period2

In summary

Rounding the discussion, the Period class can be used to easily develop subscription like solutions wherein we need to extensively process time ranges. http://www.codediesel.com/algorithms/period-time-range-api-for-php/