PHP

You are currently browsing articles tagged PHP.

Me and Sandaruwan wanted to create a Facebook app, so just to learn the process I spent an hour or two to create a simple “Hello World” like app. I wanted to share the experience (a walk through / tutorial). It was pretty easy with the example code Facebook provides, and their developer forum.

Here is the link to my Hello World app http://apps.facebook.com/xvpj_hello/. You can download the source code here.

First install get the developer app: http://www.facebook.com/developers/. Then you can create a new application by clicking Set Up New Application.

Then under My Applications you can see a link to view example code.

Clicking it will show you an example index.php (which we are going to use) and a link to download the Facebook Platform PHP library. Download it and extract the folder php in the archive in your server (you need to host this app somewhere – you cannot test it on localhost).

I extracted it on www-root/fb/; i.e. an ls should look like

Note that index.php and invite.php are added later (it’s our code :) )

Then you need to goto Edit Settings in My Applications window

There under Canvas set the Canvas Callback URL to where you hosted the app. In my case it is http://xvpj.net/fb/. (note the ‘/‘ at the end, this is required otherwise there’ll be an error when navigating to the invite page). Also I set the render method to FBML.

Now to the good part, time to code :) . Here’s what my index.php looks like. Note that the link to invite.php includes a parameter invite. This is a small trick so that when user skips sending invitations, there is no parameter invite and the page is redirected back to index.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
 
require_once 'facebook.php';
 
$appapikey = 'API_KEY';
$appsecret = 'SECRET';
 
$facebook = new Facebook($appapikey, $appsecret);
$facebook->require_frame();
$user_id = $facebook->require_login();
 
/* Greeting */
echo "<p>Hello, <fb:name uid=\"$user_id\" useyou=\"false\" />!</p>";
 
/* Get the list of friends */
$friends = $facebook->api_client->friends_get();
 
/* A link ot invite friends to the application */
echo "<p><a href=\"invite.php?invite\">Invite Friends</a></p>";
 
/* Printing out the friend list */
echo "<h2>Your friends</h2>";
 
foreach ($friends as $friend) {
  echo "<p><fb:name uid=\"$friend\" /></p>";
}

This is the invitation page I used (invite.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
require_once 'facebook.php';
 
$appapikey = 'API_KEY';
$appsecret = 'SECRET';
 
$facebook = new Facebook($appapikey, $appsecret);
$facebook->require_frame();
$user_id = $facebook->require_login();
 
/* If invitations were sent */
if(isset($_POST["ids"])) {
?>
<center>
  Thank you for inviting <? echo sizeof($_POST["ids"]); ?> of your friends to <b><a href="http://apps.facebook.com/xvpj_hello/">Hello World</a></b>.
</center>
<br /><br />
<?php
}
/* If invite page is to be displayed */
else if(isset($_GET["invite"])) {
  /* A facebook query to select the friends of the current user who use the application */
  $fql = 'SELECT uid FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1='.$user_id.') AND is_app_user = 1';
 
  /* Execute the query */
  $_friends = $facebook->api_client->fql_query($fql);
 
  /* Get the user ids */
  $friends = array();
  if (is_array($_friends) && count($_friends)) {
    foreach ($_friends as $friend) {
      $friends[] = $friend['uid'];
    }
  }
 
  /* Convert the array of friends into a comma-delimeted string. */
  $friends = implode(',', $friends);
 
  /* Prepare the invitation text that all invited users will receive. */
  $content = "<fb:name uid=\"".$user_id."\" /> has invited you to use <a href=\"http://apps.facebook.com/xvpj_hello/\">Hello World</a>!\n";
  $content .= "<fb:req-choice url=\"".$facebook->get_add_url()."\" label=\"Add Hello World to your profile\"/>";
 
  /* This creates the form to select and invite friends.
   * The multi-friend-selector lets you search and select friends */
?>
  <fb:request-form action="invite.php" method="post" type="Hello World" content="<? echo htmlentities($content); ?>">
    <fb:multi-friend-selector actiontext="These poor lads still don't use this great app. Invite em all ;)" exclude_ids="<? echo $friends; ?>" />
  </fb:request-form>
<?
}
/* If sending invitations was skipped */
else {
?>
<fb:redirect url="http://apps.facebook.com/xvpj_hello/" />
<?
}
?>

Note: substitute API_KEY and SECRET

Tags: , , ,

I previously discussed how to use extension api for PHP here. To illustrate the use of it, I will discuss how it can be implemented on exif and mbstring extensions. (Exif depends on mbstring and uses functions php_mb_check_encoding_list and php_mb_convert_encoding)

As also mentioned in the previous blog post, you can find the details about the status of the project here. The source code is available at the git repository : git://github.com/vpj/PHP-Extension-API.git, and some sample test code which uses the interface : git://github.com/vpj/PHP_EXT_API_Tests.git

How to register APIs – mbstring

You should create a structure with the API functions.

1
2
3
4
static struct {
	int (*check_encoding_list)(const char * TSRMLS_DC);
	char * (*convert_encoding)(const char *, size_t, const char *, const char *, size_t * TSRMLS_DC);
} mbstring_eapi = {php_mb_check_encoding_list, php_mb_convert_encoding};

I used a global variable for this.

Then, you should register the API during module initialization. That is, following piece of code should be included in MINIT.

1
zend_eapi_register("mbstring", "1.0", (void *)&mbstring_eapi, sizeof(mbstring_eapi));

Registering the API is pretty simple, but there might be some issues when using it in exif.

Setting up callback function – exif

First we should define the structure of the API.

1
2
3
4
5
6
typedef struct {
	int (*check_encoding_list)(const char * TSRMLS_DC);
	char * (*convert_encoding)(const char *, size_t, const char *, const char *, size_t * TSRMLS_DC);
} mbstring_eapi_struct;
 
static mbstring_eapi_struct *mbstring_eapi;

Here’s the callback function.

1
2
3
4
5
6
7
8
EAPI_CALLBACK_FUNCTION(mbstring_eapi_callback)
{
	TSRMLS_FETCH();
	mbstring_eapi = pemalloc(sizeof(mbstring_eapi_struct), 1);
 
	*mbstring_eapi = *((mbstring_eapi_struct*)api);
	REGISTER_INI_ENTRIES();
}

The callback function is named mbstring_eapi_callback. We are calling REGISTER_INI_ENTRIES from the callback, since OnUpdate event handlers for INI entries use check_encoding_list function. If INIs were registered from MINIT the event handlers will be executed before the extension api callback, so we are delaying the INI registration. Since REGISTER_INI_ENTRIES require TRSMLS we fetch those threading information using TSRMLS_FETCH() at the begining of the callback function.

The callback should be registered in MINIT.

1
2
EAPI_SET_CALLBACK("mbstring", "1.0", mbstring_eapi_callback);
mbstring_eapi = NULL;

We are left with changing the mbstring function calls. I’ll include the changed code in OnUpdateEncode; rest is similar.

1
2
3
4
5
6
7
8
9
10
11
ZEND_INI_MH(OnUpdateEncode)
{
	if(mbstring_eapi)
	{
		if (new_value && strlen(new_value) && !mbstring_eapi->check_encoding_list(new_value TSRMLS_CC)) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Illegal encoding ignored: '%s'", new_value);
			return FAILURE;
		}
	}
	return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}

Tags: , , ,

This is a short tutorial on how to use the PHP: Abstract Extension API and Dependency Interface.

You can find details about he status of the project here. The source code is available at the git repository : git://github.com/vpj/PHP-Extension-API.git, and some sample code which uses the interface : git://github.com/vpj/PHP_EXT_API_Tests.git

How to register APIs

You should create a structure with the API functions.

1
2
3
4
5
6
struct _SAMPLE_EXT_API {
	int (*add)(int, int);
	int (*multiply)(int, int);
};
 
typedef struct _SAMPLE_EXT_API SAMPLE_EXT_API;

Then you should register the API during module initialization

1
zend_eapi_register("calculator", "1.0.0.0", (void *)&ext, sizeof(ext));

calculator is the name of the extension and 1.0.0.0 is the version in the major.minor[.build[.revision]] format. It is possible to register multiple APIs if there are multiple versions, to support backward compatibility. For example:

1
2
    zend_eapi_register("calculator", "1.0", (void *)&ext_old, sizeof(ext_old));
    zend_eapi_register("calculator", "1.1", (void *)&ext_new, sizeof(ext_new));

Getting the required APIs

APIs could be retrieved using a callback function or using zend_ext_api_get. Callbacks are called after module initialization but before RINIT. Callbacks should be used when the dependent extension requires some extension during module initialization. APIs cannot be retrieved during MINIT, since it will depend on the order in which APIs are registered. Therefore, the dependent extension could set up the callback function during MINIT and it will be called once all extensions are initialized.

Here’s an example of a callback function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct _SAMPLE_EXT_API {
	int (*add)(int, int);
	int (*multiply)(int, int);
} SAMPLE_EXT_API;
 
void my_callback(void *p_api, char *ext_name, uint version)
{
	char *version_text;
	SAMPLE_EXT_API *api = (SAMPLE_EXT_API *)p_api;
 
	zend_eapi_version_toa(version, &version_text);
	php_printf("API Callback: %s - %d\n", ext_name, version_text);
	php_printf("\tsum(243, 34) = %d\n", api->sum(243, 34));
}

Callback should be registered in MINIT

1
zend_eapi_set_callback("calculator", "1.0.0.0", my_callback);

Tags: , , ,