[add-on] Subscribing a user via HTTP

3rd party code for phpList

Would you like to see an API for PHPlist?

Yes
51
86%
No
1
2%
Unsure what you mean by 'API'
7
12%
 
Total votes : 59

Re: [add-on] Subscribing a user via HTTP

Postby aheath » 1:56am, Mon 07 Jun, 2010

I am very interested in this. I have a requirement to do exactly what has been described in this article. From a Windows machine, running an in-house developed database, automatically update PHPLIST membership when a bulk email check box is ticked or unticked, or when the email address is changed.

Does anyone know whether the corresponding LCUnsub and LCChangeAddress was ever written? Or, has the functionality been built in to PHPList itself now? I have spent the best part of a week changing things around to migrate from Mailman to PHPList so that I can "work around" rate limiting rules put in place by my web hosting company recently. This is the one missing piece in the puzzle.

Any help would be greatly appreciated.
aheath
phpList newbie
 
Posts: 1
Joined: 1:48am, Mon 07 Jun, 2010

Re: [add-on] Subscribing a user via HTTP

Postby thehunmonkgroup » 8:01am, Thu 12 Jan, 2012

Major upgrade to the original posted code is attached:
  • Integrated suggestion for subscribing to multiple lists.
  • Basic test to validate that the subscribe request was successful. It's ugly, but it's the best possible given no API.
  • Code is now separated between two files, sensitive settings have been moved to a file that will not be directly visible via the webserver.
  • Simple debugging facility with a setting to turn it on/off.
  • Output from the script is now JSON, allowing for machine consumption.
  • htmlemail and makeconfirmed are now passed as query params, making them optional settings per call.
  • Cleaned up and clarified a lot of the documentation.
  • Major cleanup/refactoring of the code. I'm sure it could use even more polish, but I wish the rest of PHPList looked this good. ;)
  • Code tested and working with PHPList version 2.11.6 -- guessing it will work with a lot of older versions as well.
I tried uploading attachments to this post, but getting no love, so I guess I'll just post the two files here inline.

MAIN SCRIPT:

Code: Select all
<?php

/* subscribe_service.php --

Purpose: Remote List Control via HTTP, subscribe function
Original Author: Rich Cowan, 8/8/05
Modified by: Jesse Heap 1/3/2006
Modified by: Chad Phillips 1/11/2012


Details:
With PHPList installed this procedure can be use to
subscribe a user using the HTTP command.  The procedure works
by simulating a POST to the default subscribe page.  It requires
the CURL PHP library.


USAGE:

(Here we assume script password is "letmein")

Command:
http://mydomain.com/lists/subscribe_service.php?password=letmein&email=johndoe%40aol.com

Result:
This will subscribe John Doe to the default email list; note that the
'@' sign has been replaced here by %40 which is needed by most web servers.

Command:
http://mydomain.com/lists/subscribe_service.php?password=letmein&email=johndoe%40aol.com&attribute1=John&attribute2=Doe&attribute3=TX

Result:
This will subscribe John Doe to the email list, but also add
user data for him, namely John's first name, last name, and
state, which must be set up as phplist attributes for List #2

NOTES:

The following special parameters can also be passed:
  - htmlemail=1 : Format the list emails using HTML instead of plain text.
  - makeconfirmed=1 : Confirm user immediately, bypassing confirmation email.
  - list_ids=1,2,N : Subscribe to lists other than the default list. Pass a
                     comma separated list of list IDs.

By default, debugging is disabled, if the functionality is not working, you
can enable it to get more helpful output.

The script returns JSON to the caller.

This script is a pretty bad hack, but given that there's no usable API in
PHPList to subscribe users, it's a decent tool.  Unfortunately, there's no
good way to get feedback on the success of the cURL calls, so it's a bit of a
send and pray...  ;)


INSTALLATION AND CONFIGURATION:

1. Copy this script to the home directory of PHPList (the lists folder), and
   make sure that your webserver settings allow access to the file -- in the
   default PHPList setup, you'll need to edit the allowed list of top-level PHP
   files in the .htaccess file (located in the lists folder) to include this
   script, eg:

     <FilesMatch "(index.php|dl.php|ut.php|lt.php|download.php|subscribe_service.php)$">

2. Copy the subscribe_service_settings.inc file to the home directory of
   PHPList. Make sure your webserver settings deny access to this file. In the
   default PHPList setup on Apache, no change should be necessary.

3. Add the following line to the end of the 'Thank you page' setting for your
   subscribe page:

     <div style="display:none">###subscribe_success###</div>

   This is necessary for validating that the subscription request was
   successful.

4. Edit any necessary settings in the CONFIGURATION SETTINGS section below.

5. Edit any necessary settings in the subscribe_service_settings.inc file.

*/


// CONFIGURATION SETTINGS.
// The site-specific settings for this script are located in the file
// referenced by the require statement below -- see the file for directions
// on how to configure this script for your site. They are placed in a separate
// file for security -- should the PHP parsing engine fail, the settings will
// not be exposed to end users.
require_once "./subscribe_service_settings.inc";

// The string to search for when verifying that the subscribe thank you page
// was returned on subscription. This is a poor verification method, but the
// best we can do given that there's no subscription API.
define('SUBSCRIBE_SUCCESS_STRING', ">###subscribe_success###<");

// CODE

/**
 * Simple debug logger.
 */
function debug_log($message) {
  if (DEBUG) {
    print("$message<br />");
  }
}

function json_output($code, $message) {
  header('Content-type: application/json');
  $output = array(
    "result" => array(
      "result_num" => $code,
      "result_text" => $message,
    ),
  );
  print(json_encode($output));
}

/**
 * Make sure script password matches.
 */
function validate_access($params) {
  if (empty($params['password'])) {
    $message = "Access password not supplied.";
    debug_log($message);
    json_output(1, $message);
    exit(0);
  }
  if (SCRIPT_PASSWORD != $params['password']) {
    $message = "Access password incorrect.";
    debug_log($message);
    json_output(1, $message);
    exit(0);
  }
  debug_log("Access password correct.");
  return TRUE;
}

/**
 * Convert query parameters into subscribe post data.
 */
function process_query_params($params) {
  $list_ids = !empty($params['list_ids']) ? $params['list_ids'] : DEFAULT_LIST;
  // Remove list_ids parameter, handled separately.
  unset($params['list_ids']);
  // Remove password parameter, not needed for POST.
  unset($params['password']);
  $post_data = array();
  foreach ($params as $key => $value) {
    // Set each GET value pair to the post_data associative array in
    // preperation for the POST.
    $post_data[urldecode($key)] = urldecode($value);
  }
  // Multiple list IDs can be passed in a comma separated string.
  $list_ids_array = explode(",", $list_ids);
  foreach ($list_ids_array as $list_id) {
    $post_data["list[$list_id]"] = "signup";
    $post_data["listname[$list_id]"] = "list[$list_id]";
  }
  return $post_data;
}

/**
 * Ensure email is provided.
 */
function validate_email($post_data) {
  if (empty($post_data['email'])) {
    $message = "You must supply an email address";
    debug_log($message);
    json_output(1, $message);
    exit(0);
  }
  debug_log("Email validated");
  return TRUE;
}

/**
 * Login to phplist as admin and save cookie using CURLOPT_COOKIEFILE.
 */
function admin_login(&$ch) {
  $url = DOMAIN . "admin/?";
  $login_data = array(
    "login" => PHPLIST_ADMIN_USERNAME,
    "password" => PHPLIST_ADMIN_PASSWORD,
  );
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $login_data);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  // Enable Cookie Parser.  File does not need to exist.
  // http://curl.netmirror.org/libcurl/c/libcurl-tutorial.html for more info.
  curl_setopt($ch, CURLOPT_COOKIEFILE, "/tmp/nofileneeded.txt");
  $result = curl_exec($ch);
  debug_log("Admin login result was: " . htmlentities($result));
}

/**
 * Simulate post to subscriber form.
 */
function post_subscribe(&$ch, $post_data) {
  $post_data["emailconfirm"] = $post_data['email'];
  $post_data["subscribe"] = "Subscribe";
  debug_log("Post data: " . var_export($post_data, TRUE));
  $url = DOMAIN . "?p=subscribe";
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  $result = curl_exec($ch);
  debug_log("Subscribe result was:" . htmlentities($result));
  if (strpos($result, SUBSCRIBE_SUCCESS_STRING) !== FALSE) {
    $message = "User subscribe request successful";
    $result = 0;
  }
  else {
    $message = "User subscribe request failed";
    $result = 1;
  }
  debug_log($message);
  json_output($result, $message);
}

// Parse query params.
parse_str($_SERVER['QUERY_STRING'], $params);
debug_log("Parsed params: " . var_export($params, TRUE));

if (validate_access($params)) {
  $post_data = process_query_params($params);
  if (validate_email($post_data)) {
    $ch = curl_init();
    admin_login($ch);
    post_subscribe($ch, $post_data);
    curl_close($ch);
  }
}


SETTINGS:

Code: Select all
<?php

/* subscribe_service_settings.inc --

Purpose: Remote List Control via HTTP, settings
Original Author: Chad Phillips 1/11/2012

Details:
Controls the site-specific settings for the subscribe_service.php script.

INSTALLATION AND CONFIGURATION:

Copy this script to the home directory of phplist, the lists folder.

To configure, just replace the values below for settings with the
location of your PHPList installation, and a working admin password
for this installation.

IMPORTANT NOTE:

Exposing these settings can compromise the security of your list, therefore
you should ensure that this file is not directly visible to the outside world.
In the default PHPList installation, the .htaccess settings in the lists
directory should handle this for you.

*/

// The PHPList site to send subscriptions to.
define('DOMAIN', "http://mydomain.com/");
// Admin username for the PHPList site.
define('PHPLIST_ADMIN_USERNAME', "admin");
// Admin password for the PHPList site.
define('PHPLIST_ADMIN_PASSWORD', "phplist");
// The list ID to subscribe a user to by default, if no other is provided.
define('DEFAULT_LIST', 1);
// Simple access control for the script. Callers must send this in their
// request in the 'password' query parameter.
define('SCRIPT_PASSWORD', "letmein");
// If set to TRUE, prints extra debugging information.
define('DEBUG', FALSE);


Enjoy.
Last edited by thehunmonkgroup on 8:02am, Fri 13 Jan, 2012, edited 1 time in total.
thehunmonkgroup
phpList newbie
 
Posts: 4
Joined: 3:03am, Thu 12 Jan, 2012

Re: [add-on] Subscribing a user via HTTP

Postby thehunmonkgroup » 8:31am, Thu 12 Jan, 2012

hm. passing the makeconfirmed param in 2.10.17 doesn't seem to work. if i figure out why at some point i'll post a fix.

UPDATE: false alarm, the posted script works fine. this problem i noted was caused by having an incorrect password for the admin user in the settings file, after fixing that all features work in 2.10.17.
thehunmonkgroup
phpList newbie
 
Posts: 4
Joined: 3:03am, Thu 12 Jan, 2012

Re: [add-on] Subscribing a user via HTTP

Postby gls » 7:52pm, Mon 20 Feb, 2012

Thank you very much for this code. Works great!

Is it possible to create code for unsubscribing too, please?
gls
phpLister
 
Posts: 6
Joined: 7:48pm, Mon 20 Feb, 2012

Re: [add-on] Subscribing a user via HTTP

Postby thehunmonkgroup » 8:05pm, Mon 20 Feb, 2012

gls wrote:Is it possible to create code for unsubscribing too, please?


Not without a paycheck attached, this was my volunteer work. ;)
thehunmonkgroup
phpList newbie
 
Posts: 4
Joined: 3:03am, Thu 12 Jan, 2012

Re: [add-on] Subscribing a user via HTTP

Postby thehunmonkgroup » 7:08am, Wed 22 Feb, 2012

Updated main script. I needed to have the option of a response in JSONP format, so now a query arg of the form '_jsonp_callback=[name]' can be passed to use JSONP. [name] should be the name of the function to wrap the JSON in.

MAIN SCRIPT:
Code: Select all
<?php

/* subscribe_service.php --

Purpose: Remote List Control via HTTP, subscribe function
Original Author: Rich Cowan, 8/8/05
Modified by: Jesse Heap 1/3/2006
Modified by: Chad Phillips 1/11/2012


Details:
With PHPList installed this procedure can be use to
subscribe a user using the HTTP command.  The procedure works
by simulating a POST to the default subscribe page.  It requires
the CURL PHP library.


USAGE:

(Here we assume script password is "letmein")

Command:
http://mydomain.com/lists/subscribe_service.php?password=letmein&email=johndoe%40aol.com

Result:
This will subscribe John Doe to the default email list; note that the
'@' sign has been replaced here by %40 which is needed by most web servers.

Command:
http://mydomain.com/lists/subscribe_service.php?password=letmein&email=johndoe%40aol.com&attribute1=John&attribute2=Doe&attribute3=TX

Result:
This will subscribe John Doe to the email list, but also add
user data for him, namely John's first name, last name, and
state, which must be set up as phplist attributes for List #2

NOTES:

The following special parameters can also be passed:
  - htmlemail=1 : Format the list emails using HTML instead of plain text.
  - makeconfirmed=1 : Confirm user immediately, bypassing confirmation email.
  - list_ids=1,2,N : Subscribe to lists other than the default list. Pass a
                     comma separated list of list IDs.
  - _jsonp_callback=[name] : Use this to send the response in JSONP format,
                             [name] is the function to wrap the JSON response
                             in.

By default, debugging is disabled, if the functionality is not working, you
can enable it to get more helpful output.

The script returns JSON to the caller.

This script is a pretty bad hack, but given that there's no usable API in
PHPList to subscribe users, it's a decent tool.  Unfortunately, there's no
good way to get feedback on the success of the cURL calls, so it's a bit of a
send and pray...  ;)


INSTALLATION AND CONFIGURATION:

1. Copy this script to the home directory of PHPList (the lists folder), and
   make sure that your webserver settings allow access to the file -- in the
   default PHPList setup, you'll need to edit the allowed list of top-level PHP
   files in the .htaccess file (located in the lists folder) to include this
   script, eg:

     <FilesMatch "(index.php|dl.php|ut.php|lt.php|download.php|subscribe_service.php)$">

2. Copy the subscribe_service_settings.inc file to the home directory of
   PHPList. Make sure your webserver settings deny access to this file. In the
   default PHPList setup on Apache, no change should be necessary.

3. Add the following line to the end of the 'Thank you page' setting for your
   subscribe page:

     <div style="display:none">###subscribe_success###</div>

   This is necessary for validating that the subscription request was
   successful.

4. Edit any necessary settings in the CONFIGURATION SETTINGS section below.

5. Edit any necessary settings in the subscribe_service_settings.inc file.

*/


// CONFIGURATION SETTINGS.
// The site-specific settings for this script are located in the file
// referenced by the require statement below -- see the file for directions
// on how to configure this script for your site. They are placed in a separate
// file for security -- should the PHP parsing engine fail, the settings will
// not be exposed to end users.
require_once "./subscribe_service_settings.inc";

// The string to search for when verifying that the subscribe thank you page
// was returned on subscription. This is a poor verification method, but the
// best we can do given that there's no subscription API.
define('SUBSCRIBE_SUCCESS_STRING', ">###subscribe_success###<");

// CODE

/**
 * Simple debug logger.
 */
function debug_log($message) {
  if (DEBUG) {
    print("$message<br />");
  }
}

function json_output($code, $message, $params = array()) {
  $data = array(
    "result" => array(
      "result_num" => $code,
      "result_text" => $message,
    ),
  );
  $json = json_encode($data);
  if (!empty($params['_jsonp_callback'])) {
    $callback = $params['_jsonp_callback'];
    header('Content-type: text/javascript');
    $json = "$callback($json)";
  }
  else {
    header('Content-type: application/json');
  }
  print($json);
}

/**
 * Make sure script password matches.
 */
function validate_access($params) {
  if (empty($params['password'])) {
    $message = "Access password not supplied.";
    debug_log($message);
    json_output(1, $message, $params);
    exit(0);
  }
  if (SCRIPT_PASSWORD != $params['password']) {
    $message = "Access password incorrect.";
    debug_log($message);
    json_output(1, $message, $params);
    exit(0);
  }
  debug_log("Access password correct.");
  return TRUE;
}

/**
 * Convert query parameters into subscribe post data.
 */
function process_query_params($params) {
  $list_ids = !empty($params['list_ids']) ? $params['list_ids'] : DEFAULT_LIST;
  // Remove list_ids parameter, handled separately.
  unset($params['list_ids']);
  // Remove password parameter, not needed for POST.
  unset($params['password']);
  $post_data = array();
  foreach ($params as $key => $value) {
    // Set each GET value pair to the post_data associative array in
    // preperation for the POST.
    $post_data[urldecode($key)] = urldecode($value);
  }
  // Multiple list IDs can be passed in a comma separated string.
  $list_ids_array = explode(",", $list_ids);
  foreach ($list_ids_array as $list_id) {
    $post_data["list[$list_id]"] = "signup";
    $post_data["listname[$list_id]"] = "list[$list_id]";
  }
  return $post_data;
}

/**
 * Ensure email is provided.
 */
function validate_email($post_data) {
  if (empty($post_data['email'])) {
    $message = "You must supply an email address";
    debug_log($message);
    json_output(1, $message, $post_data);
    exit(0);
  }
  debug_log("Email validated");
  return TRUE;
}

/**
 * Login to phplist as admin and save cookie using CURLOPT_COOKIEFILE.
 */
function admin_login(&$ch) {
  $url = DOMAIN . "admin/?";
  $login_data = array(
    "login" => PHPLIST_ADMIN_USERNAME,
    "password" => PHPLIST_ADMIN_PASSWORD,
  );
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $login_data);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  // Enable Cookie Parser.  File does not need to exist.
  // http://curl.netmirror.org/libcurl/c/libcurl-tutorial.html for more info.
  curl_setopt($ch, CURLOPT_COOKIEFILE, "/tmp/nofileneeded.txt");
  $result = curl_exec($ch);
  debug_log("Admin login result was: " . htmlentities($result));
}

/**
 * Simulate post to subscriber form.
 */
function post_subscribe(&$ch, $post_data) {
  $post_data["emailconfirm"] = $post_data['email'];
  $post_data["subscribe"] = "Subscribe";
  debug_log("Post data: " . var_export($post_data, TRUE));
  $url = DOMAIN . "?p=subscribe";
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  $result = curl_exec($ch);
  debug_log("Subscribe result was:" . htmlentities($result));
  if (strpos($result, SUBSCRIBE_SUCCESS_STRING) !== FALSE) {
    $message = "User subscribe request successful";
    $result = 0;
  }
  else {
    $message = "User subscribe request failed";
    $result = 1;
  }
  debug_log($message);
  json_output($result, $message, $post_data);
}

// Parse query params.
parse_str($_SERVER['QUERY_STRING'], $params);
debug_log("Parsed params: " . var_export($params, TRUE));

if (validate_access($params)) {
  $post_data = process_query_params($params);
  if (validate_email($post_data)) {
    $ch = curl_init();
    admin_login($ch);
    post_subscribe($ch, $post_data);
    curl_close($ch);
  }
}
thehunmonkgroup
phpList newbie
 
Posts: 4
Joined: 3:03am, Thu 12 Jan, 2012

Re: [add-on] Subscribing a user via HTTP

Postby mebuzzme » 3:19pm, Thu 03 May, 2012

I have been trying to use this script with attributes, the subscription works, email, list ids, etc is saved, however the attribute is not saved.
http://... subscribe_service.php?password=kiosk&email=test16%40yahoo.com&htmlemail=1&makeconfirmed=1&list_ids=27&attribute1=John

Does this look correct? Debug says...

Parsed params: array ( 'password' => 'kiosk', 'email' => 'test18@yahoo.com', 'htmlemail' => '1', 'makeconfirmed' => '1', 'list_ids' => '27', 'attribute1' => 'John', )
Access password correct.
Email validated
User subscribe request successful

Warning: Cannot modify header information - headers already sent by (output started at ... /public_html/lists/subscribe_service.php:105) in .../public_html/lists/subscribe_service.php on line 110
{"result":{"result_num":0,"result_text":"User subscribe request successful"}}
mebuzzme
phpList newbie
 
Posts: 3
Joined: 9:45pm, Mon 28 Apr, 2008

Re: [add-on] Subscribing a user via HTTP

Postby GordonGecko » 3:29pm, Wed 06 Jun, 2012

Check if your subscribe form has the attributes activated that you want saved. The only way I got the attributes to save via the subscription form (?p=subscribe) was to edit the page on the admin side to "Check this box to use this attribute in the page" for each attribute. If there's another way, I'd love to know :wink:
GordonGecko
phpList newbie
 
Posts: 1
Joined: 3:23pm, Wed 06 Jun, 2012

Re: [add-on] Subscribing a user via HTTP

Postby RikkieD » 10:19am, Mon 08 Apr, 2013

I can't get this script to work.

Call: http://..../lists/subscribe_service.php ... onfirmed=1

Result:
Code: Select all
Parsed params: array ( 'password' => 'letmein', 'email' => 'johndoe@aol.com', 'htmlemail' => '1', 'makeconfirmed' => '1', )
Access password correct.
Email validated


That's all...no other messages and the user is not added to the list.

Any suggestions?
RikkieD
phpList newbie
 
Posts: 1
Joined: 10:12am, Mon 08 Apr, 2013

Re: [add-on] Subscribing a user via HTTP

Postby iiv7 » 12:03am, Tue 25 Feb, 2014

Would someone kindly post an example of what the HTTP request code looks like?

I can get the subscribe_service script to work exactly right through the address bar, but it doesn't respond to a cURL request. :p At least I'm not smart enough to get it to.

I have a custom user registration form in a Joomla site, and I'd like to post the email from the form in my install of PHP List.

Many thanks for any help I can get!

Best Regards,
Jonathan
iiv7
phpLister
 
Posts: 6
Joined: 1:48pm, Sun 23 Feb, 2014

Re: [add-on] Subscribing a user via HTTP

Postby KyleHarrison » 7:03pm, Fri 18 Jul, 2014

So i got the API to work, was pretty simple, and immesnely helpful of course :)

I had to make a small alteration, nothing big, but I stashed the fileset on a public github GIST https://gist.github.com/DJDarkViper/244 ... d9f73d3321 so the latest version can always be found, forked, edited, and shared.

Cheers!
KyleHarrison
phpList newbie
 
Posts: 3
Joined: 9:54pm, Thu 17 Jul, 2014

Re: [add-on] Subscribing a user via HTTP

Postby abylon » 5:01pm, Thu 18 Dec, 2014

Hi,
the submitting of a new email address with the script works fine. The recipient will receive the corresponding e-mail notification.

My problem is that after calling the URL

Code: Select all
http://www.mysite.de/nl2/lists/subscribe_service.php?password=xxxxxxxx&email=test%40gmx.de&htmlemail=1&list_ids=2&attribute1=test&attribute2=3"


The page "subscribe_service.php" display the code
Code: Select all
"{" result ": {" result_num ": 0," result_text ":" User subscribe request successful "}}"


Should it not redirected to the "Thankyoupage" directly?

It's also inconvenient if the HTML link is shown in plain text in the browser.

Does anyone have any idea what I'm doing wrong?

Could it have something to do with the "JSONP". This functionality I did not understand.

Best regards
tom
abylon
phpList newbie
 
Posts: 3
Joined: 8:47am, Sat 29 Oct, 2011

Previous

Return to Contributions: Plug-ins, Add-ons, Mods

Who is online

Users browsing this forum: No registered users and 2 guests