johnrom

Constant Contact Merge Lists API Fix

May 16th, 2013
404
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 96.89 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Constant Contact PHP Class
  4.  *
  5.  * @package        wordpress
  6.  * @subackage    constant-contact-api
  7.  */
  8. // $Id$
  9. /**
  10.  * @file
  11.  */
  12. class cc {
  13.  
  14.  
  15.     /**
  16.      * The user-agent header to send with all API requests
  17.      *
  18.      * @access     public
  19.      */
  20.     var $http_user_agent = 'Constant Contact for WordPress';
  21.  
  22.     /**
  23.      * The developers API key which is associated with the application
  24.      * PLEASE DO NOT CHANGE THIS API KEY
  25.      */
  26.     var $api_key = 'a9f642af-8f34-43b2-8882-00e6aaebfa46';
  27.  
  28.     /**
  29.      * The API username which is passed to the constructor, always required
  30.      *
  31.      * @access     public
  32.      */
  33.     var $api_username = '';
  34.  
  35.     /**
  36.      * The API password which is passed to the constructor, always required
  37.      *
  38.      * @access     public
  39.      */
  40.     var $api_password = '';
  41.  
  42.     /**
  43.      * The URL to use for all API calls, DO NOT INCLUDE A TRAILING SLASH!
  44.      *
  45.      * @access     public
  46.      */
  47.     var $api_url = 'https://api.constantcontact.com';
  48.  
  49.     /**
  50.      * This will be constructed automatically, same as above without the full URL
  51.      *
  52.      * @access     protected
  53.      */
  54.     var $api_uri = '';
  55.  
  56.     /**
  57.      * The last error message, can be used to provide a descriptive error if something goes wrong
  58.      *
  59.      * @access     public
  60.      */
  61.     var $last_error = '';
  62.  
  63.     /**
  64.      * The action type used for API calls, action by customer or contact, important!
  65.      * If you abuse this setting it violates the terms of the API
  66.      * Do not edit this property directly, instead use the @see set_action_type() method
  67.      *
  68.      * @access     protected
  69.      */
  70.     var $action_type = 'ACTION_BY_CUSTOMER';
  71.  
  72.     /**
  73.      * Meta data relating to the last call to the get_lists method
  74.      *
  75.      * @access     public
  76.      */
  77.     var $list_meta_data;
  78.  
  79.     /**
  80.      * Meta data relating to the last call to the get_list_members method
  81.      *
  82.      * @access     public
  83.      */
  84.     var $member_meta_data;
  85.  
  86.     /**
  87.      * The HTTP host used for the API
  88.      * This will be just the hostname of the API
  89.      *
  90.      * @access protected
  91.      */
  92.     var $http_host;
  93.  
  94.     /**
  95.      * The HTTP port used for the API
  96.      * This will be port 443 if using HTTPS or 80 is using HTTP
  97.      *
  98.      * @access protected
  99.      */
  100.     var $http_port;
  101.  
  102.     /**
  103.      * The results from a call to the PHP function @see parse_url()
  104.      * Contains an array of all the URL bits parsed by @see parse_url()
  105.      *
  106.      * @access protected
  107.      */
  108.     var $http_url_bits;
  109.  
  110.     /**
  111.      * HTTP request timeout in seconds
  112.      * This can be changed to any number you want
  113.      *
  114.      * @access public
  115.      */
  116.     var $http_request_timeout = 120;
  117.  
  118.     /**
  119.      * Username used for HTTP authentication
  120.      * It contains the string used to authenticate
  121.      * This will be built automatically from the API key and username
  122.      *
  123.      * @access protected
  124.      */
  125.     var $http_user;
  126.  
  127.     /**
  128.      * Password used for HTTP authentication
  129.      *
  130.      * @access protected
  131.      */
  132.     var $http_pass;
  133.  
  134.     /**
  135.      * The Content-Type header to use for all HTTP requests
  136.      * Do not edit this directly instead use the @see set_content_type() method
  137.      *
  138.      * @access protected
  139.      */
  140.     var $http_content_type;
  141.  
  142.     /**
  143.      * The default Content-Type header to use for all HTTP requests
  144.      * If no Content-Type header is set this is the default
  145.      *
  146.      * @access protected
  147.      */
  148.     var $http_default_content_type = 'text/html';
  149.  
  150.     /**
  151.      * The HTTP response code of the last HTTP request
  152.      *
  153.      * @access protected
  154.      */
  155.     var $http_response_code;
  156.  
  157.     /**
  158.      * The full HTTP response of the last HTTP request
  159.      *
  160.      * @access protected
  161.      */
  162.     var $http_response;
  163.  
  164.     /**
  165.      * The HTTP response body of the last HTTP request
  166.      *
  167.      * @access protected
  168.      */
  169.     var $http_response_body;
  170.  
  171.     /**
  172.      * The full HTTP request body of the last HTTP request
  173.      *
  174.      * @access protected
  175.      */
  176.     var $http_request;
  177.  
  178.     /**
  179.      * The method to use for the HTTP request
  180.      *
  181.      * @access protected
  182.      */
  183.     var $http_method;
  184.  
  185.     /**
  186.      * The line break used to separate HTTP headers
  187.      *
  188.      * @access public
  189.      */
  190.     var $http_linebreak = "\r\n";
  191.  
  192.     /**
  193.      * The HTTP requests headers, use @see http_headers_add() to add individual headers
  194.      *
  195.      * @access protected
  196.      */
  197.     var $http_request_headers = array();
  198.  
  199.     /**
  200.      * The HTTP response headers
  201.      *
  202.      * @access protected
  203.      */
  204.     var $http_response_headers = array();
  205.  
  206.     /**
  207.      * A list of encodings we support for the XML file
  208.      *
  209.      * @access public
  210.      */
  211.     var $xml_known_encodings = array('UTF-8', 'US-ASCII', 'ISO-8859-1');
  212.  
  213.  
  214.  
  215.     /**
  216.      * Constructor method
  217.      * Sets default params
  218.      * Constructs the correct API URL
  219.      * Sets variables for the http_* methods
  220.      * If you want to change the APi key use the @see set_api_key() method
  221.      *
  222.      * @param string     The username for your Constant Contact account
  223.      * @param string     The password for your Constant Contact account
  224.      * @param string     The API key for your Constant Contact developer account (deprecated)
  225.      *
  226.      * @access     public
  227.      */
  228.     function cc($api_username, $api_password)
  229.     {
  230.         $this->api_username = $api_username;
  231.         $this->api_password = $api_password;
  232.  
  233.         $this->api_url .= '/ws/customers/' . rawurlencode($api_username) . '/';
  234.         $this->api_uri .= '/ws/customers/' . urlencode($api_username) . '/';
  235.  
  236.         $this->http_user = $this->api_key . "%" . $api_username;
  237.         $this->http_pass = $api_password;
  238.         $this->http_set_content_type($this->http_default_content_type);
  239.     }
  240.  
  241.  
  242.     /**
  243.      * IMPORTANT!
  244.      * This method sets the action type
  245.      * If a user performs the action themselves you should call this method with the param 'contact'
  246.      * This triggers the welcome email if a new subscriber
  247.      * You may get banned if you use this setting incorrectly!
  248.      * The default action is ACTION_BY_CUSTOMER meaning the constant contact account owner made the action themselves, this can typically be associated with an admin subscribers users or updating a users details
  249.      * If you have a signup form on your website you should set this method to ACTION_BY_CONTACT
  250.      * Call this method before you subscribe a user or perform any other action they make and again to reset it
  251.      * eg. $cc->set_action_type('contact');
  252.      *
  253.      *
  254.      * @access     public
  255.      */
  256.     function set_action_type($action_type='customer')
  257.     {
  258.         $this->action_type = (strtolower($action_type)=='customer') ? 'ACTION_BY_CUSTOMER' : 'ACTION_BY_CONTACT';
  259.     }
  260.  
  261.     /**
  262.      * This method does a print_r on the http_request and http_response variables
  263.      * Useful for debugging the HTTP request
  264.      *
  265.      * @access     public
  266.      */
  267.     function show_last_connection()
  268.     {
  269.         print_r($this->http_request);
  270.         print_r($this->http_response);
  271.     }
  272.  
  273.     /**
  274.      * Shows the last request
  275.      *
  276.      * @access     public
  277.      */
  278.     function show_request()
  279.     {
  280.         print_r($this->http_request);
  281.     }
  282.  
  283.     /**
  284.      * Shows the last response
  285.      *
  286.      * @access     public
  287.      */
  288.     function show_response()
  289.     {
  290.         print_r($this->http_response);
  291.     }
  292.  
  293.  
  294.     /**
  295.      * This sets the API key to the given string
  296.      * You do not need to use this method unless your bundling the code into your own application
  297.      * If your application will be used by multiple users please create your own API key and call this
  298.      *
  299.      * @access     public
  300.      */
  301.     function set_api_key($api_key)
  302.     {
  303.         $this->api_key = $api_key;
  304.     }
  305.  
  306.  
  307.     /**
  308.      * This gets the service description file from CC
  309.      *
  310.      *
  311.      * @access     public
  312.      */
  313.     function get_service_description()
  314.     {
  315.         return $this->load_url();
  316.     }
  317.  
  318.  
  319.     /**
  320.      * Gets all the contact lists for the CC account
  321.      * If more than one page exists we grab them too
  322.      * Second argument can be used to show/hide the do-not-mail etc lists
  323.      * This method also sorts the lists based on the SortOrder field
  324.      *
  325.      * Avoid using this function directly, instead use constant_contact_get_lists()
  326.      * which has built-in caching via WordPress transients to avoid constant queries
  327.      * to the API that slow down the frontend of a site.
  328.      *
  329.      * @access     public
  330.      */
  331.     function get_all_lists($action = 'lists', $exclude = 3, $callback = '')
  332.     {
  333.         $lists = $this->get_lists($action, $exclude);
  334.  
  335.         if(count($lists) > 0):
  336.             if(isset($this->list_meta_data->next_page)):
  337.                 // grab all the other pages if they exist
  338.                 while($this->list_meta_data->next_page != ''):
  339.                 $lists = array_merge($lists, $this->get_lists($this->list_meta_data->next_page, 0));
  340.                 endwhile;
  341.             endif;
  342.  
  343.             $callback = ($callback) ? $callback : array("cc", "sort_lists");
  344.             if(is_array($lists)):
  345.                 usort($lists, $callback);
  346.             endif;
  347.  
  348.         endif;
  349.  
  350.         return $lists;
  351.     }
  352.  
  353.     /**
  354.      * sort the lists based on the SortOrder field
  355.      *
  356.      * @access     private
  357.      */
  358.     function sort_lists($a, $b)
  359.     {
  360.         if(!isset($a['SortOrder'], $b['SortOrder']) || $a['SortOrder'] == $b['SortOrder']):
  361.             return 0;
  362.         endif;
  363.         return ($a['SortOrder'] < $b['SortOrder']) ? -1 : 1;
  364.     }
  365.  
  366.  
  367.     /**
  368.      * Gets the contact lists for the CC account
  369.      * The results are pageable
  370.      * Second argument can be used to show/hide the do-not-mail etc lists
  371.      *
  372.      *
  373.      * @access     public
  374.      */
  375.     function get_lists($action = 'lists', $exclude = 3)
  376.     {
  377.         $xml = $this->load_url($action);
  378.  
  379.         if(!$xml):
  380.             return false;
  381.         endif;
  382.  
  383.         $lists = array();
  384.  
  385.         // parse into nicer array
  386.         $_lists = (isset($xml['feed']['entry'])) ? $xml['feed']['entry'] : false;
  387.  
  388.         // Prevent PHP warning caused by page stuff below.
  389.         if(!is_object($this->list_meta_data)) {
  390.             $this->list_meta_data = new stdClass();
  391.         }
  392.  
  393.         if(isset($xml['feed']['link']['2_attr']['rel']) && $xml['feed']['link']['2_attr']['rel'] == 'first'):
  394.             $this->list_meta_data->first_page = $this->get_id_from_link($xml['feed']['link']['2_attr']['href']);
  395.             $this->list_meta_data->current_page = $this->get_id_from_link($xml['feed']['link']['3_attr']['href']);
  396.             $this->list_meta_data->next_page = '';
  397.         elseif(isset($xml['feed']['link']['2_attr']['rel']) && $xml['feed']['link']['2_attr']['rel'] == 'next'):
  398.             $this->list_meta_data->next_page = $this->get_id_from_link($xml['feed']['link']['2_attr']['href']);
  399.             $this->list_meta_data->current_page = $this->get_id_from_link($xml['feed']['link']['3_attr']['href']);
  400.             $this->list_meta_data->first_page = $this->get_id_from_link($xml['feed']['link']['4_attr']['href']);
  401.         endif;
  402.  
  403.  
  404.         if(is_array($_lists) && count($_lists) > 3):
  405.  
  406.             if($exclude):
  407.                 // skip first x amount of lists - remove, do not mail etc
  408.                 $_lists = array_slice($_lists, $exclude);
  409.             endif;
  410.  
  411.             if(isset($_lists[0]['link_attr']['href'])):
  412.                 foreach($_lists as $k => $v):
  413.                     $id = $this->get_id_from_link($v['link_attr']['href']);
  414.  
  415.                     $list = array(
  416.                         'id' => $id,
  417.                         'Name' => $v['content']['ContactList']['Name'],
  418.                         'ShortName' => $v['content']['ContactList']['ShortName'],
  419.                     );
  420.  
  421.                     if(isset($v['content']['ContactList']['OptInDefault'])):
  422.                         $list['OptInDefault'] = $v['content']['ContactList']['OptInDefault'];
  423.                     endif;
  424.  
  425.                     if(isset($v['content']['ContactList']['SortOrder'])):
  426.                         $list['SortOrder'] = $v['content']['ContactList']['SortOrder'];
  427.                     endif;
  428.  
  429.                     $lists[] = $list;
  430.                 endforeach;
  431.             else:
  432.                 $id = $this->get_id_from_link($_lists['link_attr']['href']);
  433.  
  434.                 $list = array(
  435.                     'id' => $id,
  436.                     'Name' => $_lists['content']['ContactList']['Name'],
  437.                     'ShortName' => $_lists['content']['ContactList']['ShortName'],
  438.                 );
  439.  
  440.                 if(isset($_lists['content']['ContactList']['OptInDefault'])):
  441.                     $list['OptInDefault'] = $_lists['content']['ContactList']['OptInDefault'];
  442.                 endif;
  443.  
  444.                 if(isset($_lists['content']['ContactList']['SortOrder'])):
  445.                     $list['SortOrder'] = $_lists['content']['ContactList']['SortOrder'];
  446.                 endif;
  447.  
  448.                 $lists[] = $list;
  449.             endif;
  450.         endif;
  451.  
  452.         return $lists;
  453.     }
  454.  
  455.  
  456.     /**
  457.      * Gets the details of a specific constant list
  458.      *
  459.      *
  460.      * @access     public
  461.      */
  462.     function get_list($listid)
  463.     {
  464.         $xml = $this->load_url("lists/$listid");
  465.  
  466.         if(!$xml):
  467.             return false;
  468.         endif;
  469.  
  470.         $list = false;
  471.         $_list = (isset($xml['entry'])) ? $xml['entry'] : false;
  472.  
  473.         // parse into nicer array
  474.         if(is_array($_list)):
  475.             $id = $this->get_id_from_link($_list['link_attr']['href']);
  476.  
  477.             $list = array(
  478.                 'id' => $id,
  479.                 'Name' => $_list['content']['ContactList']['Name'],
  480.                 'ShortName' => $_list['content']['ContactList']['ShortName'],
  481.                 'OptInDefault' => $_list['content']['ContactList']['OptInDefault'],
  482.                 'SortOrder' => $_list['content']['ContactList']['SortOrder'],
  483.             );
  484.         endif;
  485.  
  486.         return $list;
  487.     }
  488.  
  489.  
  490.     /**
  491.      * Deletes a contact list
  492.      *
  493.      *
  494.      * @access     public
  495.      */
  496.     function delete_list($listid = 0)
  497.     {
  498.         $this->http_set_content_type('text/html');
  499.         $this->load_url("lists/$listid", 'delete', array(), 204);
  500.         if(intval($this->http_response_code) === 204):
  501.             return true;
  502.         endif;
  503.         return false;
  504.     }
  505.  
  506.  
  507.     /**
  508.      * Updates an existing contact list
  509.      *
  510.      *
  511.      * @access     public
  512.      */
  513.     function update_list($id, $name, $default = "false", $sort_order = 99)
  514.     {
  515.         // build the XML put data
  516.         $url = $this->get_list_url($id);
  517.  
  518.         $xml_data = '
  519. <entry xmlns="http://www.w3.org/2005/Atom">
  520.  <id>'.$url.'</id>
  521.  <title type="text">'.$name.'</title>
  522.  <author />
  523.  <updated>2008-04-16T18:39:35.710Z</updated>
  524.  <content type="application/vnd.ctct+xml">
  525.    <ContactList xmlns="http://ws.constantcontact.com/ns/1.0/"
  526.        id="'.$url.'">
  527.      <OptInDefault>'.$default.'</OptInDefault>
  528.      <Name>'.$name.'</Name>
  529.      <ShortName>'.$name.'</ShortName>
  530.      <SortOrder>'.$sort_order.'</SortOrder>
  531.    </ContactList>
  532.  </content>
  533.  <link href="/ws/customers/'.$this->api_username.'/lists/'.$id.'" rel="update" />
  534. </entry>
  535. ';
  536.  
  537.         $this->http_set_content_type('application/atom+xml');
  538.         $xml = $this->load_url("lists/$id", 'put', $xml_data, 204);
  539.  
  540.         if(intval($this->http_response_code) === 204):
  541.             return true;
  542.         endif;
  543.         return false;
  544.     }
  545.  
  546.  
  547.     /**
  548.      * Creates a new contact list
  549.      *
  550.      *
  551.      * @access     public
  552.      */
  553.     function create_list($name, $default = "false", $sort_order = 99)
  554.     {
  555.         // build the XML post data
  556.         $xml_post = '<entry xmlns="http://www.w3.org/2005/Atom">
  557.  <id>data:,</id>
  558.  <title/>
  559.  <author/>
  560.  <updated>2008-04-16</updated>
  561.  <content type="application/vnd.ctct+xml">
  562.    <ContactList xmlns="http://ws.constantcontact.com/ns/1.0/">
  563.      <OptInDefault>'.$default.'</OptInDefault>
  564.      <Name>'.$name.'</Name>
  565.      <SortOrder>'.$sort_order.'</SortOrder>
  566.    </ContactList>
  567.  </content>
  568. </entry>';
  569.  
  570.         $this->http_set_content_type('application/atom+xml');
  571.  
  572.         $xml = $this->load_url("lists", 'post', $xml_post, 201);
  573.  
  574.         if(isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != ''):
  575.             return $this->get_id_from_link($this->http_response_headers['Location']);
  576.         endif;
  577.  
  578.         return false;
  579.     }
  580.  
  581.     /**
  582.      * Returns the full URL for list operations
  583.      * NOTE: this is a HTTP URL unike the one we call
  584.      *
  585.      *
  586.      * @access     private
  587.      */
  588.     function get_list_url($id, $full_address = true)
  589.     {
  590.         if($full_address):
  591.             $_url = str_replace('https:', 'http:', $this->api_url . "lists");
  592.         else:
  593.             $_url = $this->api_uri . "lists";
  594.         endif;
  595.  
  596.         return "$_url/$id";
  597.     }
  598.  
  599.  
  600.     /**
  601.      * This returns the HTTP URL for the API
  602.      *
  603.      * @access     private
  604.      */
  605.     function get_http_api_url()
  606.     {
  607.         return str_replace('https:', 'http:', $this->api_url);
  608.     }
  609.  
  610.  
  611.     /**
  612.      * Gets the members (contacts) in a specific contact list
  613.      * Supports paging of the results
  614.      *
  615.      *
  616.      * @access     public
  617.      */
  618.     function get_list_members($listid, $action = 'members')
  619.     {
  620.         $xml = $this->load_url("lists/$listid/$action");
  621.  
  622.         if(!$xml):
  623.             return false;
  624.         endif;
  625.  
  626.         // parse into nicer array
  627.         $contacts = array();
  628.         $_members = (isset($xml['feed']['entry'])) ? $xml['feed']['entry'] : false;
  629.  
  630.  
  631.         if(isset($xml['feed']['link']['2_attr']['rel']) && $xml['feed']['link']['2_attr']['rel'] == 'first'):
  632.             $this->member_meta_data->first_page = $this->get_id_from_link($xml['feed']['link']['2_attr']['href']);
  633.             $this->member_meta_data->current_page = $this->get_id_from_link($xml['feed']['link']['3_attr']['href']);
  634.             $this->member_meta_data->next_page = '';
  635.         elseif(isset($xml['feed']['link']['2_attr']['rel']) && $xml['feed']['link']['2_attr']['rel'] == 'next'):
  636.             $this->member_meta_data->next_page = $this->get_id_from_link($xml['feed']['link']['2_attr']['href']);
  637.             $this->member_meta_data->current_page = $this->get_id_from_link($xml['feed']['link']['3_attr']['href']);
  638.             $this->member_meta_data->first_page = $this->get_id_from_link($xml['feed']['link']['4_attr']['href']);
  639.         endif;
  640.  
  641.         if(is_array($_members)):
  642.             if(isset($_members[0]['link_attr']['href'])):
  643.                 foreach($_members as $k => $v):
  644.                     $EmailAddress = $v['content']['ContactListMember']['EmailAddress'];
  645.                     $Name = $v['content']['ContactListMember']['Name'];
  646.                     $id = $this->get_id_from_link($v['link_attr']['href']);
  647.  
  648.                     $contact = array(
  649.                         'id' => $id,
  650.                         'EmailAddress' => $EmailAddress,
  651.                         'Name' => $Name,
  652.                     );
  653.                     $contacts[] = $contact;
  654.                 endforeach;
  655.             else:
  656.                 $EmailAddress = $_members['content']['ContactListMember']['EmailAddress'];
  657.                 $Name = $_members['content']['ContactListMember']['Name'];
  658.                 $id = $this->get_id_from_link($_members['link_attr']['href']);
  659.  
  660.                 $contact = array(
  661.                     'id' => $id,
  662.                     'EmailAddress' => $EmailAddress,
  663.                     'Name' => $Name,
  664.                 );
  665.                 $contacts[] = $contact;
  666.             endif;
  667.         endif;
  668.  
  669.         return $contacts;
  670.     }
  671.  
  672.  
  673.     function get_all_list_members($listid) {
  674.         $contacts = constant_contact_get_transient('listmembers'.$listid);
  675.         if($contacts && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'list')) { return maybe_unserialize($contacts); }
  676.  
  677.         $contacts = array();
  678.         $_contacts = array($this->get_list_members($listid));
  679.         if(!empty($_contacts)) {
  680.  
  681.             while(!empty($this->member_meta_data->next_page)) {
  682.                 $_contacts[] = $this->get_list_members($listid, $this->member_meta_data->next_page);
  683.             }
  684.             foreach($_contacts as $contactList) {
  685.                 foreach($contactList as $k => $v) {
  686.                     $contacts[$v['id']] = $v;
  687.                 }
  688.             }
  689.             #r($contacts);
  690.  
  691.         }
  692.  
  693.         constant_contact_set_transient('listmembers'.$listid, maybe_serialize($contacts));
  694.         return $contacts;
  695.     }
  696.  
  697.  
  698.     /**
  699.      * Creates a new contact
  700.      *
  701.      * @access     public
  702.      */
  703.     function create_contact($email, $lists = array(), $additional_fields = array())
  704.     {
  705.         $lists_url = str_replace('https:', 'http:', $this->api_url . "lists");
  706.  
  707.         // build the XML post data
  708.         $xml_post = '
  709. <entry xmlns="http://www.w3.org/2005/Atom">
  710.  <title type="text"> </title>
  711.  <updated>2008-07-23T14:21:06.407Z</updated>
  712.  <author></author>
  713.  <id>data:,none</id>
  714.  <summary type="text">Contact</summary>
  715.  <content type="application/vnd.ctct+xml">
  716.    <Contact xmlns="http://ws.constantcontact.com/ns/1.0/">
  717.      <EmailAddress>'.$email.'</EmailAddress>
  718.      <OptInSource>'.$this->action_type.'</OptInSource>
  719. ';
  720.  
  721.     if($additional_fields):
  722.     foreach($additional_fields as $field => $value):
  723.         $xml_post .= "<$field>$value</$field>\n";
  724.     endforeach;
  725.     endif;
  726.  
  727.     $xml_post .= '<ContactLists>';
  728.     if($lists):
  729.     if(is_array($lists)):
  730.         foreach($lists as $k => $id):
  731.             $xml_post .= '<ContactList id="'.$lists_url.'/'.$id.'" />';
  732.         endforeach;
  733.     else:
  734.         $xml_post .= '<ContactList id="'.$lists_url.'/'.$lists.'" />';
  735.     endif;
  736.     endif;
  737.     $xml_post .= '</ContactLists>';
  738.  
  739. $xml_post .= '
  740.    </Contact>
  741.  </content>
  742. </entry>';
  743.         $this->http_set_content_type('application/atom+xml');
  744.  
  745.         $xml = $this->load_url("contacts", 'post', $xml_post, 201);
  746.  
  747.         if(isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != ''):
  748.             return $this->get_id_from_link($this->http_response_headers['Location']);
  749.         endif;
  750.  
  751.         return $this->http_response_body; // was simply `return`
  752.     }
  753.  
  754.  
  755.     /**
  756.      * Updates a contact
  757.      * @param  integer $id               The ID of the contact.
  758.      * @param  string $email             The email of the contact.
  759.      * @param  array  $lists             [description]
  760.      * @param  array  $additional_fields [description]
  761.      * @return [type]                    [description]
  762.      */
  763.     function update_contact($id, $email, $lists = array(), $additional_fields = array())
  764.     {
  765.  
  766.         $id = intval($id);
  767.         $email = esc_html($email);
  768.  
  769.         // set a third argument, $refresh, to be sure we're manipulating up-to-date information
  770.         $contact = $this->get_contact($id, 3600, true);
  771.         $current_lists = $contact['lists'];
  772.  
  773.         // email address is already listed in $email
  774.         unset($additional_fields['EmailAddress']);
  775.  
  776.         if ( empty($additional_fields) && count(array_intersect($lists, $current_lists)) == count($lists) )
  777.             return true; // already registered for all lists, nothing else to do, let's not send another request
  778.  
  779.         $lists = array_unique( array_merge($current_lists, $lists) );
  780.  
  781.         if(empty($id) || !is_email( $email )) { return; }
  782.  
  783.         // build the XML put data
  784.         $_url = str_replace('https:', 'http:', $this->api_url . "contacts");
  785.         $url = "$_url/$id";
  786.         $url = esc_url( $url );
  787.         $xml_data = '<entry xmlns="http://www.w3.org/2005/Atom">
  788.  <id>'.$url.'</id>
  789.  <title type="text">Contact: '.$email.'</title>
  790.  <updated>2008-04-25T19:29:06.096Z</updated>
  791.  <author></author>
  792.  <content type="application/vnd.ctct+xml">
  793.    <Contact xmlns="http://ws.constantcontact.com/ns/1.0/" id="'.$url.'">
  794.      <EmailAddress>'.$email.'</EmailAddress>
  795.      <OptInSource>'.esc_html($this->action_type).'</OptInSource>
  796.      <OptInTime>2009-11-19T14:48:41.761Z</OptInTime>
  797. ';
  798.         if($additional_fields):
  799.  
  800.             // We want to double-encode for edge cases.
  801.             $additional_fields = array_map('htmlentities', $additional_fields);
  802.             $additional_fields = array_map('htmlspecialchars', $additional_fields);
  803.             $additional_fields = array_map('stripslashes', $additional_fields);
  804.  
  805.         foreach($additional_fields as $field => $value):
  806.             $xml_data .= "<$field>$value</$field>\n";
  807.         endforeach;
  808.         endif;
  809.  
  810.         $xml_data .= "<ContactLists>\n";
  811.         if($lists):
  812.         if(is_array($lists)):
  813.             foreach($lists as $k => $list_id):
  814.                 $list_id = intval($list_id);
  815.                 $xml_data .= '<ContactList id="'.$this->get_list_url($list_id).'"></ContactList>';
  816.             endforeach;
  817.         else:
  818.             $xml_data .= '<ContactList id="'.$this->get_list_url($list_id).'"></ContactList>';
  819.         endif;
  820.         endif;
  821.         $xml_data .= "</ContactLists>\n";
  822.  
  823. $xml_data .= '
  824.    </Contact>
  825.  </content>
  826. </entry>
  827. ';
  828.        
  829.         $this->http_set_content_type('application/atom+xml');
  830.         $this->load_url("contacts/$id", 'put', $xml_data, 204);
  831.  
  832.         if(intval($this->http_response_code) === 204):
  833.             return true;
  834.         endif;
  835.         return false;
  836.     }
  837.  
  838.  
  839.     function get_all_contacts($timeout = 21600) {
  840.         $contacts = constant_contact_get_transient('cc_contacts');
  841.         if($contacts && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'contacts')) { return maybe_unserialize($contacts); }
  842.  
  843.         $contacts = array();
  844.         $_contacts = array($this->get_contacts());
  845.         if(!empty($_contacts)) {
  846.  
  847.             while(!empty($this->contact_meta_data->next_page)) {
  848.                 $_contacts[] = $this->get_contacts($this->contact_meta_data->next_page);
  849.             }
  850.             foreach($_contacts as $contactList) {
  851.                 foreach($contactList as $k => $v) {
  852.                     $contacts[$v['id']] = $v;
  853.                 }
  854.             }
  855.             #r($contacts);
  856.  
  857.         }
  858.  
  859.         constant_contact_set_transient('cc_contacts', maybe_serialize($contacts), $timeout);
  860.         return $contacts;
  861.     }
  862.  
  863.  
  864.     /**
  865.      * Gets all contacts and allows paging of the results
  866.      *
  867.      * @access     public
  868.      */
  869.     function get_contacts($action = 'contacts', $timeout = 3600)
  870.     {
  871.         $xml = $this->load_url($action);
  872.  
  873.         if(!$xml):
  874.             return false;
  875.         endif;
  876.  
  877.         // parse into nicer array
  878.         $contacts = array();
  879.         $_contacts = (isset($xml['feed']['entry'])) ? $xml['feed']['entry'] : false;
  880.  
  881.         // Prevent PHP warning caused by page stuff below.
  882.         if(!is_object($this->contact_meta_data)) {
  883.             $this->contact_meta_data = new stdClass();
  884.         }
  885.  
  886.         if(isset($xml['feed']['link']['2_attr']['rel']) && $xml['feed']['link']['2_attr']['rel'] == 'first'):
  887.             $this->contact_meta_data->first_page = $this->get_id_from_link($xml['feed']['link']['2_attr']['href']);
  888.             $this->contact_meta_data->current_page = $this->get_id_from_link($xml['feed']['link']['3_attr']['href']);
  889.             $this->contact_meta_data->next_page = '';
  890.         elseif(isset($xml['feed']['link']['2_attr']['rel']) && $xml['feed']['link']['2_attr']['rel'] == 'next'):
  891.             $this->contact_meta_data->next_page = $this->get_id_from_link($xml['feed']['link']['2_attr']['href']);
  892.             $this->contact_meta_data->current_page = $this->get_id_from_link($xml['feed']['link']['3_attr']['href']);
  893.             $this->contact_meta_data->first_page = $this->get_id_from_link($xml['feed']['link']['4_attr']['href']);
  894.         endif;
  895.  
  896.         if(is_array($_contacts)):
  897.             if(isset($_contacts[0]['link_attr']['href'])):
  898.                 foreach($_contacts as $k => $v):
  899.                     $id = $this->get_id_from_link($v['link_attr']['href']);
  900.                     $contact = $v['content']['Contact'];
  901.                     $contact['id'] = $id;
  902.                     $contacts[] = $contact;
  903.                 endforeach;
  904.             else:
  905.                 $id = $this->get_id_from_link($_contacts['link_attr']['href']);
  906.                 $contact = $_contacts['content']['Contact'];
  907.                 $contact['id'] = $id;
  908.                 $contacts[] = $contact;
  909.             endif;
  910.         endif;
  911.  
  912.         return $contacts;
  913.     }
  914.  
  915.  
  916.     /**
  917.      * Gets a specific contacts details
  918.      *
  919.      * @access     public
  920.      */
  921.     function get_contact($id = null, $timeout = 3600, $refresh = false)
  922.     {
  923.         $transient_title = 'cccon'.sha1($id);
  924.         $contact = constant_contact_get_transient($transient_title);
  925.         if(!empty($timeout) && !$refresh && $contact && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'contact')) { return maybe_unserialize($contact); }
  926.  
  927.         $xml = $this->load_url("contacts/$id");
  928.  
  929.         if(!$xml):
  930.             return false;
  931.         endif;
  932.  
  933.         $contact = false;
  934.         $_contact = (isset($xml['entry'])) ? $xml['entry'] : false;
  935.  
  936.         // parse into nicer array
  937.         if(is_array($_contact)):
  938.             $id = $this->get_id_from_link($_contact['link_attr']['href']);
  939.  
  940.             $contact = $_contact['content']['Contact'];
  941.  
  942.             if(isset($_contact['content']['Contact']['ContactLists']['ContactList'])):
  943.                 $_lists = $_contact['content']['Contact']['ContactLists']['ContactList'];
  944.                 unset($_lists['0_attr']);
  945.                 unset($_lists['ContactList_attr']);
  946.             else:
  947.                 $_lists = false;
  948.             endif;
  949.  
  950.             // get lists
  951.             $lists = array();
  952.             if(is_array($_lists) && count($_lists) > 0):
  953.                 unset($_lists['id']);
  954.  
  955.                 if(isset($_lists['link_attr']['href'])):
  956.                     $list_id = $this->get_id_from_link($_lists['link_attr']['href']);
  957.                     $lists[$list_id] = $list_id;
  958.                 else:
  959.                     foreach($_lists as $k => $v):
  960.                         if(isset($v['link_attr']['href'])):
  961.                             $list_id = $this->get_id_from_link($v['link_attr']['href']);
  962.                             $lists[$list_id] = $list_id;
  963.                         endif;
  964.                     endforeach;
  965.                 endif;
  966.  
  967.                 unset($contact['ContactLists']);
  968.             endif;
  969.  
  970.             $contact['lists'] = $lists;
  971.             $contact['id'] = $id;
  972.         endif;
  973.  
  974.         constant_contact_set_transient($transient_title, maybe_serialize($contact), $timeout);
  975.  
  976.         return $contact;
  977.     }
  978.  
  979.  
  980.     /**
  981.      * This queries the API for contacts with a similar email address to the one you supply
  982.      *
  983.      * @access     public
  984.      */
  985.     function query_contacts($email)
  986.     {
  987.         $xml = $this->load_url('contacts?email=' . strtolower(urlencode($email)));
  988.  
  989.         if(!$xml):
  990.             return false;
  991.         endif;
  992.  
  993.         $contact = false;
  994.         $_contact = (isset($xml['feed']['entry'])) ? $xml['feed']['entry'] : false;
  995.  
  996.         // parse into nicer array
  997.         if(is_array($_contact)):
  998.             $id = $this->get_id_from_link($_contact['link_attr']['href']);
  999.  
  1000.             $contact = $_contact['content']['Contact'];
  1001.             $contact['id'] = $id;
  1002.         endif;
  1003.  
  1004.         return $contact;
  1005.     }
  1006.  
  1007.     /**
  1008.      * Deletes a contact
  1009.      *
  1010.      * @access     public
  1011.      */
  1012.     function delete_contact($id)
  1013.     {
  1014.         $this->http_set_content_type('text/html');
  1015.         $this->load_url("contacts/$id", 'delete', array(), 204);
  1016.         if(intval($this->http_response_code) === 204):
  1017.             return true;
  1018.         endif;
  1019.         return false;
  1020.     }
  1021.  
  1022.  
  1023.     /**
  1024.      * Activities (bulk) operations
  1025.      * The Activities resource is designed to be used only with large sets of contacts (ie. 25 or more). To manage individual contacts or small sets of contacts, use the  Contacts Collection API resource. (As discussed in the  Constant Contact API Terms and Conditions, intentional and unintentional misuse of this bulk API to frequently manage individual contacts or small sets of contacts is subject to API access or account termination).
  1026.      *
  1027.      */
  1028.  
  1029.  
  1030.     /**
  1031.      * Downloads an activity file
  1032.      *
  1033.      * @access     public
  1034.      */
  1035.     function download_activity_file($filename)
  1036.     {
  1037.         $this->http_set_content_type(NULL);
  1038.         $this->load_url("activities/$filename", 'get');
  1039.         return $this->http_response_body;
  1040.     }
  1041.  
  1042.  
  1043.     /**
  1044.      * Gets an individual activity
  1045.      *
  1046.      * @access     public
  1047.      */
  1048.     function get_activity($id)
  1049.     {
  1050.         $xml = $this->load_url("activities/$id");
  1051.  
  1052.         if(!$xml):
  1053.             return false;
  1054.         endif;
  1055.  
  1056.         // parse into nicer array
  1057.         $_activity = (isset($xml['entry'])) ? $xml['entry'] : false;
  1058.         $activity = $_activity['content']['Activity'];
  1059.         $activity['id'] = $id;
  1060.  
  1061.         if(isset($activity['FileName'])):
  1062.             $activity['FileName'] = $this->get_id_from_link($activity['FileName']);
  1063.         endif;
  1064.  
  1065.         return $activity;
  1066.     }
  1067.  
  1068.  
  1069.     /**
  1070.      * Gets all activities
  1071.      *
  1072.      * @access     public
  1073.      */
  1074.     function get_activities($action = 'activities')
  1075.     {
  1076.         $xml = $this->load_url($action);
  1077.  
  1078.         if(!$xml):
  1079.             return false;
  1080.         endif;
  1081.  
  1082.         // parse into nicer array
  1083.         $activities = array();
  1084.         $_activities = (isset($xml['feed']['entry'])) ? $xml['feed']['entry'] : false;
  1085.  
  1086.         if(is_array($_activities)):
  1087.             if(isset($_activities[0]['link_attr']['href'])):
  1088.                 foreach($_activities as $k => $v):
  1089.                     $id = $this->get_id_from_link($v['link_attr']['href']);
  1090.                     $activity = $v['content']['Activity'];
  1091.                     $activity['id'] = $id;
  1092.                     $activities[] = $activity;
  1093.                 endforeach;
  1094.             else:
  1095.                 $id = $this->get_id_from_link($_activities['link_attr']['href']);
  1096.                 $activity = $_activities['content']['Activity'];
  1097.                 $activity['id'] = $id;
  1098.                 $activities[] = $activity;
  1099.             endif;
  1100.         endif;
  1101.  
  1102.         return $activities;
  1103.     }
  1104.  
  1105.  
  1106.     /**
  1107.      * Gets all activities
  1108.      *
  1109.      * @access     public
  1110.      */
  1111.     function get_events($action = 'events', $timeout = 3600)
  1112.     {
  1113.         $events = constant_contact_get_transient('cc_events');
  1114.         if($events && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'events')) { return maybe_unserialize($events); }
  1115.  
  1116.         $xml = $this->load_url($action);
  1117.  
  1118.         if(!$xml):
  1119.             return false;
  1120.         endif;
  1121.  
  1122.         // parse into nicer array
  1123.         $events = array();
  1124.         $_events = (isset($xml['atom:feed']['atom:entry'])) ? $xml['atom:feed']['atom:entry'] : false;
  1125.         if(is_array($_events)):
  1126.             if(isset($_events[0]['atom:link_attr']['href'])):
  1127.                 foreach($_events as $k => $v):
  1128.                     $id = $this->get_id_from_link($v['atom:link_attr']['href']);
  1129.                     $event = $v['atom:content']['Event'];
  1130.                     $event['id'] = $id;
  1131.                     $events[] = $event;
  1132.                 endforeach;
  1133.             else:
  1134.                 $id = $this->get_id_from_link($_events['atom:link_attr']['href']);
  1135.                 $event = $_events['atom:content']['Event'];
  1136.                 $event['id'] = $id;
  1137.                 $events[] = $event;
  1138.             endif;
  1139.         endif;
  1140.  
  1141.         if(!empty($events)) {
  1142.             constant_contact_set_transient('cc_events', maybe_serialize($events), $timeout);
  1143.         }
  1144.  
  1145.         return $events;
  1146.     }
  1147.  
  1148.      /**
  1149.      * Gets an individual activity
  1150.      *
  1151.      * @access     public
  1152.      */
  1153.     function get_event($id = null, $timeout = 3600)
  1154.     {
  1155.         $transient_title = 'ccev_'.sha1($id);
  1156.         $events = constant_contact_get_transient($transient_title);
  1157.         if($events && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'event')) { return maybe_unserialize($events); }
  1158.  
  1159.         $xml = $this->load_url("events/$id");
  1160.  
  1161.         if(!$xml):
  1162.             return false;
  1163.         endif;
  1164.  
  1165.         // parse into nicer array
  1166.         $_events = (isset($xml['atom:entry'])) ? $xml['atom:entry'] : false;
  1167.         $events = $_events['atom:content']['Event'];
  1168.         $events['id'] = $id;
  1169.  
  1170.         if(isset($events['FileName'])):
  1171.             $events['FileName'] = $this->get_id_from_link($events['FileName']);
  1172.         endif;
  1173.  
  1174.         if(!empty($events)) {
  1175.             constant_contact_set_transient($transient_title, maybe_serialize($events), $timeout);
  1176.         }
  1177.  
  1178.         return $events;
  1179.     }
  1180.  
  1181.     function get_event_registrants($id) {
  1182.  
  1183.         $transient_title = 'ccers'.sha1($id);
  1184.         $registrants = constant_contact_get_transient($transient_title);
  1185.         if($registrants && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'registrants')) { return maybe_unserialize($registrants); }
  1186.  
  1187.          $xml = $this->load_url("events/$id/registrants");
  1188.  
  1189.         if(!$xml):
  1190.             return false;
  1191.         endif;
  1192.  
  1193.         // parse into nicer array
  1194.         $registrants = array();
  1195.         $_registrants = (isset($xml['atom:feed']['atom:entry'])) ? $xml['atom:feed']['atom:entry'] : false;
  1196.  
  1197.         if(is_array($_registrants)):
  1198.             if(isset($_registrants[0]['atom:link_attr']['href'])):
  1199.                 foreach($_registrants as $k => $v):
  1200.                     $id = $this->get_id_from_link($v['atom:link_attr']['href']);
  1201.                     $registrant = $v['atom:content']['Registrant'];
  1202.                     $registrant['id'] = $id;
  1203.                     $registrants[] = $registrant;
  1204.                 endforeach;
  1205.             else:
  1206.                 $id = $this->get_id_from_link($_registrants['atom:link_attr']['href']);
  1207.                 $registrant = $_registrants['atom:content']['Registrant'];
  1208.                 $registrant['id'] = $id;
  1209.                 $registrants[] = $registrant;
  1210.             endif;
  1211.  
  1212.         endif;
  1213.  
  1214.         if(!empty($registrants)) {
  1215.             constant_contact_set_transient($transient_title, maybe_serialize($registrants), 60*60);
  1216.         }
  1217.  
  1218.         return $registrants;
  1219.     }
  1220.  
  1221.     function get_event_registrant($eventid = '',$registrantid = '')
  1222.     {
  1223.         $transient_title = 'ccer'.sha1($eventid.$registrantid);
  1224.         $registrant = constant_contact_get_transient($transient_title);
  1225.         if($registrant && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'registrant')) { return maybe_unserialize($registrant); }
  1226.  
  1227.         $xml = $this->load_url("events/$eventid/registrants/$registrantid");
  1228.  
  1229.         if(!$xml):
  1230.             return false;
  1231.         endif;
  1232.  
  1233.  
  1234.         // parse into nicer array
  1235.         $registrant = false;
  1236.         $_registrant = (isset($xml['atom:entry'])) ? $xml['atom:entry'] : false;
  1237.  
  1238.         // parse into nicer array
  1239.         if(is_array($_registrant)):
  1240.             $id = $this->get_id_from_link($_registrant['atom:link_attr']['href']);
  1241.             $registrant = $_registrant['atom:content']['Registrant'];
  1242.             $registrant['id'] = $id;
  1243.         endif;
  1244.  
  1245.         if(!empty($registrant)) {
  1246.             constant_contact_set_transient($transient_title, maybe_serialize($registrant), 60*60);
  1247.         }
  1248.  
  1249.         return $registrant;
  1250.     }
  1251.  
  1252.  
  1253.     /**
  1254.      * Be careful with this method :)
  1255.      * You can use this to clear all contacts from a specific set of contact lists
  1256.      *
  1257.      *
  1258.      * @param    array    An array of contact list ID's to clear of contacts
  1259.      * @access     public
  1260.      */
  1261.     function clear_contacts($lists)
  1262.     {
  1263.         $params['activityType'] = 'CLEAR_CONTACTS_FROM_LISTS';
  1264.  
  1265.         $lists_string = '';
  1266.         if(is_array($lists)):
  1267.             foreach($lists as $id):
  1268.                 $params['lists'][] = $this->get_list_url($id);
  1269.             endforeach;
  1270.         endif;
  1271.  
  1272.         $this->http_set_content_type('application/x-www-form-urlencoded');
  1273.  
  1274.         $this->load_url("activities", 'post', $params, 201);
  1275.  
  1276.         if(isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != ''):
  1277.             return $this->get_id_from_link($this->http_response_headers['Location']);
  1278.         endif;
  1279.  
  1280.         return false;
  1281.     }
  1282.  
  1283.  
  1284.     /**
  1285.      * Returns a list of the columns used in the export file
  1286.      *
  1287.      * @access     public
  1288.      */
  1289.     function get_export_file_columns()
  1290.     {
  1291.         $columns = array(
  1292.             'FIRST NAME',
  1293.             'MIDDLE NAME',
  1294.             'LAST NAME',
  1295.             'JOB TITLE',
  1296.             'COMPANY NAME',
  1297.             'WORK PHONE',
  1298.             'HOME PHONE',
  1299.             'ADDRESS LINE 1',
  1300.             'ADDRESS LINE 2',
  1301.             'ADDRESS LINE 3',
  1302.             'CITY',
  1303.             'STATE',
  1304.             'STATE/PROVINCE (US/CANADA)',
  1305.             'COUNTRY',
  1306.             'POSTAL CODE',
  1307.             'SUB POSTAL CODE',
  1308.         );
  1309.  
  1310.         $new = array();
  1311.  
  1312.         foreach($columns as $column):
  1313.             $new[$column] = $column;
  1314.         endforeach;
  1315.  
  1316.         return $new;
  1317.     }
  1318.  
  1319.  
  1320.     /**
  1321.      * This method creates a new export contacts activity
  1322.      * It returns the activity ID to use to check the status
  1323.      *
  1324.      *
  1325.      * @param    array    An array: fieldnames to export: see fieldnames.html
  1326.      * @param    int        The ID of the list to export
  1327.      * @param    string    The format of the export, either CSV or TXT
  1328.      *
  1329.      * @access     public
  1330.      */
  1331.     function export_contacts($list_id, $export_type = 'CSV', $columns = array(), $sort_by = 'DATE_DESC')
  1332.     {
  1333.         if(!is_array($columns) || !count($columns)):
  1334.             $columns = $this->get_export_file_columns();
  1335.         endif;
  1336.  
  1337.         $params['activityType'] = 'EXPORT_CONTACTS';
  1338.         $params['fileType'] = $export_type;
  1339.         $params['exportOptDate'] = 'true';
  1340.         $params['exportOptSource'] = 'true';
  1341.         $params['exportListName'] = 'false';
  1342.         $params['sortBy'] = $sort_by;
  1343.         $params['columns'] = $columns;
  1344.         $params['listId'] = $this->get_list_url($list_id);
  1345.  
  1346.         $this->http_set_content_type('application/x-www-form-urlencoded');
  1347.  
  1348.         $this->load_url("activities", 'post', $params, 201);
  1349.  
  1350.         if((isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != '') || isset($this->http_response_headers['location']) && trim($this->http_response_headers['location']) != '') {
  1351.             if(isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != '') {
  1352.                 return $this->get_id_from_link($this->http_response_headers['Location']);
  1353.             } else {
  1354.                 return $this->get_id_from_link($this->http_response_headers['location']);
  1355.             }
  1356.         }
  1357.  
  1358.         return false;
  1359.     }
  1360.  
  1361.  
  1362.     /**
  1363.      * This method is used to add 25 or more contacts
  1364.      * Pass this method an associative array of contact details
  1365.      * Alternatively you can give the path to a local or remote file
  1366.      * The file should be text or CSV format:
  1367.      * @link http://constantcontact.custhelp.com/cgi-bin/constantcontact.cfg/php/enduser/std_adp.php?p_faqid=2523
  1368.      *
  1369.      *
  1370.      * @param    mixed    This can be an array or a path to a file
  1371.      * @param    array    An array of contact list ID's to add the user to
  1372.      *
  1373.      * @access     public
  1374.      */
  1375.     function create_contacts($contacts, $lists)
  1376.     {
  1377.         $params['activityType'] = 'SV_ADD';
  1378.  
  1379.         if(is_array($contacts) && count($contacts) > 0):
  1380.             // get fieldnames from keys of the first contact array
  1381.             $fieldnames = array_keys($contacts[0]);
  1382.             $contacts = array_values($contacts);
  1383.  
  1384.             // transform the given array into a CSV formatted string
  1385.             $contacts_string = '';
  1386.             foreach($contacts as $k => $contact):
  1387.                 foreach($fieldnames as $k => $fieldname):
  1388.                     if(isset($contact[$fieldname]) || is_null($contact[$fieldname])):
  1389.                         $contacts_string .= $contact[$fieldname].",";
  1390.                     else:
  1391.                         $this->last_error = 'contacts array is not formatted correctly, please ensure all contact entries have the same fields and values';
  1392.                         return false;
  1393.                     endif;
  1394.                 endforeach;
  1395.                 $contacts_string .= "{$this->http_linebreak}";
  1396.             endforeach;
  1397.  
  1398.             $params['data'] = implode(',', $fieldnames)."{$this->http_linebreak}" . $contacts_string;
  1399.  
  1400.         elseif(file_exists($contacts) && is_readable($contacts)):
  1401.             // grab the file and output it directly in the request
  1402.             $params['data'] = file_get_contents($contacts);
  1403.         endif;
  1404.  
  1405.         if(is_array($lists)):
  1406.             foreach($lists as $id):
  1407.                 $params['lists'][] = $this->get_list_url($id);
  1408.             endforeach;
  1409.         endif;
  1410.  
  1411.         $this->http_set_content_type('application/x-www-form-urlencoded');
  1412.  
  1413.         $this->load_url("activities", 'post', $params, 201);
  1414.  
  1415.         if((isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != '') || (isset($this->http_response_headers['location']) && trim($this->http_response_headers['location']) != '')) {
  1416.             if(isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != '') {
  1417.                 return $this->get_id_from_link($this->http_response_headers['Location']);
  1418.             } else {
  1419.                 return $this->get_id_from_link($this->http_response_headers['location']);
  1420.             }
  1421.         }
  1422.  
  1423.         return false;
  1424.     }
  1425.  
  1426.  
  1427.  
  1428.     /**
  1429.      * Gets all campaigns
  1430.      *
  1431.      * @access     public
  1432.      */
  1433.     function get_campaigns($action = 'campaigns')
  1434.     {
  1435.         $transient_title = 'cc_campaigns';
  1436.         $campaigns = constant_contact_get_transient($transient_title);
  1437.         if($campaigns && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'campaigns')) { return maybe_unserialize($campaigns); }
  1438.  
  1439.         $xml = $this->load_url($action);
  1440.  
  1441.         if(!$xml):
  1442.             return false;
  1443.         endif;
  1444.  
  1445.  
  1446.         // parse into nicer array
  1447.         $campaigns = array();
  1448.         $_campaigns = (isset($xml['feed']['entry'])) ? $xml['feed']['entry'] : false;
  1449.  
  1450.         if(is_array($_campaigns)):
  1451.             if(isset($_campaigns[0]['link_attr']['href'])):
  1452.                 foreach($_campaigns as $k => $v):
  1453.                     $id = $this->get_id_from_link($v['link_attr']['href']);
  1454.                     $campaign = $v['content']['Campaign'];
  1455.                     $campaign['id'] = $id;
  1456.                     $campaigns[] = $campaign;
  1457.                 endforeach;
  1458.             else:
  1459.                 $id = $this->get_id_from_link($_campaigns['link_attr']['href']);
  1460.                 $campaign = $_campaigns['content']['Campaign'];
  1461.                 $campaign['id'] = $id;
  1462.                 $campaigns[] = $campaign;
  1463.             endif;
  1464.  
  1465.         endif;
  1466.  
  1467.         constant_contact_set_transient($transient_title, maybe_serialize($campaigns), 60*60);
  1468.  
  1469.         return $campaigns;
  1470.     }
  1471.  
  1472.  
  1473.     /**
  1474.      * Gets an individual campaign
  1475.      *
  1476.      * @access     public
  1477.      */
  1478.     function get_campaign($id)
  1479.     {
  1480.         $xml = $this->load_url("campaigns/$id");
  1481.  
  1482.         if(!$xml):
  1483.             return false;
  1484.         endif;
  1485.  
  1486.  
  1487.         // parse into nicer array
  1488.         $campaign = false;
  1489.         $_campaign = (isset($xml['entry'])) ? $xml['entry'] : false;
  1490.  
  1491.         // parse into nicer array
  1492.         if(is_array($_campaign)):
  1493.             $id = $this->get_id_from_link($_campaign['link_attr']['href']);
  1494.             $campaign = $_campaign['content']['Campaign'];
  1495.             $campaign['id'] = $id;
  1496.         endif;
  1497.  
  1498.         return $campaign;
  1499.     }
  1500.  
  1501.  
  1502.     /**
  1503.      * Deletes a campaign
  1504.      *
  1505.      * @access     public
  1506.      */
  1507.     function delete_campaign($id)
  1508.     {
  1509.         $this->http_set_content_type('text/html');
  1510.         $this->load_url("campaigns/$id", 'delete', array(), 204);
  1511.         if(intval($this->http_response_code) === 204):
  1512.             return true;
  1513.         endif;
  1514.         return false;
  1515.     }
  1516.  
  1517.  
  1518.     /**
  1519.      * Creates a new campaign
  1520.      *
  1521.      * @access     public
  1522.      */
  1523. /*
  1524.     function create_campaign($title, $contact_lists = array(), $options = array())
  1525.     {
  1526.         $email = (isset($options['EmailAddress'])) ? $options['EmailAddress'] : '';
  1527.         unset($options['EmailAddress']);
  1528.  
  1529.         $xml_post = '<?xml version="1.0" encoding="UTF-8"?>
  1530. <entry xmlns="http://www.w3.org/2005/Atom">
  1531.   <link href="/ws/customers/'.$this->api_username.'/campaigns" rel="edit" />
  1532.   <id>'.$this->get_http_api_url().'campaigns</id>
  1533.   <title type="text">'.$title.'</title>
  1534.   <updated>2009-10-19T18:34:53.105Z</updated>
  1535.   <author>
  1536.     <name>Constant Contact</name>
  1537.   </author>
  1538.   <content type="application/vnd.ctct+xml">
  1539.     <Campaign xmlns="http://ws.constantcontact.com/ns/1.0/"
  1540. id="'.$this->get_http_api_url().'campaigns/1100546096289">
  1541.       <Name>'.$title.'</Name>
  1542.       <Status>Draft</Status>
  1543.       <Date>2009-10-19T18:34:53.105Z</Date>
  1544. ';
  1545.         if(!is_array($options)):
  1546.             trigger_error('Third argument to create_campaign() should be an array', E_USER_ERROR);
  1547.         endif;
  1548.  
  1549.         foreach($options as $fieldname => $fieldvalue):
  1550.         if(isset($options[$fieldname])):
  1551.             $xml_post .= "<$fieldname>$fieldvalue</$fieldname>\n";
  1552.         endif;
  1553.         endforeach;
  1554.  
  1555.         if(is_array($contact_lists)):
  1556.             $xml_post  .= '<ContactLists>';
  1557.             foreach($contact_lists as $id):
  1558.                 $xml_post  .= '
  1559.                 <ContactList id="'.$this->get_list_url($id).'">
  1560.                 <link xmlns="http://www.w3.org/2005/Atom" href="'.$this->get_list_url($id,0).'" rel="self" />
  1561.                 </ContactList>
  1562.               ';
  1563.             endforeach;
  1564.             $xml_post .= '</ContactLists>';
  1565.         endif;
  1566.  
  1567.         if($email):
  1568.             $email = $this->get_emails($email);
  1569.  
  1570.             if(!isset($email['id'])):
  1571.                 $this->last_error = 'Invalid Email Address, the email address must exist in your constant contact account to be able to send an email from this address';
  1572.                 return false;
  1573.             endif;
  1574.  
  1575.             $xml_post .= '
  1576.             <FromEmail>
  1577.             <Email id="'.$this->get_http_api_url().'settings/emailaddresses/'.$email['id'].'">
  1578.             <link xmlns="http://www.w3.org/2005/Atom" href="'.$this->api_uri.'settings/emailaddresses/'.$email['id'].'" rel="self" />
  1579.             </Email>
  1580.             <EmailAddress>'.$email['EmailAddress'].'</EmailAddress>
  1581.             </FromEmail>
  1582.             <ReplyToEmail>
  1583.             <Email id="'.$this->get_http_api_url().'settings/emailaddresses/'.$email['id'].'">
  1584.             <link xmlns="http://www.w3.org/2005/Atom" href="'.$this->api_uri.'settings/emailaddresses/'.$email['id'].'" rel="self" />
  1585.             </Email>
  1586.             <EmailAddress>'.$email['EmailAddress'].'</EmailAddress>
  1587.             </ReplyToEmail>
  1588.             ';
  1589.         endif;
  1590.  
  1591.         $xml_post .= '
  1592.     </Campaign>
  1593.     </content>
  1594.     <source>
  1595.         <id>'.$this->get_http_api_url().'campaigns</id>
  1596.         <title type="text">Campaigns for customer: '.$this->api_username.'</title>
  1597.         <link href="campaigns" />
  1598.         <link href="campaigns" rel="self" />
  1599.         <author>
  1600.             <name>'.$this->api_username.'</name>
  1601.         </author>
  1602.         <updated>2009-10-19T19:36:12.622Z</updated>
  1603.     </source>
  1604. </entry>';
  1605.  
  1606.  
  1607.         $this->http_set_content_type('application/atom+xml');
  1608.         $xml = $this->load_url("campaigns", 'post', $xml_post, 201);
  1609.  
  1610.         if(isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != ''):
  1611.             return $this->get_id_from_link($this->http_response_headers['Location']);
  1612.         endif;
  1613.  
  1614.         return false;
  1615.     }
  1616. */
  1617.  
  1618.  
  1619.         /**
  1620.      * Creates a new campaign
  1621.      *
  1622.      * @access  public
  1623.      */
  1624.     function create_campaign($title = '', $email_subject = '', $email_head = '', $email_html = '', $email_text = '', $contact_lists = array(),$options = array(), $content_type = 'HTML')
  1625.     {
  1626.         $defaults = array(
  1627.             'FromName' => get_option('blogname'),
  1628.             'EmailAddress' => get_option('admin_email'),
  1629.             'ViewAsWebpage' => 'NO',
  1630.             'ViewAsWebpageText' => '',
  1631.             'ViewAsWebpageLinkText' => '',
  1632.             'IncludeForwardEmail' => 'NO',
  1633.             'IncludeSubscribeLink' => 'NO',
  1634.             'GreetingSalutation' => 'Dear',
  1635.             'GreetingName' => 'FirstName',
  1636.             'GreetingString' => 'Greetings!',
  1637.             'OrganizationName' => '',
  1638.             'OrganizationAddress1' => 'Account.AddressLine1',
  1639.             'OrganizationAddress2' => 'Account.AddressLine2',
  1640.             'OrganizationAddress3' => 'Account.AddressLine3',
  1641.             'OrganizationCity' => 'Account.City',
  1642.             'OrganizationState' => 'Account.USState',
  1643.             'OrganizationInternationalState' => 'Account.State',
  1644.             'OrganizationCountry' => 'Account.CountryCode',
  1645.             'OrganizationPostalCode' => 'Account.PostalCode',
  1646.             'StyleSheet' => '',
  1647.             'Status' => 'Draft',
  1648.             'ForwardEmailLinkText' => '',
  1649.             'PermissionReminderText' => '',
  1650.             'SubscribeLinkText' => '',
  1651.             'EmailContentFormat' => 'XHTML',
  1652.             'PermissionReminder' => 'YES',
  1653.         );
  1654.  
  1655.         $options = wp_parse_args($options, $defaults);
  1656.  
  1657.       if(get_option('gmt_offset')) {
  1658.         $offset = get_option('gmt_offset') * 60;
  1659.       } else {
  1660.         $offset = (60 * -5);
  1661.       }
  1662.  
  1663.         // build the XML post data
  1664.         $xml_post = '
  1665. <?xml version="1.0" encoding="UTF-8"?>
  1666. <entry xmlns="http://www.w3.org/2005/Atom">
  1667.  <link href="/ws/customers/'.$this->api_username.'/campaigns" rel="edit" />
  1668.  <id>'.$this->get_http_api_url().'campaigns</id>
  1669.  <title type="text">'.esc_html($title).'</title>
  1670.  <updated>'.date('Y').'-'.date('m').'-'.date('d').'T'.date('G').':'.date('i').':'.date('s').'.'.$offset.'Z</updated>
  1671.  <author>
  1672.    <name>Constant Contact for WordPress</name>
  1673.  </author>
  1674.  <content type="application/vnd.ctct+xml">
  1675.    <Campaign xmlns="http://ws.constantcontact.com/ns/1.0/" id="'.$this->get_http_api_url().'campaigns">
  1676.      <Name>'.esc_html($title).'</Name>
  1677.      <Date>'.date('Y').'-'.date('m').'-'.date('d').'T'.date('G').':'.date('i').':'.date('s').'.'.$offset.'Z</Date>
  1678.      <Subject>'.esc_html($email_subject).'</Subject>
  1679.      ';
  1680.  
  1681.  
  1682.     $xml_post .= '
  1683.        <ViewAsWebpage>'.$options['ViewAsWebpage'].'</ViewAsWebpage>
  1684.        <ViewAsWebpageLinkText>'.esc_html($options['ViewAsWebpageLinkText']).'</ViewAsWebpageLinkText>
  1685.        <ViewAsWebpageText>'.esc_html($options['ViewAsWebpageText']).'</ViewAsWebpageText>
  1686.        ';
  1687.     unset($options['ViewAsWebpage'], $options['ViewAsWebpageLinkText'], $options['ViewAsWebpageText']);
  1688.  
  1689.     if(isset($options['PermissionReminder']) && $options['PermissionReminder'] == 'YES') {
  1690.         $xml_post .= '
  1691.        <PermissionReminder>YES</PermissionReminder>
  1692.        <PermissionReminderText>'.esc_html($options['PermissionReminderText']).'</PermissionReminderText>';
  1693.     }
  1694.     unset($options['PermissionReminder'], $options['PermissionReminderText']);
  1695.  
  1696.     if($options['IncludeForwardEmail'] == 'YES') {
  1697.         $xml_post .= '
  1698.        <IncludeForwardEmail>YES</IncludeForwardEmail>
  1699.        <ForwardEmailLinkText>'.esc_html($options['ForwardEmailLinkText']).'</ForwardEmailLinkText>
  1700.        ';
  1701.     } else {
  1702.         $xml_post .= '
  1703.        <IncludeForwardEmail>NO</IncludeForwardEmail>
  1704.        <ForwardEmailLinkText></ForwardEmailLinkText>
  1705.        ';
  1706.     }
  1707.     unset($options['IncludeForwardEmail'], $options['ForwardEmailLinkText']);
  1708.  
  1709.     if($options['IncludeSubscribeLink'] == 'YES') {
  1710.         $xml_post .= '
  1711.        <IncludeSubscribeLink>YES</IncludeSubscribeLink>
  1712.        <SubscribeLinkText>'.esc_html($options['SubscribeLinkText']).'</SubscribeLinkText>
  1713.        ';
  1714.     } else {
  1715.         $xml_post .= '
  1716.        <IncludeSubscribeLink>NO</IncludeSubscribeLink>
  1717.        <SubscribeLinkText></SubscribeLinkText>
  1718.        ';
  1719.     }
  1720.     unset($options['IncludeSubscribeLink'], $options['SubscribeLinkText']);
  1721.  
  1722.         if(!empty($options['EmailAddress'])) {
  1723.             $email = $this->get_emails($options['EmailAddress']);
  1724.  
  1725.             if(!isset($email['id'])) {
  1726.                 $this->last_error = 'Invalid Email Address, the email address must exist in your constant contact account to be able to send an email from this address';
  1727.                 return false;
  1728.             }
  1729.  
  1730.             unset($options['EmailAddress']);
  1731.  
  1732.  
  1733.         $xml_post .= '
  1734.        <FromEmail>
  1735.            <Email id="'.$this->get_http_api_url().'settings/emailaddresses/'.$email['id'].'">
  1736.                <link xmlns="http://www.w3.org/2005/Atom" href="'.$this->api_uri.'settings/emailaddresses/'.$email['id'].'" rel="self" />
  1737.            </Email>
  1738.            <EmailAddress>'.$email['EmailAddress'].'</EmailAddress>
  1739.        </FromEmail>
  1740.        <ReplyToEmail>
  1741.            <Email id="'.$this->get_http_api_url().'settings/emailaddresses/'.$email['id'].'">
  1742.                <link xmlns="http://www.w3.org/2005/Atom" href="'.$this->api_uri.'settings/emailaddresses/'.$email['id'].'" rel="self" />
  1743.            </Email>
  1744.            <EmailAddress>'.$email['EmailAddress'].'</EmailAddress>
  1745.        </ReplyToEmail>
  1746.        ';
  1747.         foreach($options as $field => $value) {
  1748.             $xml_post .= '<'.$field.'>'.esc_html($value).'</'.$field.'>'."\n\t\t";
  1749.             unset($options[$field]);
  1750.         }
  1751.  
  1752.             $xml_post .= '
  1753.        <EmailContent>'.esc_html('<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"
  1754. xmlns:cctd="http://www.constantcontact.com/cctd">
  1755.            '.$email_head.'
  1756.            <body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
  1757.                <CopyRight>Copyright (c) 1996-2009 Constant Contact. All rights reserved.  Except as permitted under a separate written agreement with Constant Contact, neither the Constant Contact software, nor any content that appears on any Constant Contact site, including but not limited to, web pages, newsletters, or templates may be reproduced, republished, repurposed, or distributed without the prior written permission of Constant Contact.  For inquiries regarding reproduction or distribution of any Constant Contact material, please contact '.$email['EmailAddress'].'</CopyRight>
  1758.                <OpenTracking/>
  1759.                <CustomBlock name="letter.intro" title="Personalization">
  1760.                    <Greeting/>
  1761.                </CustomBlock>'.
  1762.         htmlentities2('<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%" id="backgroundTable">
  1763.                <tr>
  1764.                    <td align="center" valign="top">
  1765.                        <table border="0" cellpadding="10" cellspacing="0" width="600" id="templatePreheader">
  1766.                            <tr>
  1767.                                <td valign="top" class="preheaderContent">
  1768.                                    <table border="0" cellpadding="10" cellspacing="0" width="100%">
  1769.                                        <tr>
  1770.                                            <td valign="top">
  1771.                                                <div>
  1772.                                                     Use this area to offer a short teaser of your email content. Text here will show in the preview area of some email clients.
  1773.                                                </div>
  1774.                                            </td>
  1775.                                            <td valign="top" width="190">
  1776.                                                <div>
  1777.                                                    Is this email not displaying correctly?<br /><a href="*|ARCHIVE|*" target="_blank">View it in your browser</a>.
  1778.                                                </div>
  1779.                                            </td>
  1780.                                        </tr>
  1781.                                    </table>
  1782.                                </td>
  1783.                            </tr>
  1784.                        </table>
  1785.                        <table border="0" cellpadding="0" cellspacing="0" width="600" id="templateContainer">
  1786.                            <tr>
  1787.                                <td align="center" valign="top">
  1788.                                    <table border="0" cellpadding="0" cellspacing="0" width="600" id="templateHeader">
  1789.                                        <tr>
  1790.                                            <td class="headerContent">
  1791.                                                <img src="http://gallery.mailchimp.com/653153ae841fd11de66ad181a/images/placeholder_600.gif" style="max-width:600px;" id="headerImage campaign-icon" mc:label="header_image" mc:allowdesigner mc:allowtext />
  1792.                                            </td>
  1793.                                        </tr>
  1794.                                    </table>
  1795.                                </td>
  1796.                            </tr>
  1797.                            <tr>
  1798.                                <td align="center" valign="top">
  1799.                                    <table border="0" cellpadding="0" cellspacing="0" width="600" id="templateBody">
  1800.                                        <tr>
  1801.                                            <td valign="top" class="bodyContent">
  1802.                                                <table border="0" cellpadding="20" cellspacing="0" width="100%">
  1803.                                                    <tr>
  1804.                                                        <td valign="top">
  1805.                                                            <div>
  1806.                                                               '.$email_html.'
  1807.                                                            </div>
  1808.                                                        </td>
  1809.                                                    </tr>
  1810.                                                </table>
  1811.                                            </td>
  1812.                                        </tr>
  1813.                                    </table>
  1814.                                </td>
  1815.                            </tr>
  1816.                            <tr>
  1817.                                <td align="center" valign="top">
  1818.                                    <table border="0" cellpadding="10" cellspacing="0" width="600" id="templateFooter">
  1819.                                        <tr>
  1820.                                            <td valign="top" class="footerContent">
  1821.                                                <table border="0" cellpadding="10" cellspacing="0" width="100%">
  1822.                                                    <tr>
  1823.                                                        <td colspan="2" valign="middle" id="social">
  1824.                                                            <div>
  1825.                                                                &nbsp;<a href="*|TWITTER:PROFILEURL|*">follow on Twitter</a> | <a href="*|FACEBOOK:PROFILEURL|*">friend on Facebook</a> | <a href="*|FORWARD|*">forward to a friend</a>&nbsp;
  1826.                                                            </div>
  1827.                                                        </td>
  1828.                                                    </tr>
  1829.                                                    <tr>
  1830.                                                        <td valign="top" width="350">
  1831.                                                            <div>
  1832.                                                                <em>Copyright &copy; *|CURRENT_YEAR|* *|LIST:COMPANY|*, All rights reserved.</em>
  1833.                                                                <br />
  1834.                                                                *|IFNOT:ARCHIVE_PAGE|* *|LIST:DESCRIPTION|*
  1835.                                                                <br />
  1836.                                                                <strong>Our mailing address is:</strong>
  1837.                                                                <br />
  1838.                                                                *|HTML:LIST_ADDRESS_HTML|**|END:IF|*
  1839.                                                            </div>
  1840.                                                        </td>
  1841.                                                        <td valign="top" width="190" id="monkeyRewards">
  1842.                                                            <div>
  1843.                                                                *|IF:REWARDS|* *|HTML:REWARDS|* *|END:IF|*
  1844.                                                            </div>
  1845.                                                        </td>
  1846.                                                    </tr>
  1847.                                                    <tr>
  1848.                                                        <td colspan="2" valign="middle" id="utility">
  1849.                                                            <div>
  1850.                                                                &nbsp;<a href="*|UNSUB|*">unsubscribe from this list</a> | <a href="*|UPDATE_PROFILE|*">update subscription preferences</a>&nbsp;
  1851.                                                            </div>
  1852.                                                        </td>
  1853.                                                    </tr>
  1854.                                                </table>
  1855.                                            </td>
  1856.                                        </tr>
  1857.                                    </table>
  1858.                                </td>
  1859.                            </tr>
  1860.                        </table>
  1861.                        <br />
  1862.                    </td>
  1863.                </tr>
  1864.            </table>').'
  1865.            </body>
  1866.            </html>').'
  1867.        </EmailContent>
  1868.        <EmailTextContent>&lt;Text>'.esc_html($email_text).'&lt;/Text></EmailTextContent>
  1869.    ';
  1870.         if(is_array($contact_lists)):
  1871.             $xml_post  .= '<ContactLists>';
  1872.             foreach($contact_lists as $id):
  1873.                 $xml_post  .= '
  1874.                <ContactList id="'.$this->get_list_url($id).'">
  1875.                    <link xmlns="http://www.w3.org/2005/Atom" href="'.$this->get_list_url($id,0).'" rel="self" />
  1876.                </ContactList>
  1877.              ';
  1878.             endforeach;
  1879.             $xml_post .= '</ContactLists>';
  1880.         endif;
  1881.  
  1882.         } else {
  1883.             return false;
  1884.         }
  1885.  
  1886.         $xml_post .= '
  1887.        </Campaign>
  1888.    </content>
  1889.    <source>
  1890.        <id>'.$this->get_http_api_url().'campaigns</id>
  1891.        <title type="text">Campaigns for customer: '.$this->api_username.'</title>
  1892.        <link href="campaigns" />
  1893.        <link href="campaigns" rel="self" />
  1894.        <author>
  1895.          <name>'.$this->api_username.'</name>
  1896.        </author>
  1897.        <updated>'.date('Y').'-'.date('m').'-'.date('d').'T'.date('G').':'.date('i').':'.date('s').'.'.$offset.'Z</updated>
  1898.    </source>
  1899. </entry>';
  1900.  
  1901.         $this->http_set_content_type('application/atom+xml');
  1902.  
  1903.     #   die(htmlentities(print_r($xml_post, true)));
  1904.  
  1905.         $xml = $this->load_url("campaigns", 'post', trim(rtrim($xml_post)), 201);
  1906.  
  1907.     #   if(!is_admin()) {
  1908.            echo '<pre>';
  1909.             print_r($xml_post);
  1910.             print_r($xml);
  1911.             print_r($this);
  1912.             echo '</pre>';
  1913.     #   }
  1914.  
  1915.         if(isset($this->http_response_headers['Location']) && trim($this->http_response_headers['Location']) != ''):
  1916.             return $this->get_id_from_link($this->http_response_headers['Location']);
  1917.         endif;
  1918.  
  1919.         return false;
  1920.     }
  1921.  
  1922.  
  1923.  
  1924.     /**
  1925.      * This queries the API for campaigns with a certain status
  1926.      * Supported status codes are:
  1927.      * SENT          All campaigns that have been sent and not currently scheduled for resend
  1928.      * SCHEDULED     All campaigns that are currently scheduled to be sent some time in the future
  1929.      * DRAFT         All campaigns that have not yet been scheduled for delivery
  1930.      * RUNNING         All campaigns that are currently being processed and delivered
  1931.      *
  1932.      * @access     public
  1933.      */
  1934.     function query_campaigns($status = 'SENT')
  1935.     {
  1936.         $transient_title = 'cccam'.$status;
  1937.         $campaigns = constant_contact_get_transient($transient_title);
  1938.         if($campaigns && (!isset($_GET['refresh']) || $_GET['refresh'] !== 'campaigns')) { return maybe_unserialize($campaigns); }
  1939.  
  1940.         $xml = $this->load_url('campaigns?status=' . urlencode($status));
  1941.  
  1942.         if(!$xml):
  1943.             return false;
  1944.         endif;
  1945.  
  1946.         // parse into nicer array
  1947.         $campaigns = array();
  1948.         $_campaigns = (isset($xml['feed']['entry'])) ? $xml['feed']['entry'] : false;
  1949.  
  1950.         if(is_array($_campaigns)):
  1951.             if(isset($_campaigns[0]['link_attr']['href'])):
  1952.                 foreach($_campaigns as $k => $v):
  1953.                     $id = $this->get_id_from_link($v['link_attr']['href']);
  1954.                     $campaign = $v['content']['Campaign'];
  1955.                     $campaign['id'] = $id;
  1956.                     $campaigns[] = $campaign;
  1957.                 endforeach;
  1958.             else:
  1959.                 $id = $this->get_id_from_link($_campaigns['link_attr']['href']);
  1960.                 $campaign = $_campaigns['content']['Campaign'];
  1961.                 $campaign['id'] = $id;
  1962.                 $campaigns[] = $campaign;
  1963.             endif;
  1964.         endif;
  1965.  
  1966.         constant_contact_set_transient($transient_title, maybe_serialize($campaigns), 60*60*6);
  1967.  
  1968.         return $campaigns;
  1969.     }
  1970.  
  1971.  
  1972.     /**
  1973.      * Gets all account email addresses or a single email
  1974.      * These are used with the campaigns collection
  1975.      *
  1976.      * @access     public
  1977.      */
  1978.     function get_emails($return_email = '')
  1979.     {
  1980.         $xml = $this->load_url("settings/emailaddresses");
  1981.  
  1982.         if(!$xml):
  1983.             return false;
  1984.         endif;
  1985.  
  1986.         // parse into nicer array
  1987.         $emails = array();
  1988.         $_emails = (isset($xml['feed']['entry'])) ? $xml['feed']['entry'] : false;
  1989.  
  1990.         if(is_array($_emails)):
  1991.             if(isset($_emails[0]['link_attr']['href'])):
  1992.                 foreach($_emails as $k => $v):
  1993.                     $id = $this->get_id_from_link($v['link_attr']['href']);
  1994.                     $email = $v['content']['Email'];
  1995.                     $email['id'] = $id;
  1996.  
  1997.                     if($return_email && $return_email == $v['content']['Email']['EmailAddress']):
  1998.                         // return single email
  1999.                         return $email;
  2000.                     endif;
  2001.  
  2002.                     $emails[] = $email;
  2003.                 endforeach;
  2004.             else:
  2005.                 $id = $this->get_id_from_link($_emails['link_attr']['href']);
  2006.                 $email = $_emails['content']['Email'];
  2007.                 $email['id'] = $id;
  2008.                 $emails[] = $email;
  2009.  
  2010.                 if($return_email && $return_email == $_emails['content']['Email']['EmailAddress']):
  2011.                     // return single email
  2012.                     return $email;
  2013.                 endif;
  2014.             endif;
  2015.  
  2016.         endif;
  2017.  
  2018.         return $emails;
  2019.     }
  2020.  
  2021.  
  2022.     /**
  2023.      * Converts a timestamp that is in the format 2008-08-05T16:50:04.534Z to a UNIX timestamp
  2024.      *
  2025.      *
  2026.      * @access     public
  2027.      */
  2028.     function convert_timestamp($timestamp)
  2029.     {
  2030.         $timestamp_bits = explode('T', $timestamp);
  2031.  
  2032.         if(isset($timestamp_bits[0], $timestamp_bits[0])):
  2033.             $date_bits = explode('-', $timestamp_bits[0]);
  2034.             $time_bits = explode(':', $timestamp_bits[1]);
  2035.  
  2036.             $year = (int) $date_bits[0];
  2037.             if($year < 1900) { $year = date('Y'); } // The year was showing 111
  2038.             $month = (int) $date_bits[1];
  2039.             $day = (int) $date_bits[2];
  2040.             $hour = (int) $time_bits[0];
  2041.             $minute = (int) $time_bits[1];
  2042.             $second = (int) $time_bits[2];
  2043.  
  2044.           return mktime($hour, $minute, $second, $month, $day, $year);
  2045.         endif;
  2046.  
  2047.         return false;
  2048.  
  2049.     }
  2050.  
  2051.  
  2052.     /**
  2053.      * Method other methods call to get the unique ID of the resource
  2054.      * Unique ID's are used to identify a specific resource such as a contact or contact list and are passed as arguments to some of the methods
  2055.      * This is also used to get just the last piece of the URL in other functions eg. get_lists()
  2056.      *
  2057.      * @access     public
  2058.      */
  2059.     function get_id_from_link($link)
  2060.     {
  2061.         $link_bits = explode('/', $link);
  2062.         return $link_bits[(count($link_bits)-1)];
  2063.     }
  2064.  
  2065.  
  2066.     /**
  2067.      * This method will convert a string comtaining XML into a nicely formatted PHP array
  2068.      *
  2069.      * @access     private
  2070.      */
  2071.     function xml_to_array($contents, $get_attributes=1, $priority = 'tag') {
  2072.         if(!$contents) return array();
  2073.  
  2074.         if(!function_exists('xml_parser_create')) {
  2075.             trigger_error("XML not supported: " .
  2076.                           "http://www.php.net/manual/en/ref.xml.php", E_USER_ERROR);
  2077.             return array();
  2078.         }
  2079.         $output_encoding = 'ISO-8859-1';
  2080.         $input_encoding = NULL;
  2081.         $detect_encoding = true;
  2082.  
  2083.         list($parser, $source) = $this->xml_create_parser($contents,
  2084.                 $output_encoding, $input_encoding, $detect_encoding);
  2085.  
  2086.  
  2087.         if (!is_resource($parser))
  2088.         {
  2089.             trigger_error("Failed to create an instance of PHP's XML parser. " .
  2090.                           "http://www.php.net/manual/en/ref.xml.php", E_USER_ERROR);
  2091.         }
  2092.  
  2093.         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
  2094.         xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
  2095.         xml_parse_into_struct($parser, trim($contents), $xml_values);
  2096.         xml_parser_free($parser);
  2097.  
  2098.         if(!$xml_values) return;//Hmm...
  2099.  
  2100.         //Initializations
  2101.         $xml_array = array();
  2102.         $parents = array();
  2103.         $opened_tags = array();
  2104.         $arr = array();
  2105.  
  2106.         $current = &$xml_array; //Refference
  2107.  
  2108.         //Go through the tags.
  2109.         $repeated_tag_index = array();//Multiple tags with same name will be turned into an array
  2110.         foreach($xml_values as $data) {
  2111.             unset($attributes,$value);//Remove existing values, or there will be trouble
  2112.  
  2113.             //This command will extract these variables into the foreach scope
  2114.             // tag(string), type(string), level(int), attributes(array).
  2115.             extract($data);//We could use the array by itself, but this cooler.
  2116.  
  2117.             $result = array();
  2118.             $attributes_data = array();
  2119.  
  2120.             if(isset($value)) {
  2121.                 if($priority == 'tag') $result = $value;
  2122.                 else $result['value'] = $value; //Put the value in a assoc array if we are in the 'Attribute' mode
  2123.             }
  2124.  
  2125.             //Set the attributes too.
  2126.             if(isset($attributes) and $get_attributes) {
  2127.                 foreach($attributes as $attr => $val) {
  2128.                     if($priority == 'tag') $attributes_data[$attr] = $val;
  2129.                     else $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
  2130.                 }
  2131.             }
  2132.  
  2133.             //See tag status and do the needed.
  2134.             if($type == "open") {//The starting of the tag '<tag>'
  2135.                 $parent[$level-1] = &$current;
  2136.                 if(!is_array($current) or (!in_array($tag, array_keys($current)))) { //Insert New tag
  2137.                     if(!is_array($current)) { $current = array(); } // Added in 2.3
  2138.                     $current[$tag] = $result;
  2139.                     if($attributes_data) $current[$tag. '_attr'] = $attributes_data;
  2140.                     $repeated_tag_index[$tag.'_'.$level] = 1;
  2141.  
  2142.                     $current = &$current[$tag];
  2143.  
  2144.                 } else { //There was another element with the same tag name
  2145.  
  2146.                     if(isset($current[$tag][0])) {//If there is a 0th element it is already an array
  2147.                         $current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;
  2148.                         $repeated_tag_index[$tag.'_'.$level]++;
  2149.                     } else {//This section will make the value an array if multiple tags with the same name appear together
  2150.                         $current[$tag] = array($current[$tag],$result);//This will combine the existing item and the new item together to make an array
  2151.                         $repeated_tag_index[$tag.'_'.$level] = 2;
  2152.  
  2153.                         if(isset($current[$tag.'_attr'])) { //The attribute of the last(0th) tag must be moved as well
  2154.                             $current[$tag]['0_attr'] = $current[$tag.'_attr'];
  2155.                             unset($current[$tag.'_attr']);
  2156.                         }
  2157.  
  2158.                     }
  2159.                     $last_item_index = $repeated_tag_index[$tag.'_'.$level]-1;
  2160.                     $current = &$current[$tag][$last_item_index];
  2161.                 }
  2162.  
  2163.             } elseif($type == "complete") { //Tags that ends in 1 line '<tag />'
  2164.                 //See if the key is already taken.
  2165.                 if(!isset($current[$tag])) { //New Key
  2166.                     $current[$tag] = $result;
  2167.                     $repeated_tag_index[$tag.'_'.$level] = 1;
  2168.                     if($priority == 'tag' and $attributes_data) $current[$tag. '_attr'] = $attributes_data;
  2169.  
  2170.                 } else { //If taken, put all things inside a list(array)
  2171.                     if(isset($current[$tag][0]) and is_array($current[$tag])) {//If it is already an array...
  2172.  
  2173.                         // ...push the new element into that array.
  2174.                         $current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;
  2175.  
  2176.                         if($priority == 'tag' and $get_attributes and $attributes_data) {
  2177.                             $current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
  2178.                         }
  2179.                         $repeated_tag_index[$tag.'_'.$level]++;
  2180.  
  2181.                     } else { //If it is not an array...
  2182.                         $current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value
  2183.                         $repeated_tag_index[$tag.'_'.$level] = 1;
  2184.                         if($priority == 'tag' and $get_attributes) {
  2185.                             if(isset($current[$tag.'_attr'])) { //The attribute of the last(0th) tag must be moved as well
  2186.  
  2187.                                 $current[$tag]['0_attr'] = $current[$tag.'_attr'];
  2188.                                 unset($current[$tag.'_attr']);
  2189.                             }
  2190.  
  2191.                             if($attributes_data) {
  2192.                                 $current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
  2193.                             }
  2194.                         }
  2195.                         $repeated_tag_index[$tag.'_'.$level]++; //0 and 1 index is already taken
  2196.                     }
  2197.                 }
  2198.  
  2199.             } elseif($type == 'close') { //End of tag '</tag>'
  2200.                 $current = &$parent[$level-1];
  2201.             }
  2202.         }
  2203.  
  2204.         return($xml_array);
  2205.     }
  2206.  
  2207.  
  2208.     /**
  2209.      * Return XML parser, and possibly re-encoded source
  2210.      *
  2211.      * @access     private
  2212.      */
  2213.     function xml_create_parser($source, $out_enc, $in_enc, $detect)
  2214.     {
  2215.         if ( substr(phpversion(),0,1) == 5) {
  2216.             $parser = $this->xml_php5_create_parser($in_enc, $detect);
  2217.         }
  2218.         else {
  2219.             list($parser, $source) = $this->xml_php4_create_parser($source, $in_enc, $detect);
  2220.         }
  2221.         if ($out_enc) {
  2222.             $this->xml_encoding = $out_enc;
  2223.             xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc);
  2224.         }
  2225.  
  2226.         return array($parser, $source);
  2227.     }
  2228.  
  2229.     /**
  2230.      * Instantiate an XML parser under PHP5
  2231.      *
  2232.      * PHP5 will do a fine job of detecting input encoding
  2233.      * if passed an empty string as the encoding.
  2234.      *
  2235.      * @access     private
  2236.      */
  2237.     function xml_php5_create_parser($in_enc, $detect)
  2238.     {
  2239.         // by default php5 does a fine job of detecting input encodings
  2240.         if(!$detect && $in_enc) {
  2241.             return xml_parser_create($in_enc);
  2242.         }
  2243.         else {
  2244.             return xml_parser_create('');
  2245.         }
  2246.     }
  2247.  
  2248.     /**
  2249.      * Instaniate an XML parser under PHP4
  2250.      *
  2251.      * Unfortunately PHP4's support for character encodings
  2252.      * and especially XML and character encodings sucks.  As
  2253.      * long as the documents you parse only contain characters
  2254.      * from the ISO-8859-1 character set (a superset of ASCII,
  2255.      * and a subset of UTF-8) you're fine.  However once you
  2256.      * step out of that comfy little world things get mad, bad,
  2257.      * and dangerous to know.
  2258.      *
  2259.      * The following code is based on SJM's work with FoF
  2260.      * @link http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
  2261.      * if passed an empty string as the encoding.
  2262.      *
  2263.      * @access     private
  2264.      */
  2265.     function xml_php4_create_parser($source, $in_enc, $detect) {
  2266.         if ( !$detect ) {
  2267.             return array(xml_parser_create($in_enc), $source);
  2268.         }
  2269.  
  2270.         if (!$in_enc) {
  2271.             if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $source, $m)) {
  2272.                 $in_enc = strtoupper($m[1]);
  2273.                 $this->xml_source_encoding = $in_enc;
  2274.             }
  2275.             else {
  2276.                 $in_enc = 'UTF-8';
  2277.             }
  2278.         }
  2279.  
  2280.         if ($this->xml_known_encoding($in_enc)) {
  2281.             return array(xml_parser_create($in_enc), $source);
  2282.         }
  2283.  
  2284.         // the dectected encoding is not one of the simple encodings PHP knows
  2285.  
  2286.         // attempt to use the iconv extension to
  2287.         // cast the XML to a known encoding
  2288.         // @link http://php.net/iconv
  2289.         if (function_exists('iconv'))  {
  2290.             $encoded_source = iconv($in_enc,'UTF-8', $source);
  2291.             if ($encoded_source) {
  2292.                 return array(xml_parser_create('UTF-8'), $encoded_source);
  2293.             }
  2294.         }
  2295.  
  2296.         // iconv didn't work, try mb_convert_encoding
  2297.         // @link http://php.net/mbstring
  2298.         if(function_exists('mb_convert_encoding')) {
  2299.             $encoded_source = mb_convert_encoding($source, 'UTF-8', $in_enc );
  2300.             if ($encoded_source) {
  2301.                 return array(xml_parser_create('UTF-8'), $encoded_source);
  2302.             }
  2303.         }
  2304.  
  2305.         // else
  2306.         trigger_error("Feed is in an unsupported character encoding. ($in_enc) " .
  2307.                      "You may see strange artifacts, and mangled characters.", E_USER_ERROR);
  2308.     }
  2309.  
  2310.     /**
  2311.      * Checks if the given encoding is one of the known encodings
  2312.      *
  2313.      *
  2314.      * @access     private
  2315.      */
  2316.     function xml_known_encoding($enc)
  2317.     {
  2318.         $enc = strtoupper($enc);
  2319.         if ( in_array($enc, $this->xml_known_encodings) ) {
  2320.             return $enc;
  2321.         }
  2322.         else {
  2323.             return false;
  2324.         }
  2325.     }
  2326.  
  2327.  
  2328.     /**
  2329.      * Loads a specific URL, this method is used by the user friendly methods
  2330.      *
  2331.      */
  2332.     function load_url($action = '', $method = 'get', $params = array(), $expected_http_code = 200)
  2333.     {
  2334.  
  2335.         $this->http_send($this->api_url . $action, $method, $params);
  2336.  
  2337.         // handle status codes
  2338.         if(floatval($expected_http_code) === floatval($this->http_response_code)) {
  2339.             if($this->http_content_type) {
  2340.                 return $this->xml_to_array($this->http_response_body);
  2341.             } else {
  2342.                 return $this->http_response_body; /* downloads the file */
  2343.             }
  2344.         } else {
  2345.             $this->last_error  = "Invalid status code {$this->http_response_code}";
  2346.  
  2347.             // if their was an error sometimes the body contains useful info
  2348.             return false;
  2349.         }
  2350.     }
  2351.  
  2352.  
  2353.     /**
  2354.      * All methods below are prefixed with http_
  2355.      * These are all used to communicate with the CC server over HTTPS
  2356.      *
  2357.      */
  2358.  
  2359.  
  2360.     /**
  2361.      * Sets the Content-Type header value used for all HTTP requests
  2362.      *
  2363.      * @access     private
  2364.      */
  2365.     function http_set_content_type($content_type)
  2366.     {
  2367.         $this->http_content_type = $content_type;
  2368.     }
  2369.  
  2370.     /**
  2371.      * Simple method which calls PHP's @see parse_url function and saves the result to a variable
  2372.      *
  2373.      *
  2374.      * @access     private
  2375.      */
  2376.     function http_parse_request_url($url) {
  2377.         $this->http_url_bits = parse_url($url);
  2378.     }
  2379.  
  2380.  
  2381.     /**
  2382.      * This method adds the necessary HTTP auth headers to communicate with the API
  2383.      *
  2384.      *
  2385.      * @access     private
  2386.      */
  2387.     function http_auth_headers() {
  2388.         if($this->http_user || $this->http_pass):
  2389.             $this->http_headers_add('Authorization', " Basic ".base64_encode($this->http_user . ":" . $this->http_pass));
  2390.         endif;
  2391.     }
  2392.  
  2393.  
  2394.     /**
  2395.      * This method takes care of escaping the values sent with the http request
  2396.      *
  2397.      * @param    array        An array of params to escape
  2398.      * @param    array        The HTTP method eg. GET
  2399.      *
  2400.      * @access     private
  2401.      */
  2402.     function http_serialize_params($params) {
  2403.         $query_string = array();
  2404.         if(is_array($params)):
  2405.             foreach($params as $key => $value):
  2406.                 if(is_array($value)):
  2407.                     foreach($value as $k => $fieldvalue):
  2408.                         $query_string[] = urlencode($key) . '=' . rawurlencode($fieldvalue);
  2409.                     endforeach;
  2410.                 else:
  2411.                     $query_string[] = urlencode($key) . '=' . rawurlencode($value);
  2412.                 endif;
  2413.             endforeach;
  2414.         else:
  2415.             return $params;
  2416.         endif;
  2417.         return implode('&', $query_string);
  2418.     }
  2419.  
  2420.  
  2421.  
  2422.     /**
  2423.      * This does most the work of creating the HTTP request
  2424.      *
  2425.      * @param    string        The path of the resource to request eg. /index.php
  2426.      * @param    string        The method to use to make the request eg. GET
  2427.      * @param    array        An array of params to use for this HTTP request, eg. post data
  2428.      * @param    array        An array of additional HTTP headers to send along with the request
  2429.      *
  2430.      * @access     private
  2431.      */
  2432.     function http_send($path, $method, $params = array(), $headers = array())
  2433.     {
  2434.         $this->http_response = '';
  2435.         $this->http_response_code = '';
  2436.         $this->http_method = $method;
  2437.         $this->http_parse_request_url($path);
  2438.         $this->http_headers_merge($headers);
  2439.  
  2440.         if(is_array($params)):
  2441.             $params = $this->http_serialize_params($params);
  2442.         endif;
  2443.  
  2444.         $method = strtoupper($method);
  2445.  
  2446.         $the_host = $this->http_url_bits['host'];
  2447.         $the_path = (isset($this->http_url_bits['path'])&&trim($this->http_url_bits['path'])!='') ? $this->http_url_bits['path'] : '';
  2448.         $the_path .= (isset($this->http_url_bits['query'])&&trim($this->http_url_bits['query'])!='') ? '?'.$this->http_url_bits['query'] : '';
  2449.  
  2450.         $this->http_headers_add('', "$method $the_path HTTP/1.1");
  2451.         $this->http_headers_add('Host', $the_host);
  2452.  
  2453.         if($this->http_content_type) {
  2454.             $this->http_headers_add('Content-Type', $this->http_content_type);
  2455.         }
  2456.  
  2457.         $this->http_headers_add('User-Agent', $this->http_user_agent);
  2458.         $this->http_headers_add('Content-Length', strlen($params));
  2459.         $this->http_headers_add('Accept', 'application/atom+xml'); // Added in 2.1 for Events marketing
  2460.  
  2461.         $request = $this->http_build_request_headers();
  2462.  
  2463.         $body = '';
  2464.         if(trim($params) != ''):
  2465.             $body = "$params{$this->http_linebreak}";
  2466.         endif;
  2467.  
  2468.         $this->http_request = $request;
  2469.  
  2470.     /*
  2471.         if($this->http_url_bits['scheme']=='https'):
  2472.             $url = "https://$the_host";
  2473.         else:
  2474.             $url = "http://$the_host";
  2475.         endif;
  2476.     */
  2477.  
  2478.         $url = "https://$the_host";
  2479.  
  2480.         $args = array(
  2481.             'body' => $body,
  2482.             'headers'=> $request,
  2483.             'method' => strtoupper($method), // GET, POST, PUT, DELETE, etc.
  2484.             'sslverify' => false,
  2485.             'timeout' => $this->http_request_timeout,
  2486.             'httpversion' => '1.1'
  2487.         );
  2488.  
  2489.         $response = wp_remote_request($url.$the_path, $args);
  2490.  
  2491.         global $cc_responses;
  2492.         $cc_responses[] = array('url' => $url.$the_path, 'args' => $args, 'response' => $response);
  2493.  
  2494.         if($response && !is_wp_error($response)) {
  2495.             $this->http_response = $response;
  2496.             $this->http_parse_response();
  2497.             return true;
  2498.         } elseif(is_wp_error($response)) {
  2499.             $this->last_error = $response->get_error_message();
  2500.         }
  2501.         return false;
  2502.     }
  2503.  
  2504.  
  2505.     /**
  2506.      * determine if a string can represent a number in hexadecimal
  2507.      *
  2508.      * @param string $hex
  2509.      * @return boolean true if the string is a hex, otherwise false
  2510.      */
  2511.     function is_hex($hex) {
  2512.         // regex is for weenies
  2513.         $hex = strtolower(trim(ltrim($hex,"0")));
  2514.         if (empty($hex)) { $hex = 0; };
  2515.         $dec = hexdec($hex);
  2516.         return ($hex == dechex($dec));
  2517.     }
  2518.  
  2519.     /**
  2520.      * This method calls other methods
  2521.      * It is mainly here so we can do everything in the correct order, according to HTTP spec
  2522.      *
  2523.      * @return    string        A string containing the entire HTTP request
  2524.      *
  2525.      * @access     private
  2526.      */
  2527.     function http_build_request_headers()
  2528.     {
  2529.         $this->http_auth_headers();
  2530.         $this->http_headers_add('Connection', "Close{$this->http_linebreak}");
  2531.         $request = $this->http_headers_to_s($this->http_request_headers);
  2532.         $this->http_request_headers = array();
  2533.         return $request;
  2534.     }
  2535.  
  2536.  
  2537.     /**
  2538.      * This method parses the raw http response into local variables we use later on
  2539.      *
  2540.      *
  2541.      * @access     private
  2542.      */
  2543.     function http_parse_response()
  2544.     {
  2545.         if(empty($this->http_response)) { return false; }
  2546.         $headers = wp_remote_retrieve_headers($this->http_response);
  2547.  
  2548.         foreach($headers as $header => $value) {
  2549.             if(is_string($value)) { $value = trim($value); }
  2550.             $this->http_response_headers[$header] = $value;
  2551.         }
  2552.  
  2553.         $this->http_response_body = $body = wp_remote_retrieve_body($this->http_response);
  2554.         $this->http_response_code = wp_remote_retrieve_response_code($this->http_response);
  2555.  
  2556.         $this->http_set_content_type($this->http_default_content_type);
  2557.     }
  2558.  
  2559.  
  2560.     /**
  2561.      * This method converts an array of request headers into a correctly formatted HTTP request header
  2562.      *
  2563.      * @param    array        The array of headers to convert
  2564.      * @return    string        A string that can be used within an HTTP request
  2565.      *
  2566.      * @access     private
  2567.      */
  2568.     function http_headers_to_s($headers) {
  2569.         $string = '';
  2570.         if(is_array($headers)):
  2571.             foreach ($headers as $header => $value) {
  2572.                 if(trim($header) != '' && !is_numeric($header)):
  2573.                     $string .= "$header: $value{$this->http_linebreak}";
  2574.                 else:
  2575.                     $string .= "$value{$this->http_linebreak}";
  2576.                 endif;
  2577.             }
  2578.         endif;
  2579.         return $string;
  2580.     }
  2581.  
  2582.  
  2583.     /**
  2584.      * This method allows us to add a specific header to the @see $http_request_headers array
  2585.      *
  2586.      * @param    string        The name of the header to add
  2587.      * @param    string        The value of the header to add
  2588.      *
  2589.      * @access     private
  2590.      */
  2591.     function http_headers_add($header, $value) {
  2592.         if(trim($header) != '' && !is_numeric($header)):
  2593.             $this->http_request_headers[$header] = $value;
  2594.         else:
  2595.             $this->http_request_headers[] = $value;
  2596.         endif;
  2597.     }
  2598.  
  2599.  
  2600.     /**
  2601.      * This merges the given array with the @see $http_request_headers array
  2602.      *
  2603.      * @param    array        The associative array of headers to merge
  2604.      *
  2605.      * @access     private
  2606.      */
  2607.     function http_headers_merge($headers) {
  2608.         $this->http_request_headers = array_merge($this->http_request_headers, $headers);
  2609.     }
  2610.  
  2611.  
  2612.  
  2613.     /**
  2614.      * This gets a specific request header from the @see $http_request_headers array
  2615.      *
  2616.      * @param    string        The name of the header to retrieve
  2617.      *
  2618.      * @access     private
  2619.      */
  2620.     function http_headers_get($header) {
  2621.         return $this->http_request_headers[$header];
  2622.     }
  2623.  
  2624.  
  2625.     /**
  2626.      * This gets the response code of the last HTTP request
  2627.      *
  2628.      * @return    int        The response code, eg. 200
  2629.      *
  2630.      * @access     private
  2631.      */
  2632.     function http_headers_get_response_code() {
  2633.         return $this->http_response_code;
  2634.     }
  2635.  
  2636.  
  2637.     /**
  2638.      * Parses the response headers and response code into a readable format
  2639.      *
  2640.      * @param    array    An associative array of headers to include in the HTTP request
  2641.      *
  2642.      * @access     private
  2643.      */
  2644.     function http_parse_headers($headers) {
  2645.         $replace = ($this->http_linebreak == "\n" ? "\r\n" : "\n");
  2646.         $headers = str_replace($replace, $this->http_linebreak, trim($headers));
  2647.         $headers = explode($this->http_linebreak, $headers);
  2648.         $this->http_response_headers = array();
  2649.         if (preg_match('/^HTTP\/\d\.\d (\d{3})/', $headers[0], $matches)) {
  2650.           $this->http_response_code = intval($matches[1]);
  2651.           array_shift($headers);
  2652.         }
  2653.         if($headers):
  2654.             foreach ($headers as $string) {
  2655.               list($header, $value) = explode(': ', $string, 2);
  2656.               $this->http_response_headers[$header] = trim($value);
  2657.             }
  2658.         endif;
  2659.     }
  2660.  
  2661.  
  2662.  
  2663.     /**
  2664.      * Returns a friendly error message for the given HTTP status error code
  2665.      * This can be used to better understand a status code returned by the API
  2666.      *
  2667.      *
  2668.      * @access     private
  2669.      */
  2670.     function http_get_response_code_error($code = '')
  2671.     {
  2672.  
  2673.         if(empty($code)) { return ''; }
  2674.  
  2675.         $errors = array(
  2676.             200 => __('<strong>Success</strong> - The request was successful', 'constant-contact-api'),
  2677.             201 => __('<strong>Created (Success)</strong> - The request was successful. The requested object/resource was created.', 'constant-contact-api'),
  2678.             400 => __('<p><strong>Invalid Request (400)</strong></p><p>There are many possible causes for this error, but most commonly there is a problem with the structure or content of XML your application provided. Please <a href="http://wordpress.org/tags/constant-contact-api?forum_id=10">Let the plugin developers know about the issue</a>, and make sure to mention what you were doing when you got this error.</p>', 'constant-contact-api'),
  2679.             401 => __('<p><strong>This plugin is not configured with a valid Constant Contact account.</strong></p>
  2680.                    <p>Please enter a valid username and password then press the Save Changes button before continuing.</p>', 'constant-contact-api'),
  2681.             403 => __('<p><strong>The Constant Contact account has been locked.</strong></p>
  2682.                    <p>User account is locked due to too many bad login attempts. Please reset <a href="http://katz.si/6d">follow these instructions to reset account access</a>.</p>', 'constant-contact-api'),
  2683.             404 => __('<p><strong>URL Not Found (404)</strong></p> <p>The URI which was provided was incorrect.  Please <a href="http://wordpress.org/tags/constant-contact-api?forum_id=10">Let the plugin developers know about the issue</a>, and make sure to mention what you were doing when you got this error.</p>', 'constant-contact-api'),
  2684.             409 => __('<p><strong>Conflict (409)</strong></p><p>There is a problem with the action you are trying to perform. Commonly, you are trying to "Create" (POST) a resource which already exists such as a Contact List or Email Address that already exists. In general, if a resource already exists, an application can "Update" the resource with a "PUT" request for that resource.</p>', 'constant-contact-api'),
  2685.             415 => __('<p><strong>Unsupported Media Type (415)</strong></p><p>The Media Type (Content Type) of the data you are sending does not match the expected Content Type for the specific action you are performing on the specific Resource you are acting on. Please <a href="http://wordpress.org/tags/constant-contact-api?forum_id=10">Let the plugin developers know about the issue</a>, and make sure to mention what you were doing when you got this error.</p>', 'constant-contact-api'),
  2686.             500  => __('<p><strong>Server Error (500)</strong></p><p>Constant Contact is likely having server issues. Even though it is likely a Constant Contact issue, please <a href="http://wordpress.org/tags/constant-contact-api?forum_id=10">Let the plugin developers know about the issue</a>, and make sure to mention what you were doing when you got this error.</p>', 'constant-contact-api'),
  2687.         );
  2688.  
  2689.         if(array_key_exists($code, $errors)):
  2690.             return $errors[$code];
  2691.         endif;
  2692.  
  2693.         return '';
  2694.     }
  2695. // ENDOF CLASS
  2696. }
Add Comment
Please, Sign In to add comment