UNIVERSITY OF MARIBOR
FACULTY OF ELECTRICAL ENGINEERING AND COMPUTER SCIENCE
Internship Report at
InGenius Labs
Perth, Western Australia
Duration 24 April 2012 to 27 July 2012
Mentor Stuart Kidd
Student Bojan Kogoj
Enrolment number E1031364
Email address [email protected]
Telephone number +386 41 393 561
4
Contents
1 INTRODUCTION 6
1.1 Perth 6
1.2 InGenius Labs 6
2 INTERNSHIP 7
2.1 Working environment and tasks 7
2.2 Tools 7
2.2.1 NetBeans 7
2.2.2 EasyPHP 8
2.2.3 Kohana PHP framework 8
2.2.4 Dropbox 9
2.2.5 JQUERY 9
2.2.6 JSON 9
2.2.7 Google maps 10
2.2.8 Piwik 10
3 THE PROJECTS 11
3.1 Olsen Environment.com.au 11
3.2 Envoy Settlement Agency 12
3.3 Property Resource 13
3.4 Reportable 14
3.5 InGenius Labs 15
3.5.1 News 15
3.5.2 Application – Emotion detective 15
3.5.3 Application – Property Resource 15
3.6 Backpacker Application 16
3.7 Mobile club guide 19
3.7.1 Search 19
3.7.2 User location 20
3.7.3 Location 21
3.7.4 Venues 23
3.7.5 Event 25
3.7.6 Venue 26
3.7.7 Reports 29
3.7.8 Most popular 29
3.7.9 Editing and creating pages 31
3.7.10 Image upload 33
6
1 INTRODUCTION
For my internship I chose to work at InGenius Labs, a company based in Perth, Australia.
The reason for choosing a company abroad was that I wanted a different, more challenging
experience in an English speaking environment. Western Australia was convenient for two
reasons; firstly I have spent there over a year before and am quite familiar with it and Perth
in particular, and secondly, I have my aunt living in this city therefore my accommodation
issues were easily solved.
This report is written in English so that my mentor is able to read and evaluate it.
1.1 Perth
Perth lies on the western coast of Australia. With its 1.7million inhabitants it is the largest
city of Western Australia and also its capital. The city is located along the Indian Ocean and
spans nearly 50km.
Western Australia is economically very successful, mostly due to its rich natural resources.
The most important industry is mining (iron, gold, nickel and natural gas) and associated
sectors. Wheat is the number one agricultural product, and recently service sector has
developed significantly. The company I worked for represents one of them.
1.2 InGenius Labs
InGenius Labs is a small company based in Perth. The owner is Stuart Kidd, who was also
my mentor. The company has a small team of designers and developers who create
applications for mobile devices, mostly iPhone, iPad and Android. Their clients are
companies and individuals working in different areas, so the products of InGenius Labs
range from applications for supporting working processes in mining to games for children
with autism. Occasionally they also create websites which are mostly used for presenting
and advertising applications.
Some of their products, mostly those I have worked on, are mentioned in the following
chapters of this report.
7
2 INTERNSHIP
2.1 Working environment and tasks
I worked mostly in the company’s office, or occasionally, when my mentor was out of
office, I also worked from home. For my work I used my own laptop. Work instructions
were given to me over email or in person. When I communicated with other developers we
used email or Skype.
Although my orientation is Android applications, the majority of my tasks were web
oriented. I created a bigger website, and a few smaller ones for application advertising
purposes. Two of the projects required work with mobile phone developers, since a website
was used only as a web service. On one occasion I had to make an evaluation of three
websites which were due to be moved. The client who owns them did not have access to
their source code and needed estimated costs for the eventual move.
I also attended a three-day conference organised by Media 140 in topics related with mobile
and social issues of contemporary businesses with my mentor as one of the presenters.
Mr. Kidd monitored and evaluated my work and made necessary comments which I used for
improvement. I also received feedback from clients who ordered the product.
After I had completed my internship and returned from Australia, I kept contacts with my
mentor and some of the clients to continue and finalise some work.
In the next chapter tools and technologies I have used will be described.
2.2 Tools
I have used most of the tools I employed for the work with InGenius Labs before I started
my internship. However, there is always room for improvement. During my internship I
enhanced my programming skills. I got some insight into running a small business, from
establishing contacts with potential clients and communicating with them, to team work with
other developers. On top of that, I improved my English language skills.
Here is a brief description of the tools and the way I used them.
2.2.1 NetBeans
Figure 1: NetBeans logo
8
NetBeans is a multi-language IDE (Integrated development environment). With its PHP
support it helps you develop with a nice interface and warns you about syntax errors. I have
used it for website development. I have occasionally worked on more than one project at the
same time, and that is where project groups helped a lot, since I could easily switch between
projects.
2.2.2 EasyPHP
Figure 2: EasyPHP logo
EasyPHP is a software package for PHP developers on Windows. It contains Apache server,
PHP, MySQL, phpMyAdmin and many more features. It is preconfigured, so you can use all
of its functions immediately after installation.
2.2.3 Kohana PHP framework
Figure 3: Kohana logo
Kohana is a HMVC PHP framework. That means that it is based on Model-View-Controller
design, but is less strict, so Model and View can be accessed without controller. The purpose
of the framework is to create easily readable and more consistent code. It helps you develop
a code, since you do not have to write everything because of its predefined features. It also
has built in security, such as escaping MySQL queries.
For my main project I have used Kohana 3.1.
9
2.2.4 Dropbox
Figure 4: Dropbox logo
Even though it is not a development tool, Dropbox has been an incredible help in sharing
projects, since there were over 12000 files shared.
2.2.5 JQUERY
jQuery is the most popular javascript library. It is very fast and helps programmers create
complex scripts with a minimum effort. It can animate, handle events and use AJAX. There
are many plugins available, making development mostly the matter of copy pasting.
Sample:
$('#mydiv').text('This is text').show("slow");
The code above will set the text of element “mydiv” to “This is text” and slowly display it
(expand it).
2.2.6 JSON
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is a simple
text based notation, which is easily readable by humans and machines. It is natively
supported by some programming languages (such as PHP) and some have written libraries
for it. In comparison to XML it is much smaller, since it contains a minimum amount of data
and is better supported by most programming languages. You can easily save Objects as
well as Arrays and both of them can be nested.
Sample: { "employees": [ { "firstName":"John" , "lastName":"Doe" }, { "firstName":"Anna" , "lastName":"Smith" }, { "firstName":"Peter" , "lastName":"Jones" } ] }
10
This is an Object, containing Array called “employees” which contains Objects with values
of “firstName” and “lastName”.
Because it is so easy to use and is widely spread I have used it in my AJAX requests and for
web services for mobile devices.
2.2.7 Google maps
Two projects required location information. Google maps have a very good support and web
services, so it was a perfect tool for required tasks. I used geocoding API for obtaining an
address from the location and vice versa. I also used Maps for displaying locations.
2.2.8 Piwik
Piwik is an open source traffic analytics. It basically does the same as Google Analytics, but
you host it on your server and have complete access to it. Because of that, I have used it to
create the “most popular” events list for which I required specific data which you cannot get
in any other way. It is very easy to install and use and it made a perfect tool for my task.
Figure 5: Piwik dashboard (piwik.org)
11
3 THE PROJECTS
In the following chapters I will describe some of the products I worked on. Due to relatively
numerous and diverse projects I decided to present some most significant ones. My main
project was Mobile Club Guide, a Website for displaying events all around the world. In the
future mobile application will also be designed therefore a web service has been created.
Only parts of products will be described here and the relevant code.
3.1 Olsen Environment.com.au
Olsen Environment is a company that provides services to mining industry. InGenius Labs
created an iPhone application for them called 'Bionic Balancer', and as part of the contract
also created instructions for use on their website. I have been given all required information
from which I have created an instruction page for the application.
Figure 6: Olsen Environment Instructions
12
I have also been asked to make a vertically scrolling news feed. For the given task I have
used a code found on JSFiddle (http://jsfiddle.net/HxKAJ/21/), which is a javascript/jQuery
code.
Figure 7: Olsen Environment news page
3.2 Envoy Settlement Agency
Envoy Settlement Agency asked for a few corrections on their website which is a static html.
Some employees have changed and the list needed to be updated. Their main request was to
change a quote form, which was a Flash with a PHP backend for email. I have done
minimum changes to backend, but I have replaced Flash form with Html. All design has
been carefully put in CSS, therefore HTML code used is minimal. Here is an example of one
of input boxes:
<div> <label class="l"> Phone number<font color="red">*</font>: </label><p> <input id="phNumber" class="required" type="text" name="phNumber" value="" size="30"> </p> </div>
This code is a part of a form for purchase quote, a very similar form has been created for
sellers quote.
13
Figure 8: Envoy Settlement Agency contact form
3.3 Property Resource
Property Resource is an iPad application for a client. It requires a website as a backend,
which has been created by InGenius Labs. A client has requested a few changes to the
website, mostly smaller text changes which were assigned to me. On one occasion I also had
to change the design, since text change destroyed graphical display of the website. The
changes were mostly in CSS.
14
Figure 9: Property Resource
3.4 Reportable
Reportable is an iPhone and iPad app created to help people make reports with the
government guidelines. My task was to create a simple website for a description of the
application.
Figure 10: The Reportable website
15
3.5 InGenius Labs
A few smaller changes had to be made on the website, mostly adding application
descriptions but also some changes in JavaScript were done.
3.5.1 News
On my company’s website I have been asked to add another section for news. The current
menu did not support another link, so it had to be changed.
Figure 11: InGenius labs menu
3.5.2 Application – Emotion detective
Figure 12: Emotion Detective page
3.5.3 Application – Property Resource
16
Figure 13: Property Resource page
3.6 Backpacker Application
Backpacker Application is an iPhone applicatin for tourists in Australia. Its function is to
help people find different places (later referred to as items). It has 6 categories: Sleep, Food,
Drinks, Cafes, Attractions and Tours. Under each category you can find places with basic
information about them, such as address, phone number, opening times and description.
My job was to make a backend for the application, a web service which would provide
information for mobile device. For this task I used Kohana 3.1, and JSON for
communicating with mobile devices. This is only a backend for a mobile device, therefore
all requests and forms have been created to the liking of an iOS developer.
For the task I have created the following requests
Get comments
Example: getcomments?timestamp=1341389657
Return is an array of all comments, whose timestamp is greater than the one
provided. If timestamp is not provided it is considered to be 0.
Add comment
Example: addcomment
No URL parameters are required, all data is sent via POST.
Get Items
Example: getbackpackeritem?timestamp=1341389657
Return is an array of all items, whose timestamp is greater than the one provided. If
no timestamp is provided it is considered to be 0. Items also contain an array of all
images, which provides URL to image and its thumbnail.
17
Add rating
Example: addrating?item_id=2&rating=4
It accepts two arguments (item ID and rating) vie GET, and returns status success or
error, depending whether rating was successful or whether an error occurred.
For administration, a simple website with the most basic forms has been created. It contains
a list of all items, a form to add and edit items and a form to upload and edit images.
Figure 14: List of items
The form to edit and add items uses Google maps for obtaining location. An address can be
inserted manually, or with the help of Google Maps (address is being fetched from the
location).
19
3.7 Mobile club guide
Mobile club guide is a website and iPhone application for events around the world. My task
was to create a website, as well as web services for mobile devices.
It contains information of artists, events and venues, where events can be separated into
Concerts, Festivals (which includes multiple events), Clubs and Gigs, and even further by its
genre. Here it is described in greater detail, since it was my major project.
3.7.1 Search
There is one search engine for all three main items: events, venues and artists.
Search is being sent via GET parameters, with one parameter called s. (search?s=test).
I wanted the results to be ordered by relevance but I could not use the simple MySQL
expression using LIKE so I had to use MATCH, which also returns a matching value. The
following is a SQL example for events. Kohana database helper only supports functions
which are used by all SQL databases, therefore MATCH is not implemented because it is
MySQL only. This means I had to use hardcoded SQL statements.
$events = DB::query(Database::SELECT, "SELECT name, description, id, 'event' AS type, match(name, description) against ('" . $keyword . "') as rel FROM events WHERE match(name, description) against ('" . $keyword . "') ")->execute()->as_array();
I used a similar SQL expression for artists and venues. Field 'type' has been created to
distinguish between the tables, so we can later on make appropriate URL's. The search
results will be shown as one, so I had to join all three results with the following code.
$result = array_merge($events, $venues, $artists);
Item 'rel' is relevance, which means the higher that number is, the more important it is. To
sort the array by relevance, I used the following code:
function compare_rel($a, $b) { return -strcmp($a['rel'], $b['rel']); } usort($result, 'compare_rel');
The usort function uses quick sort, with the comparing function provided. In this case, I
compare relevance, so it is ordered from the biggest to smallest.
20
Figure 16: Search result
3.7.2 User location
In Venues and Location I show venues and events close to the user’s current location. The
only way to get the user's location is to use GeoIP. There are a few free scripts available,
which you can install on your web server, yet none of them were up to the task because
sometimes they could not locate a town properly. The only other option was to use a web
service, which would provide me with the required data. I have chosen ipinfodb.com for its
precision and speed. The only thing that needs to be done is to make an account because you
have to use an API key to access their service.
Usage is very simple, all you need to provide is a key, ip and define in what format you want
result to be. An example of such url:
http://api.ipinfodb.com/v3/ip-city/?key=<API key>&ip120.145.10.95&format=json
In return I get a JSON containing my location data. This request takes more 100ms, so it
cannot be simply embedded within a PHP code because the website would wait until you
load this data before displaying the website. To solve this problem I created a simple jQuery
call, which would get the required data in the background.
$(function() { $.get('<?php echo Url::base(); ?>geoip'); });
This simple AJAX call triggers PHP script that calls the web service. The following is a web
service response.
21
{ "statusCode": "OK", "statusMessage": "", "ipAddress": "120.145.10.95", "countryCode": "AU", "countryName": "AUSTRALIA", "regionName": "WESTERN AUSTRALIA", "cityName": "PERTH", "zipCode": "-", "latitude": "-31.9333", "longitude": "115.833", "timeZone": "+08:00" }
Most of the information received is up to no use to me, so I extract only countryName,
cityName, latitude and logitude and safely save them as JSON in a cookie.
cookie::set('gloc', json_encode($myloc));
The reason I decided to use a cookie is simple, it is easily usable, and very effective.
The final values in a cookie look like this:
{"city":"PERTH","country":"AUSTRALIA","lat":"-31.9333","lng":"115.833"}
3.7.3 Location
Location by default displays your own city, getting it from the cookie (as described in User
location) unless it is provided in URL (example: location/slovenia/velenje). If a city or a
country cannot be found in the database, it is being requested from Google and asks the user
for confirmation that the town is correct. Google has its own web service and scripts already
created; all you need is to provide the required data as follows:
var geocoder = new google.maps.Geocoder(); //init var address = 'celje, slovenia' geocoder.geocode({ 'address': address }, function (results, status) { //calling web service var lat = results[0].geometry.location.lat(); //getting latitude var lng = results[0].geometry.location.lng(); //getting longitude var city = results[0].address_components[0].long_name; //getting city name
Even Google can make mistakes, so the user has to confirm the location, which is shown on
the map. To do that, we simply create URL using the newly acquired information and
display the map: var mapurl = "http://www.google.com/uds/modules/elements/mapselement/iframe.html?maptype=roadmap&latlng="+lat+","+lng+"&mlatlng="+lat+","+lng+"&zoom=13&mtitle=name&element=true"; $('#gmap').attr('src',mapurl); //setting google map url to the new one
The result can be seen in the following image:
22
Figure 17: Location, adding new city
If the city already exists in the database, it is shown with all its venues . The list below
contains upcoming events in those venues, and if clicked on the ‘pin’, it will open a small
window on the map containing address information and a link to the venue. Each venue has
its own letter, and if all letters have been taken, only dot is used.
23
Figure 18: Location, showing venues and events
3.7.4 Venues
Venues are very similar to Location, except it does not show events. It also works a slightly
differently. When a city cannot be found it does not give you a choice to enter it, but it tells
you to go to location and create it there.
24
Figure 19: Venues when city is unknown
If city is known, it displays a map with all venues and a list.
25
Figure 20: Venues
3.7.5 Event
Events are listed in four groups; concerts, festivals, clubs and gigs. A Festival is basically an
event that holds multiple events. Each event contains the basic information about the
performer, the time, location, ticket cost and a short description. There are also images and
YouTube video. The location address is being fetched from the venue, and so is location for
Google map. By default the map is hidden, and can be easily shown or hidden by clicking on
the link under the address.
26
Figure 21: Event
3.7.6 Venue
Venue is considered to be a place where an event is being held. It can be a club, a concert
hall, a stadium or even a park. It contains all important information such as location
27
(including on a Google map) and description. You can also add images and YouTube video
to it, and all events held there can be easily visible.
Displaying a Google map is actually very simple. Google does most of the work, since in
HTML you only need to put a simple div to show where it should be.
<div class="frame_right" id="map_canvas" style="width:400px;height:300px;margin-left:0px;">
The only thing you need to do is set up settings, define what the zoom should be, center the
coordinates and define type of the map.
var latlng = new google.maps.LatLng(<?php echo $venue['lat']; ?>, <?php echo $venue['lng']; ?>); var options = { zoom: 15, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map($('#map_canvas')[0], options); var latLng = new google.maps.LatLng(<?php echo $venue['lat']; ?>,<?php echo $venue['lng']; ?>); var marker = new google.maps.Marker({ position: latLng, title: '<?php echo $venue['name'] ?>', map: map });
I also inserted a marker in the map so that it shows exactly where the location is. I set ‘Title’
of my marker to venue name. When you click on it, a small window containing the venue
address displays. This has been created with the following code:
var content ='<?php echo Html::chars($venue['name']) ?>'; var address1 = '<?php echo Html::chars($venue['address1']); ?>'; var address2 = '<?php echo Html::chars($venue['address2']); ?>'; content+= '<br />' + address1; content+= ', ' + address2; var infowindow = new google.maps.InfoWindow( { content: content, size: new google.maps.Size(50,50) }); google.maps.event.addListener(marker, 'click', function() { infowindow.open(map,marker);
29
3.7.7 Reports
Website content is being created by its users; therefore some of it might be inappropriate or
incorrect. Administration cannot review every single update, so we rely on users to report
those that break the rules.
A report system has been set up with a “Report” link on every site. When clicking on it a
simple window appears, asking you to provide more details about the problem. Once the
“Report” button is pressed, an AJAX request is being sent to report, and it gives a simple
response.
Figure 23: Report window
Reports can then be viewed in administration and dealt with. Administrator has a choice of
ignoring it, approving or marking it as “in progress”.
Figure 24: List of reports and report view
3.7.8 Most popular
This was one of the very demanding tasks. Getting most popular events on its own is not
very difficult if you save number of visits to each event. The challenge was created by the
30
requirement that it had to be most popular of the last 6 days. In this way we avoid one event
staying on the very top because it was popular at some point. To do this, I had to use
analytics (Piwik) which saves every visit and every view. Unfortunately Piwik does not
provide web services with the information required for this, so I had to go directly to
MySQL and extract data from there. Piwik saves every record to the table
analytics_log_action which contains titles and URL's. Titles have type set to 4, URL's to 1,
so we only need the ones with type 1. Every visit is saved to analytics_log_link_visit_action,
so we link the two tables by id. By using LIKE statements, we only get those url's that
contain /event/<number>, to make sure URL like page/event/edit do not come through. We
only select those that are less than a week old by substracting 6 days from the current date.
Then we order them by number of appearances, so they are in a required order, although
they get mixed up later on. The result is the following SQL statement:
SELECT COUNT( DISTINCT ( llva.idvisitor ) ) AS num, la.name FROM analytics_log_link_visit_action AS llva, analytics_log_action AS la WHERE la.idaction = llva.idaction_url AND la.type = '1' AND (la.name LIKE '%/event/0%' OR la.name LIKE '%/event/1%' OR la.name LIKE '%/event/2%' OR la.name LIKE '%/event/3%' OR la.name LIKE '%/event/4%' OR la.name LIKE '%/event/5%' OR la.name LIKE '%/event/6%' OR la.name LIKE '%/event/7%' OR la.name LIKE '%/event/8%' OR la.name LIKE '%/event/9%') AND llva.server_time >= curdate( ) - INTERVAL DAYOFWEEK( curdate( ) ) +6 DAY GROUP BY la.idaction ORDER BY num DESC LIMIT 5
The results are URL's and are not sufficient. The data required are URL, city, country and
title, so I extract ID using a very simple php code:
foreach ($res as $i => $r) { $tmp = explode('/', $r['name']); $ids[$i] = $tmp[4]; }
To get my missing data I connect the required MySQL tables together and fetch information
using a previously acquired ID's:
DB::select('e.name', 'e.id', array('v.city', 'city'), array('c.name', 'country')) ->from(array('events', 'e')) ->join(array('venues', 'v')) ->on('v.id', '=', 'e.venue_id') ->join(array('countries', 'c')) ->on('c.id', '=', 'v.country_id') ->where('e.id', 'IN', $ids)
31
->execute()->as_array();
I also retreive images for each event but at this point I will not go into details on how I got
them. Unfortunately, when I selected this new data, the order has changed. That having in
mind, I reordered them using the previous array of id's which is correctly ordered:
$out = array(); foreach ($result as $i => $r) { $id = array_search($r['id'], $ids); $out[$id] = $r; }
3.7.9 Editing and creating pages
Every person with a login privilege is allowed to create an event, a venue or an artist. For
that purpose the forms have been created. They are called pages.
Figure 25: Form for creating an event
32
Some fields in forms are connected to other information, already stored in the database, such
as a country in venues, or a venue name in events. To help the user with this, an
autocomplete script has been added.
To do this, I had to use a jQuery autocomplete library, which, after inserting a few
characters, requests similar results from the database using AJAX.
$("#country").autocomplete({ url: '<?php echo Url::base(); ?>search/country?output=json', showResult: function(value, data) { return '<span>' + value + '</span>'; } remoteDataType: 'json' });
The code above calls a PHP script that very simply searches for supplied information and
then encodes it in JSON and prints it out.
$countries = DB::select('name', 'id')->from('countries')->where('name', 'like', $search . '%')->execute(); $result = array(); foreach ($countries as $country) { $result[$country['name']] = $country['id']; } echo json_encode($results);
JSON is picked up by the jQuery and displayed in a list as seen on the image below.
Figure 26: Example of autocomplete
Each event has a starting and finishing date and time, and to help user choose those another
jQuery plugin has been used. The plugin used is called »jQuery Timepicker«, and is an
extension of the official Datepicker script. The usage is very simple, and because data and
time field are separate you also call them separately:
$('#startTime').timepicker({}); $( "#startDate").datepicker({ defaultDate: "+1w", dateFormat: "yy-mm-dd", changeMonth: true, numberOfMonths: 1 });
33
Another thing needed was saving YouTube URL. Inserting a player in the website is very
easy, the code is provided by YouTube:
<iframe width="560" height="315" src="http://www.youtube.com/embed/a-ahy218_FM" frameborder="0" allowfullscreen></iframe>
Unfortunately, there are three different types of URL available (provided by YouTube
website) as seen below:
http://www.youtube.com/embed/a-ahy218_FM http://www.youtube.com/watch?v=a-ahy218_FM http://youtu.be/a-ahy218_FM
Only the first URL can be used in the script, so I had to parse the user's input URL and if it
is not in the correct form, transform it.
$query_string = array(); $result = ""; parse_str(parse_url($fullurl, PHP_URL_QUERY), $query_string); if (isset($query_string["v"])) //#1 { $id = $query_string["v"]; if (strlen($id) > 5) $result = "http://www.youtube.com/embed/" . $id; } else if (preg_match('/http:\/\/[w.]*youtube\.com\/embed\/[^.]+$/', $fullurl)) //#2 $result = $fullurl; else if(preg_match("#(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&\n]+|(?<=v=)[^&\n]+|(?<=youtu.be/)[^&\n]+#", $fullurl, $matches)) //#3 { $result = "http://www.youtube.com/embed/" . $matches[0]; }
In number one only this is being searched for: v=a-ahy218_FM. If that exists, it extracts the
hash (a-ahy218_FM) from it, and creates a valid URL.
Number two checks the whole URL ignoring the hash. If URL is correct it will return true,
and use it as it is in a correct form.
The third one does the URL match similar to the second one, but uses the hash from it to
create valid URL. The final URL which can be used in the script is saved in $result.
3.7.10 Image upload
The website will later be used mostly as a backend for mobile applications. Mobile devices
have a smaller screen and much stricter designs, so images uploaded on the website had to
be limited to a certain ration and size. We have decided for one of the most common of
ratios, that is 4:3. To keep a certain quality we decided to use a »minimum size« condition,
and set it to 1024x768.
Images can belong to an event, a venue or an artist. To keep some kind of an order the
images have been saved under a folder of each page, and in another folder, matching pages
ID.
34
Figure 27: Image folders
To keep the order there were two more folders created, one for thumbnails and another one
for images about to be resized.
When you want to upload an image you just click the »Upload image« link on the image
page. With the help of the »Once click upload« jQuery plugin the image is being
immediately uploaded after you select it.
Figure 28: Uploading image
The image has been automatically saved to images/<page>/<id>/tmp folder and renamed for
search engine optimization and to have a unique name. The first page name is changed to
lower case and then stripped of all spaces and replaced with an underscore. To make sure the
image names are unique PHP provides a simple function called uniqid that gives a unique
hash.
$newfilename = str_replace(" ", "_", strtolower($item['name'])) . '-' . uniqid() . '.' . $ext;
Then it is being shown to the user to resize it. To do the job a jQuery plugin called Jcrop is
used. With a few simple settings the plugin automatically ensures that the resized image is a
4:3 ratio and at least 1024x746 in size.
jQuery('#cropbox').Jcrop({
35
onChange: showPreview, onSelect: updateCoords, aspectRatio: 1.33333, minSize:[ 1024, 80 ], boxWidth: 512 });
The result is a very easy to use interface.
Figure 29: Image cropping
Once your desired image has been selected and you press »Crop image« a simple AJAX
request sends your newly chosen image size.
$.post( "<?php echo Url::base() . 'admin/images/resize' . $di . '/' . $item_id ?>", {w:w,h:h,x:x,y:y,image:img} , function(data) {
36
loadingmessage('', 'hide'); if(data=='success') { location.reload(); } } );
Then the server uses a Kohana created class for manipulating the image. First it crops the
image to selected values and then resizes it for image and thumbnail and saves them in
appropriate folders. The last thing left is to remove the original image because it is no longer
required.
$image = Image::factory($targetPath . '/tmp/' . $imgname); $image->crop($w, $h, $x, $y); $image->resize(1024, 768)->save($targetPath . $imgname); $image->resize(200, 150)->save($targetPath . '/thumbnails/' . $imgname); unlink($targetPath . 'tmp/' . $imgname);
37
4 CONCLUSION
I enjoyed my work in spite of the fact that it was occasionally demanding. Creating and
fixing websites for application promotion has been quite an easy but still interesting job.
Creating web services has been interesting because I worked with mobile platform
developers.
Unlike most of the school work where we worked with computer applications and Android
applications, I have worked with PHP websites. I have learned the technologies prior to the
internship and have now improved my skills.
This internship has been a great experience for me, I not only worked for a company with
experienced developers in a foreign country, but I also had an opportunity to meet client’s
requests and cooperate with other programmers.
I would like to thank Mr. Stuart Kidd for giving me a chance to do my internship in his
company and learn from them, and my aunt Marjana for providing a hospitable
accommodation and company in Perth.
38
5 SOURCES
http://kohanaframework.org/
http://jquery.com/
http://netbeans.org/
http://www.json.org/
http://www.dropbox.com/
http://www.easyphp.org/
https://developers.google.com/maps/
http://docs.jquery.com/UI/Autocomplete
http://piwik.org/
http://deepliquid.com/content/Jcrop.html
http://code.google.com/p/ocupload/