Php on the Web and Desktop


Published on

PHP-GTK talk from Zendcon 2009

Published in: Technology
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • How many people have ever heard “the desktop is dead, everything is online”There have been several recent articles about itEveryone is touting their RIA application that “works like a desktop”If the desktop is dead, and everything is going to be online, why do you keep hearing about this RIA thing?
  • So what they’re really saying is – web apps that want to act like desktop appsEverybody wants the connection of the internet, but the user experience of a desktop applicationSo how do we join the two?
  • Name a webservice you use all the time ( I better hear twitter)Can use straight REST, SOAP, xml-rpc (ugh), plus other variants
  • So how do we take these three things – an application that wants to be on the desktop, not just the web, webservices we hit with http, and PHP which “talks http” fabulously?
  • Contrary to popular belief, people still work offlineEmbedded OS’s have major issues with memory and bandwidth and websites not working properly with themWho here has had issues with IE ever?And then there’s issues with AIR or silverlight or titanium… they just don’t quite work yet
  • There are lots of advantages to using PHP to write a desktop app
  • Speed is the big reason to pick C or something similar – stacked against ruby or python though, that’s the only advantage ;)The code protection, runtime distribution, etc only let’s you win over C or similar languages, not against python or ruby or other $flavor of the dayNote that runtime distribution is going to differ from platform to platformIt’s 13MB for EVERYTHING for windows – php, php-gtk, all the gtk libraries even esoteric stuff, and one or two localizationsMac has a new runtime that doesn’t require X – which is awesome
  • GTK was Gimp Tool Kit (long long ago)Php-gtk is really php-gtk2 – but php-gtk1 only works on php4 which is dead, so it in esscense is dead as well (good riddance)Your computer does not care about HTML.Your shell does not care about HTML.PHP does not care about HTML.Because of all of this, you should not care about HTML.PHP and GTK does not use HTML.PHP and GTK does not build web pages.PHP and GTK does not build web applications.PHP and GTK builds computer programs.- From bob MajdakThere are other options, but right now none work as well or are as complete as php-gtkPHP-QTWxWidgetsWin\\GuiWinbinder
  • Do not change the users desired colors and theme unless absolutely necessary and make sure there are ways for the use rto control the changes the OS is handling theming for a reasonYou can’tbe certain users have the sametheme as you, gtkcan have anynumber of themes and look manydifferentwaysThere ishowever, nothingwrongwithofferingusers options – perhaps an option to makeiteasier to use on embeddeddevices, withfingerwidthscrollbars and otherusefultools
  • It’s trivial to add a webservice for your database, and much safer then allowing access across the network to the dbRemember you can do multiple CLI binaries on a system – one just for php-gtk is fine
  • We already have a class to manage caching data in an sqlite3 DB via PDO, and a class to manage talking to the Twitter API – reusing code is greatYou can use any PHP code with php-gtk – from Zend Framework to anything else you want
  • Widgets – think legos, each with a specific shape and specific jobThere are a LOT of gtk widgets, and some “widgets” that aren’t widgets…Brief note about two types of windows – a gtkwindow (the actual widget window) and gdkwindow (what the widget is drawing in)
  • The contained widgets are container's children.Containers usually respond to resize events and addition and removal of children by reallocating the available space among its remaining children.
  • In computer programming, event-driven programming or event-based programming is a programming paradigm in which the flow of the program is determined by events—i.e., sensor outputs or user actions (mouse clicks, key presses) or messages from other programs or threads.Signals are identified by nameMention “events’ as well and bubbling and signal emission order
  • Different style of programming
  • TODO: get the installers done and in place, linux installer of bobs
  • Encrypting settings isn’t going to gain you much, although you can do it if you are really paranoidWhere is the “user defined location”APPDATA for windows and HOME for most other systems (in $_SERVER)There are also some other “special location” – on windows you can get to these through some com tricks
  • These are the window widgets – there are also gdk windows – those are the areas where the underlying system actually draws onto – they’re both called windows just to confuse the hell out of you
  • Creating a splash screen means creating a window, hinting it as a splashscreen, telling it not to have edges or taskbar or resize, then taking an image and rendering it as the background – the mask stuff means that it can be a transparent png or the like and have a custom shape
  • Stuff to know
  • Using what we just talked aboutLet’s start with a basicgtk window – notice it’s easier to extend the base classConnect the destruction of our main window with stopping theConcepts – signals and connections, the main loop and main_quit, show allNotice if you put PHP after the main(); call it will not be executed until after the main_quit call
  • Gtkbuilder is preferred, and it’s built in – glade is old and busted – but the editor (glade3) is the same for both, just change the output you want
  • There are more than 50 widgets, and those widgets have thousands of signals and methods…GTK is HUGE and learning the cool stuff available might take awhile (remember when you started learning PHP?)
  • The full code shows how to create the status icon and other fun stuff
  • My own simple twitter class – login, logout, public timeline, own friends timeline, send message Concepts – use PHP code with PHP-GTK, can use other extensions but then they have to be installed
  • So to show something in a treeview, you create a datastore, stuff in the data, then create a treeview, hook it to the model – then create renderers for each type of data you want to show, put the renderer(s) in a column, and put the column in a treeview (deep breath)
  • So to show something in a treeview, you create a datastore, stuff in the data, then create a treeview, hook it to the model – then create renderers for each type of data you want to show, put the renderer(s) in a column, and put the column in a treeview (deep breath)
  • First version of the app with the public timeline
  • So to show something in a treeview, you create a datastore, stuff in the data, then create a treeview, hook it to the model – then create renderers for each type of data you want to show, put the renderer(s) in a column, and put the column in a treeview (deep breath)
  • Concepts: packing and toolbarsMore gtktimeout
  • General concept of dialogs – when is a good time for modal dialogs, when is not a good time
  • Concepts: packing and toolbarsMore gtktimeout
  • Concepts: packing and toolbarsMore gtktimeout
  • Add data in with a gtkentry
  • Concepts: packing and toolbarsMore gtktimeout
  • Here’s the finished app – then I’ll run it in action
  • Places to get more information and recruit!!
  • Php on the Web and Desktop

    1. 1. PHP on the Web and Desktop Webservices and PHP-GTK
    2. 2. Whoami•• Work at• PHP-GTK• PECL cairo• WinGui• Bad bad bad things to PHP (on windows)• Twitter @auroraeosrose• IRC auroraeosrose
    3. 3. Community Heckling• On twitter #zendcon• Bonus points if you start tweeting with the app• IRC is open, I can see backlog – constructive criticism is good• Comment on• No comments on hair, clothes, or my fat belly – constructive criticism is welcome ;)
    4. 4. The Desktop Is Dead?• If the desktop is dead… what is this browser thing you use everyday?• What is really happening?• RIA? WTF is RIA?
    5. 5. RIA Rich Internet Applicationsweb applications that have most of the characteristics of desktop applications, typically delivered by way of standards based web browser plug-ins or independently via sandboxes or virtual machines (wikipedia)
    6. 6. Webservices• API’s you can talk to using HTTP• Extend the power of the web anywhere and everywhere
    7. 7. PHP• Ability to talk HTTP natively (streams) or with several extensions (pecl_http and curl)• Lots of code already written for common problems involving web
    8. 8. PHP-GTK• Cross platform widget toolkit for desktop programs• Native look and feel for all platforms – this includes Windows and Mac• Reuse all the code you already have for your models
    9. 9. Why the desktop?• People aren’t always online• Some things would be bandwidth prohibitive• Some data is too sensitive• Embedded OSs have issues• Browsers are just Quirky• Current Desktop RIA tools are still young
    10. 10. Why use PHP• No new language to learn• No Compiling• Instant Changes• Plug into PHP extensions• Easy to Use• Fast to Write• Use existing code
    11. 11. Disadvantages• Slower than compiled code• Distribution of runtime – New installers help with that• Distribution of code – Phar helps with that• Code “protection” – Can use encoders but anyone with enough effort could decode
    12. 12. What is PHP-GTK• Language bindings for GTK+ – Cross platform widgeting toolkit, if you use gnome you use it• Multiple “backends” – speaks Windows, Mac OSX and X server• Needs php CLI, php-gtk extension, and gtk libraries to run
    13. 13. Installing•• Windows has Binaries• Compile it yourself – Some distros do bad things to PHP, you may get errors
    14. 14. Some points to remember1. In CLI applications, memory is more important than speed2. Clean up after yourself, unset is your friend3. The OS is handling theming. Unlike html, where the design is controlled by you. If you manipulate themes, users WILL be irritated.
    15. 15. Some points to remember4. Do not connect directly to a database on another machine. This is asking for security issues. Instead slap a webservice in front of the database for your app.5. Use 5.3 The memory savings you’ll get will make it worth the hassle of having a special CLI binary just for PHP-GTK
    16. 16. GTK Theory• Twitter is the new “Hello World”• Use pre-existing twitter API class for talking to twitter via PHP streams• See how much work we saved? We just write the pretty front-end
    17. 17. Widgets• A building block for GUIs – Window – Button – Menu• "True" widgets descend from GtkWidget• Some widgets have their own window• Some widgets draw on the window beneath them instead
    18. 18. Containers• Specialized widget, holds other widgets• Can nest containers inside containers• GTK+ does not do pixel perfect or fixed positioning, instead it uses packing• Packing defines the size of the widgets
    19. 19. Signals• Event driven, not line by line• Emits "signals" that have a default handler and can have other callbacks attached• Different widgets can have the same signal with a different meaning
    20. 20. Main Loop• No code will run after calling Gtk::main() until you call Gtk::main_quit()• The loop sits around until something happens that emits a signal or event• Long running script as opposed to quick set up and tear down
    21. 21. On to Code••
    22. 22. A note on settings• Store settings in user defined location• Xml or ini files are good formats, can also use sqlite for lots of settings• Limited by user permissions for reading and writing
    23. 23. Windows – the GTK kind• Usually you have one main window• You can create pretty splash screens if desired• Windows can be grouped, and can be either a parent or transient for another window
    24. 24. SplashScreen Example<?php$window = new GtkWindow();$window->set_resizable(false);$window->set_decorated(false);$window->set_skip_taskbar_hint(true);$window->set_skip_pager_hint(true);$window->set_type_hint(Gdk::WINDOW_TYPE_HINT_SPLASHSCREEN);$pixbuf = GdkPixbuf::new_from_file($image);list($pixmap, $mask) = $pixbuf->render_pixmap_and_mask();list($width, $height) = $pixmap->get_size();$window->set_app_paintable(true);$window->set_size_request($width, $height);$window->realize();if($mask instanceof GdkPixmap) { $window->shape_combine_mask($mask, 0, 0);}$window->window->set_back_pixmap($pixmap, false);
    25. 25. Create our Main Window• If we close it, the program ends• Can set pretty icons for the corner and stuff a single widget inside• You can’t see any widgets until you show them
    26. 26. <?phpclass Php_Gtk_Twitter_Client extends GtkWindow { public function __construct() { parent::__construct(); $this->set_icon($this->render_icon( Gtk::STOCK_ABOUT, Gtk::ICON_SIZE_DIALOG)); $this->set_size_request(300, 500); $this->set_title(PHP-GTK Twitter Client); $this->connect_simple(destroy, array(Gtk, main_quit)); }}$window = new Php_Gtk_Twitter_Client;$window->show_all();Gtk::main();
    27. 27. A word on Glade/Gtkbuilder • Design your layouts in an editor (glade3) • Save them as xml files • Load them via special methods in PHP-GTK • Automatically generated widgets
    28. 28. Specialty Widgets and Events• Events are lower level things that happen• You can attach to events like you attach to signals• Lots of specialty widgets to do fancy stuff, from infobars to aboutdialogs to statusicons – and that’s not counting extensions
    29. 29. Minimize to the Tray• Attach to the minimize event (this is not as easy as it looks)• Attach to the activate event• Make them act differently then they normally would
    30. 30. <?php public function activate_window($icon, $window) { if ($window->is_visible()) { $window->hide(); } else { $window->deiconify(); $window->show(); } }$this->statusicon->connect(activate, array($this->statusicon, activate_window), $this);$this->set_skip_taskbar_hint(true);$this->connect(window-state-event, array($this, minimize_to_tray));public function minimize_to_tray($window, $event) { if ($event- >changed_mask == Gdk::WINDOW_STATE_ICONIFIED && $event- >new_window_state & Gdk::WINDOW_STATE_ICONIFIED) { $window->hide(); } return true; //stop bubbling }
    31. 31. • I really don’t believe in wheel inventing , especially when I have little experience with the subject. However there is an issue – every existing twitter API uses curl – and I don’t want to depend on an extension that isn’t always installed protected function process($url, $date = 0, $type = GET, $data = null) { // add caching header $this->headers[0] = If-Modified-Since: . date(DATE_RFC822, $date); $options = array( http => array( method => $type, header => $this->headers) ); if (!is_null($data)) { $options[http][content] = http_build_query($data); } $context = stream_context_create($options); if ($this->username && $this->password) { $base = http:// . urlencode($this->username) . : . urlencode($this->password) .; } else { $base =; } set_error_handler(array($this,swallow_error)); $string = file_get_contents($base . $url, false, $context); restore_error_handler(); return json_decode($string); }
    32. 32. TreeView Madness• You will use lots of treeviews• Treeviews work with two components, a view and model• TextViews work in a similar manner• TreeViews have columns with renderers
    33. 33. $store = new GtkListStore(GdkPixbuf::gtype, Gobject::TYPE_STRING, Gobject::TYPE_STRING, Gobject::TYPE_LONG, GObject::TYPE_STRING, GObject::TYPE_BOOLEAN, GObject::TYPE_STRING, Gobject::TYPE_LONG); $store->set_sort_column_id(7, Gtk::SORT_DESCENDING); $list = $this->twitter->get_public_timeline(); // stuff the store foreach($list as $object) { $store->append(array(null, $object->user->profile_image_url, $object->user->name, $object->user->id, $object->text, $object->favorited, $object->created_at, $object->id)); } $this->treeview = new GtkTreeView($store); $picture_renderer = new GtkCellRendererPixbuf(); $picture_column = new GtkTreeViewColumn(Picture, $picture_renderer, pixbuf, 0); $picture_column->set_cell_data_func($picture_renderer, array($this, show_user)); $this->treeview->append_column($picture_column);$message_renderer = new GtkCellRendererText(); $message_renderer->set_property(wrap-mode, Gtk::WRAP_WORD); $message_renderer->set_property(wrap-width, 200); $message_renderer->set_property(width, 10); $message_column = new GtkTreeViewColumn(Message, $message_renderer); $message_column->set_cell_data_func($message_renderer, array($this, message_markup)); $this->treeview->append_column($message_column); $this->treeview->set_resize_mode(Gtk::RESIZE_IMMEDIATE);
    34. 34. Formatting Callbackspublic function show_user($column, $cell, $store, $position) { $pic = $store->get_value($position, 1); $name = $this->temp . md5($pic); if (isset($this->pic_queue[$name])) { return; } elseif (isset($this->pic_cached[$name])) { $store = $this->treeview->get_model(); if (is_null($store->get_value($position, 0))) { $pixbuf = GdkPixbuf::new_from_file($name . .jpg); $store->set($position, 0, $pixbuf); $cell->set_property(pixbuf, $pixbuf); } return; } $this->pic_queue[$name] = array(name => $name, url => $pic, pos => $position, cell => $cell); if (empty($this->load_images_timeout)) { $this->load_images_timeout = Gtk::timeout_add(500, array($this, pic_queue)); } } public function message_markup($column, $cell, $store, $position) { $user = utf8_decode($store->get_value($position, 2)); $message = utf8_decode($store->get_value($position, 4)); $time = $this->distance($store->get_value($position, 6)); $message = htmlspecialchars_decode($message, ENT_QUOTES); $message = str_replace(array(@ . $user, &nbsp;, &), array(<span foreground="#FF6633">@ . $user . </span>, , &amp;), $message); $cell->set_property(markup, "<b>$user</b>:n$messagen<small>$time</small>"); }
    35. 35. Packing Fun• GTK is not “pixel perfect”• Packing is not as hard as it looks• Containers can hold one or many• Remember that a container expands to the size of it’s contents
    36. 36. $vbox = new GtkVBox();$this->add($vbox);$vbox->pack_start($tb, false, false);$vbox->pack_start($scrolled);$vbox->pack_start($this->statusbar, false, false);
    37. 37. Dialogs• Dialogs are cool• Dialogs are usually modal, but not always• Dialogs can be very general or very specific• You can put anything inside one
    38. 38. class Php_Gtk_Twitter_Login_Dialog extends GtkDialog { protected $emailentry; protected $passwordentry; public function __construct($parent) { parent::__construct(Login to Twitter, $parent, Gtk::DIALOG_MODAL, array( Gtk::STOCK_OK, Gtk::RESPONSE_OK, Gtk::STOCK_CANCEL, Gtk::RESPONSE_CANCEL)); $table = new GtkTable(); $email = new GtkLabel(Email:); $table->attach($email, 0, 1, 0, 1); $password = new GtkLabel(Password:); $table->attach($password, 0, 1, 1, 2); $this->emailentry = new GtkEntry(); $table->attach($this->emailentry, 1, 2, 0, 1); $this->passwordentry = new GtkEntry(); $table->attach($this->passwordentry, 1, 2, 1, 2); $this->passwordentry->set_visibility(false); $this->vbox->add($table); $this->errorlabel = new GtkLabel(); $this->vbox->add($this->errorlabel); $this->show_all(); } public function check_login($twitter) { $this->errorlabel->set_text(); $email = $this->emailentry->get_text(); $password = $this->passwordentry->get_text(); if (empty($password) || empty($password)) { $this->errorlabel->set_markup( <span color="red">Name and Password must be entered</span>); return false; } if ($twitter->login($email, $password)) { return true; } else { $this->errorlabel->set_markup( <span color="red">Authentication Error</span>); return false; } } }
    39. 39. if (!empty($this->load_images_timeout)) { Gtk::timeout_remove($this->load_images_timeout); $readd = true;}Gtk::timeout_remove($this->public_timeline_timeout);
    40. 40. Entering Data• GTKEntry• Basic Data Entry – activates on return, can set maximum length allowed• Simple label for messages – could use a dialog or other method of informing the user
    41. 41. // Create an update area $this->updateentry = new GtkEntry(); $this->updateentry->set_max_length(140); $this->updateentry->set_sensitive(false); $this->updateentry->connect(activate, array($this, send_update)); $this->entrystatus = new GtkLabel();public function send_update($entry) { if ($this->twitter->send($entry->get_text())) { $this->entrystatus->set_text(Message Sent); $this->update_timeline(); $this->updateentry->set_text(); } else { $this->entrystatus-> set_markup(‘<span color="red">Error Sending Message - Try Again</span>); }}
    42. 42. Resources• Slides •• Code •• GTK docs • • • • • • THANKS