Gallery2:Integration Howto - Gallery Codex
Personal tools

Gallery2:Integration Howto

From Gallery Codex

Introduction

Gallery2 is designed to be easily embedded in other applications. The GalleryEmbed class in embed.php provides APIs to assist in processing G2 requests and keeping sessions, user logins and user/group data in sync between G2 and the embedding application. In this document "embedding application" is shortened to emApp. This document contains instructions for:

  • Embedding G2 in another application using existing integration code.
  • Writing the integration code to embed G2 in another PHP application.

While this article focuses on getting GalleryEmbed::init() call right, you will find the complete embedding & integration documentation at:

Using Existing Integration Code

  1. Install (separately) Gallery 2 and the application in which Gallery 2 will be embedded.
  2. Obtain and install the G2 integration code written specifically for the emApp. This may be a module or plugin if the emApp supports them, or a simple php file.
  3. Follow instructions with the integration code to initially synchronize users and groups. This may be done as part of module/plugin installation or via special php files.
  4. Login to Gallery 2 as a site administrator:
    1. Make sure the registration module is deactivated or not installed.
    2. Set the Gallery 2 session lifetime to at least twice the lifetime of sessions in the emApp. This is because a user may visit Gallery 2 and then continue to use the emApp but not visit Gallery 2 pages. A longer Gallery 2 session timeout will help ensure their session sticks around until they do visit a Gallery 2 page again. Note that if the Gallery 2 session does timeout and the user returns then a new session will be created with the correct user logged in. Other data from the old session is lost but the user login is restored.
  5. Test the integration.
  6. Once everything is working you can choose to disable direct access to Gallery 2 and only allow access via the emApp. To do this set the embedOnly flag in your config.php.


Writing New Integration Code

First install (separately) Gallery 2 and the app in which Gallery 2 will be embedded.

Next you need an entry point in the emApp for all Gallery 2 requests, (similar to main.php in Gallery 2 standalone). This may be a module or plugin if the application supports these, or a plain php file. Determine the URI/path for your access point and the Gallery 2 base directory, relative to your webserver document root. Examples:

Access Point ( = embedUri ) Gallery 2 Base Directory ( = g2Uri )
/appdir/gallery2.php /appdir/gallery2
/appdir/plugins/gallery2.php /appdir/lib/gallery2/
/appdir/index.php?module=gallery2 /gallery2/
/index.php?page=gallery /albums/

You can simply use these paths as the parameters to GalleryEmbed::init($embedUri, $g2Uri);

  • embedUri = absolute URL path from document root + filename (and any query parameters, but NO path) for access point..
  • g2Uri = absolute URL path from document root to the Gallery 2 directory

Never forget the leading '/'! Complete URLs are also allowed, e.g.

Access Point ( = embedUri ) Gallery 2 Base Directory ( = g2Uri )
http://www.example.com/appdir/gallery2.php http://www.example.com/appdir/gallery2/
http://example.com/appdir/plugins/gallery2.php http://example.com/appdir/lib/gallery2/
http://example.com/index.php?module=gallery2 http://photos.example.com/

As you see, Gallery 2 and your the location where Gallery 2 is integrated in your website can be on two different subdomains! You shouldn't use two completely different domains because cookies (whether you are logged in or not) cannot be shared between different domains. But different subdomains is no problem, as long as you change the Gallery 2 cookie.path in site admin -> General appropriately.

You'll also need a URI for a login page or main page of the app; Gallery 2 will redirect here for access attempts without proper permissions.

Examples
/
/appdir/login.php

The code in the access point to handle a Gallery 2 request looks something like this:

require_once(dirname(__FILE__) . 'relative/path/to/gallery2/embed.php');
$ret = GalleryEmbed::init(array( 'embedUri' => {value}, 'g2Uri' => {value}, 'loginRedirect' => {value}, 'activeUserId' => {value}));
if ($ret) {
  // $ret->getAsHtml() has error details..
  exit;
} 
$g2data = GalleryEmbed::handleRequest(); 
if ($g2data['isDone']) {
  exit; // Gallery 2 has already sent output (redirect or binary data)
} 
// Use $g2data['headHtml'] and $g2data['bodyHtml']
// to display Gallery 2 content inside embedding application
// if you don't want to use $g2data['headHtml'] directly, you can get the css,
// javascript and page title separately by calling...
if (isset($g2moddata['headHtml'])) {
  list($title, $css, $javascript) = GalleryEmbed::parseHead($g2moddata['headHtml']);
}

The 'activeUserId' value passed to init() enables session synchronization by making sure the active user in Gallery 2 matches the emApp user. The value is the active emApp user id. Pass in an empty string for anonymous/guest user (NOT the user id of the emApp's anonymous user if it has an id). To complete session sync add a hook/callback/event-handler for the logout operation in the emApp:

require_once(dirname(__FILE__) . 'relative/path/to/gallery2/embed.php');
$ret = GalleryEmbed::logout();

This hook is not required, but it resets the Gallery 2 session at logout so a session for a logged-in user isn't left on the server.

Next decide if you want to support cookieless browsing. Some extra steps are required if Gallery 2 can't count on cookies to track its session id. The emApp must be able to provide a key=value string for its own session key and id, and have an available API to store additional data in the session. Here are the extra steps:

1. The input array for the GalleryEmbed::init() call must also contain:

'embedSessionString' => {key=value}, 'gallerySessionId' => {value}

(omit gallerySessionId when the value is not yet known) 2. After the init() call:

$gallerySessionId = GalleryEmbed::getSessionId(); // {store value in emApp's session}

Other optional tasks:

1. Prior to the handleRequest() call set GalleryCapabilities. Check modules/core/classes/GalleryCapabilities.class for available settings; also see the settings made by default in GalleryEmbed::init(). Example:

GalleryCapabilities::set('showSidebar', false);

2. Check for 'sidebarHtml' in content returned from handleRequest(). If the example GalleryCapabilities setting shown above is used then handleRequest() may return 'sidebarHtml' (when a core.ShowItem page is being viewed). You can include this content in a block on the emApp sidebar.

Next add hooks to keep users in sync between Gallery 2 and the emApp. The code in each case will look like this:

require_once(dirname(__FILE__) . 'relative/path/to/gallery2/embed.php');
$ret = GalleryEmbed::init();
if ($ret) {
  // $ret->getAsHtml() has error details..
}
// Call GalleryEmbed as required..
// ..
$ret = GalleryEmbed::done();
if ($ret->isError()) {
  // $ret->getAsHtml() has error details..
}

You'll need hooks to call GalleryEmbed::createUser(), ::updateUser() and ::deleteUser() for user creation, updates and deletes, respectively. There may be two create hooks if the emApp supports both new user registration and an admin function to create new users directly.

If the emApp supports user groups then add hooks to keep groups in sync. Synchronizing groups is optional, even if the emApp supports groups. The process is the same as above, using GalleryEmbed::createGroup, ::updateGroup, ::deleteGroup(), ::addUserToGroup() and ::removeUserFromGroup(). Note that Gallery 2 does not support nested groups. If the emApp does then the hooks will have to expand the groups into the list of users and update the Gallery 2 groups accordingly.

Compatibility Issues

  • Database: Some integrations might require that both applications use the same database (just with different table prefix) because for such integrations, the same database connection is used by both applications
  • session.use_trans_sid is turned off by G2 when you include embed.php. So if your application relies on session.use_trans_sid (which slows down PHP), you'll have to make sure that it is enabled again before session_start() is called

New (Gallery 2.1) Specs for GalleryEmbed::init()

$ret = GalleryEmbed::init($arguments);

  • $arguments is an associative array
  • $ret is a GalleryStatus object

Arguments

  • activeUserId string/mixed - emApp user Id of the active user (empty string for anonymous/guest user)
  • embedUri string - URI to access G2 via CMS application. Base URL (internally it's called baseUri) of all embedded G2 requests. Protocol and host name are optional. Examples: /index.php?module=gallery2, /portal/index.php?module=gallery2, /, http://www.example.com/index.php?module=gallery2, www.example.com/portal/index.php?module=gallery2
  • g2Uri string - URI of the G2 standalone location. Path from docroot to the directory main.php is located. Protocol / host name are both optional. Examples: /gallery2/, /sub/gallery2/, http://photos.example.com/, www.example.com/photos/main.php,
  • loginRedirect string - URI for redirect to emApp login view (example: /emApp/index.php)
  • embedSessionString string - (optional) To support cookieless browsing, pass in key=value for emApp session key and session id value to be added as query parameter in urls
  • gallerySessionId string - (optional) To support cookieless browsing, pass in G2 session id (when cookies not in use, CMS must track this value between requests)
  • activeLanguage string - (optional) language code in use for this session. Format: {LANG}_{COUNTRY}, ISO language and ISO country code (e.g. en_US)
  • fullInit' => boolean - (optional) call GalleryInitSecondPass (only use when not calling handleRequest). Defaults to false.
  • apiVersion => array (int major, int minor) - (optional but recommended) specify to check if your integration is compatible with the Embed API

Specified Behavior

  • embedUri affects all URLs generated by G2 but the static content (css files, java applet files, theme images) plus the core.DownloadItem URLs.
    • If not specified, G2 generates URLs based on the current REQUEST_URI and its default baseFile 'main.php'. If the rewrite module is active, URLs are generated based on the stored embeddedLocation.
    • If specified and full URL including host string, G2 generates URLs that start with '{PROTOCOL}://{HOST}/{embedUri}'. {PROTOCOL} and {HOST} are parsed from embedUri. {PROTOCOL} defaults to 'http', if accessed via https it's 'https'.
    • If specified and starting with '/', URLs are generated using the auto-detected {PROTOCOL} and {HOST} values
    • NOTE: Everything between the first '/' (first after the protocol http://) and the last '/' will be interpreted as embedPath (important for short URLs, since short URLs will all have embedPath as the base for URLs that have a short URL pendant and other URLs will start with the whole embedUri).
  • g2Uri affects all URLs generated by G2 that go directly to standalone G2 even when G2 is embedded. That is: core.DownloadItem and all static content (see above).
    • If not specified, G2 generates URLs based on the current REQUEST_URI and its default baseFile 'main.php' (unless embedUri is specified, then URLs are generated based on embedUri)
    • If specified and path-only (starts with '/'), G2 generates URLs that start with '{PROTOCOL}://{HOST}/{g2Path}'.
    • If specified and hostname/path (does not start with '/'), G2 generates URLs that start with '{PROTOCOL}://{g2Path}'. Useful if G2 and emApp are on different subdomains. The auto-detected {PROTOCOL} can also be overriden if specified.
  • fullInit affects the active user of G2. It defaults to false.
    • If not specified, you can only call GalleryEmbed::handleRequest() after GalleryEmbed::init(); If you do not specifiy fullInit = true and call any other method of GalleryCoreApi or GalleryEmbed, you will likely get errors.
    • If set to true, G2 is fully initiated (set the active user based on the current session) and you can call any GalleryCoreApi or GalleryEmbed method after GalleryEmbed::init().
  • activeUserId affects the active user of G2 for the session
    • If omitted, G2 uses the session ID from the cookie (or from the GALLERYSID HTTP GET argument if it exists) and loads the corresponding session data / activeUser later in ::handleRequest / fullInit)
    • If specified, G2 compares the activeUserId with the activeUserId from the session (cookie / GET argument).
      • If activeUserId == externalId from session: Nothing is changed.
      • Else If activeUserId == : The session / active user is reset, activeUser = guest
      • else (If activeUserId != externalId from session): The G2 user that is mapped to externalId = activeUserId is set as the active user for the session and for the request
      • NOTE: If activeUserId is set but not yet registered / mapped to G2 userId, GalleryEmbed::init() will return an ERROR_MISSING_OBJECT
      • NOTE: The active language of the existing session is preserved even when the session is reset / changed to another user
  • activeLanguage affects the active language of the session and of the request
    • If omitted, then the active language of the existing session is unchanged. If it's a new session, the language will default to G2's default language or to the language preference of the corresponding G2 user, if set
    • If specified, G2 will check for an exact language code match for {ll}_{CC} whereas {ll} stands for the 2 letter lower-case ÎSO language code and {CC} for the 2 letter capital-case ISO country code. And it will fallback to the default {ll}_?? translation if available and else use the site default language.
  • loginRedirect affects the URL of the login link in G2
    • If omitted, G2's login link will still point to G2's login form, thus a user would not be automatically logged in into the emApp
    • If specified, G2's login link points to the given URL thus ensuring that all users login through the emApp
    • NOTE: Whether a login link is shown or not depends on GalleryCapabilities::set('login', true|false); which is set to true (show login link) in G2 standalone and is set to false in GalleryEmbed::init(); You can change it back to true after the GalleryEmbed::init() call if you want.
  • embedSessionString affects cookie-less browsing (keeping the session ID of the emApp in all G2 URLs)
    • If omitted, G2 will not actively support cookie-less browsing
    • If specified, G2 will append the embedSessionString (string format {NAME}={VALUE}, {NAME} = URL GET argument that should be appended to all G2 generated URLs, {VALUE} it's value (session id)) too all URLs generated by G2. Thus preserving the emApp session id in the URL
      • NOTE: Usually you would specify embedSessionString only if the emApp detected that the user agent doesn't accept cookies since embedSessionString only makes URLs longer and uglier and most users accept cookies anyway.
  • gallerySessionId affects cookie-less browsing (keeping the G2 session ID in the emApp session)
    • If omitted, G2 will lose the session when a user browses from embedded G2 to another page in the emApp and back to embedded G2, if the user agent doesn't accept cookies
    • If specified, G2 doesn't lose the session of the active user even for cookie-less browsing
      • NOTE: Usually you would store the G2 session ID in the emApp's session and specify the gallerySessionId if the emApp detected cookie-less browsing. In your emApp wrapper, you can get the G2 session ID with sessionId = GalleryUtilities::getRequestVariables(SESSION_ID_PARAMETER); after including modules/core/classes/GallerySession.class and GalleryUtilities.class.
  • apiVersion is the Embed API version that your integration is compatible with. If specified, Gallery checks your API version against the current Embed API version and an error ERROR_PLUGIN_VERSION_MISMATCH is returned if your integration is not compatible. It is highly recommended to specify this parameter.

Requests for Comment

  • g2Uri and embedUri are now the only URL / path related parameters and accept a wide range of formats: from full URLs (example: http://www.example.com/portal/index.php?module=gallery2) to just index.php. This is only possible by requiring some strict rules:
    • gallery2, gallery2/ and /gallery2 would all be treated as host or file and not as path. If you want to specify a path, then it must be enclosed by '/'. The only valid value in this case would be /gallery2/. gallery2/ would be parsed as host = gallery2, path = /. gallery2 and /gallery2 would be interpreted as path = / and file = gallery2.
    • On the other hand, it's easy to obey this rule. Still, what do you think?
  • Should we split embedUri / g2Uri into mandatory embedPath + embedUri, g2Path and optional embedProtocol, embedHost, g2Protocol, g2Host? Internally, we make this distinction in g2 anyway. Would it be easier for integration writers to deal with g2Path which has always the same format and those integrations that also want to support different subdomains can put the G2 host string into g2Host? We could then treat g2Path = gallery2, gallery2/, /gallery2 and /gallery2/ all the same way, i.e. if you forget to add a leading / traling slash, it would still work. 90% of all one-time GalleryEmbed users would only need g2Path and embedPath + embedUri. The question is: is this concept of split up embedUri + embedPath too confusing? We could still have this approach and merge embedUri and embedPath into a single embedUri and still be quite tolerant to missing leading '/'.
  • Don't forget to add documentation about cookie domain / path when using different subdomains for G2 and emApp. Maybe there should be convienience methods in GalleryEmbed to set the cookie parameters.


Changing integration code from Gallery 2.0 - 2.0.2 to Gallery 2.1 compatible integration code

The parameters for GalleryEmbed::init have been changed in Gallery 2.1 because the old parameters were overcomplicated, more complicated than they needed to be.

  • G2 has to generate URLs, even when it is embedded
  • G2 generates URLs that point to the embedded G2, so all requests must go through the emApp or the wrapper file
    • Therefore, G2 needs the base URL that all URLs have in common. E.g. if embedded G2 is accessed with http://www.example.com/portal/index.php?module=gallery2, then all URLs that G2 generates must begin with this base URL.
    • The http://www.example.com/ part is already given, the PHP variable $_SERVER[HTTP_HOST] holds that value
    • We still need to know portal/index.php?module=gallery2 . This justifies embedUri
  • G2 also generates URLs that point directly to G2 and not to the embedded G2. E.g. for static content (css files, theme images, java applets (.jar files) and last but not least: core.DownloadItem requests. Since G2 has an image firewall, all image downloads must be authorized by the application. Since we have +/- 12 thumbnail image downloads per album page, these requests must be super lightweight. We can not afford booting up the emApp just to forward the request to G2 which then does a lightweight request. Thus, DownloadItem requests go directly to G2 and not through emApp.
    • Therefore, G2 needs to know the base URL of G2 standalone, e.g. http://www.example.com/gallery2/
    • The host part is already known so we just need /gallery2/ . Since usually G2 and the emApp are on the same subdomain, we could also just ask for the relative path from the emApp to G2. This justifies relativeG2Path
  • Finally, we would like to show the imageblock on arbitrary emApp pages. E.g. in news articles or blog entries. Sample URL of such a news article: http://www.example.com/portal/index.php?module=news?aid=15. We now have to generate a DownloadItem URL (pointing directly to G2) and a ShowItem URL (pointing to the embedded G2) for the embedded imageblock on the news article page.
    • Until now, we had only the relativeG2Path and the embedUri, thus we had to parse the current request URL ($_SERVER['REQUEST_URI']) to find out the G2 location. Thus we introduced embedPath. For the given example, embedPath is '/portal/' and embedUri was changed to 'index.php?module=gallery2'.
  • G2 short URLs (rewrite URL) also needs to know 'embedPath' and g2Path (the path to G2). That can be configured once and stored in the database. It could also be provided on each request.

The actual change

Replace relativeG2Path requirement with absolute g2Uri

Reason for introduction of g2Uri:

  • embedPath and g2Uri would then be absolute (consistency)
  • absolute paths are less confusing than relative paths
  • enables new feature: G2 and emApp on different subdomains (see below)
  • (if no short urls are used,) we could again merge embedUri and embedPath into a single parameter (embedUri)

Format of g2Uri: /path/ OR HOST_STRING/path/ the string before the first slash is interpreted as the host of the G2 installation and the string after the first slash is the path (you can also include the http:// bit and it is parsed correctly).

  • HOST_STRING is optional. If none specified, we use $_SERVER[HTTP_HOST] to build our URLs that point to G2 directly
  • Therefore, most users will have g2Uri = '/gallery2/' or something like that.
  • Example: if G2 is installed at http://www.example.com/gallery2/ then g2Uri is '/gallery2/'
  • Example: if G2 is at the same place and emApp is on http://portal.example.com/ (notice the different subdomain), then g2Uri would be 'www.example.com/gallery2/' or just 'http://www.example.com/gallery2/'

Remove embedPath and merge it into embedUri

Replace / merge embedUri and embedPath into a single parameter called embedUri

  • In G2, we somehow need to find the embedPath. It could either be given as a parameter or we can parse it from the current REQUEST_URI
  • If we had old-style (winter 2004/05) embedUri which includes also the embedPath, we could parse for the last slash to find the embedPath
    • Example: embedUri = '/portal/index.php?module=gallery2' then we would parse for the last '/' and find '/portal/'
  • But would that be more confusing than asking for embedUri and embedPath separately? Especially since we have at this point g2Path which has the same pattern as the current embedPath.
  • What about short URLs? Short URLs are still configured once and don't need any other input. But we introduced a feature a while back, that the current embedPath can override the stored embeddedLocation (the embedPath that was stored at rewrite module configuration time). We introduced this to allow accessing rewrite enabled embedded G2 from multiple vHosts. Would that still be possible if just embedUri was given? We could still parse for the last '/' in embedUri to get embedPath. But embedUri is likely to be in short URL format too, e.g. embedUri = '/portal/gallery2/'. Thus embedPath = embedUri in this special case (example), baseFile would be and it should be fine. Can't think of a case where we'd have problems.