Problems, need help? Have a tip or advice? Post it here.
6 posts Page 1 of 1
Greetings!!!

I am trying to integrate MailChimp into a site for newsletter signup. But I am getting the following error:
mailchimp.png
mailchimp.png (98.5 KiB) Viewed 45692 times


I have followed the tutorial @ viewtopic.php?f=8&t=7384

This is the code I am Using:

MailChimp.php
Code: Select all
<?php

namespace DrewM\MailChimp;

/**
* Super-simple, minimum abstraction MailChimp API v3 wrapper
* MailChimp API v3: http://developer.mailchimp.com
* This wrapper: https://github.com/drewm/mailchimp-api
*
* @author Drew McLellan <drew.mclellan@gmail.com>
* @version 2.2
*/
class MailChimp
{
    private $api_key;
    private $api_endpoint = 'https://<dc>.api.mailchimp.com/3.0';

    const TIMEOUT = 10;

    /*  SSL Verification
        Read before disabling:
        http://snippets.webaware.com.au/howto/stop-turning-off-curlopt_ssl_verifypeer-and-fix-your-php-config/
    */
    public $verify_ssl = true;

    private $request_successful = false;
    private $last_error         = '';
    private $last_response      = array();
    private $last_request       = array();

    /**
     * Create a new instance
     * @param string $api_key Your MailChimp API key
     * @param string $api_endpoint Optional custom API endpoint
     * @throws \Exception
     */
    public function __construct($api_key, $api_endpoint = null)
    {
        $this->api_key = $api_key;
       
        if ($api_endpoint === null) {
            if (strpos($this->api_key, '-') === false) {
                throw new \Exception("Invalid MailChimp API key `{$api_key}` supplied.");
            }
            list(, $data_center) = explode('-', $this->api_key);
            $this->api_endpoint  = str_replace('<dc>', $data_center, $this->api_endpoint);
        } else {
            $this->api_endpoint  = $api_endpoint;
        }

        $this->last_response = array('headers' => null, 'body' => null);
    }

    /**
     * Create a new instance of a Batch request. Optionally with the ID of an existing batch.
     * @param string $batch_id Optional ID of an existing batch, if you need to check its status for example.
     * @return Batch            New Batch object.
     */
    public function new_batch($batch_id = null)
    {
        return new Batch($this, $batch_id);
    }

    /**
     * Convert an email address into a 'subscriber hash' for identifying the subscriber in a method URL
     * @param   string $email The subscriber's email address
     * @return  string          Hashed version of the input
     */
    public function subscriberHash($email)
    {
        return md5(strtolower($email));
    }

    /**
     * Was the last request successful?
     * @return bool  True for success, false for failure
     */
    public function success()
    {
        return $this->request_successful;
    }

    /**
     * Get the last error returned by either the network transport, or by the API.
     * If something didn't work, this should contain the string describing the problem.
     * @return  array|false  describing the error
     */
    public function getLastError()
    {
        return $this->last_error ?: false;
    }

    /**
     * Get an array containing the HTTP headers and the body of the API response.
     * @return array  Assoc array with keys 'headers' and 'body'
     */
    public function getLastResponse()
    {
        return $this->last_response;
    }

    /**
     * Get an array containing the HTTP headers and the body of the API request.
     * @return array  Assoc array
     */
    public function getLastRequest()
    {
        return $this->last_request;
    }

    /**
     * Make an HTTP DELETE request - for deleting data
     * @param   string $method URL of the API request method
     * @param   array $args Assoc array of arguments (if any)
     * @param   int $timeout Timeout limit for request in seconds
     * @return  array|false   Assoc array of API response, decoded from JSON
     */
    public function delete($method, $args = array(), $timeout = self::TIMEOUT)
    {
        return $this->makeRequest('delete', $method, $args, $timeout);
    }

    /**
     * Make an HTTP GET request - for retrieving data
     * @param   string $method URL of the API request method
     * @param   array $args Assoc array of arguments (usually your data)
     * @param   int $timeout Timeout limit for request in seconds
     * @return  array|false   Assoc array of API response, decoded from JSON
     */
    public function get($method, $args = array(), $timeout = self::TIMEOUT)
    {
        return $this->makeRequest('get', $method, $args, $timeout);
    }

    /**
     * Make an HTTP PATCH request - for performing partial updates
     * @param   string $method URL of the API request method
     * @param   array $args Assoc array of arguments (usually your data)
     * @param   int $timeout Timeout limit for request in seconds
     * @return  array|false   Assoc array of API response, decoded from JSON
     */
    public function patch($method, $args = array(), $timeout = self::TIMEOUT)
    {
        return $this->makeRequest('patch', $method, $args, $timeout);
    }

    /**
     * Make an HTTP POST request - for creating and updating items
     * @param   string $method URL of the API request method
     * @param   array $args Assoc array of arguments (usually your data)
     * @param   int $timeout Timeout limit for request in seconds
     * @return  array|false   Assoc array of API response, decoded from JSON
     */
    public function post($method, $args = array(), $timeout = self::TIMEOUT)
    {
        return $this->makeRequest('post', $method, $args, $timeout);
    }

    /**
     * Make an HTTP PUT request - for creating new items
     * @param   string $method URL of the API request method
     * @param   array $args Assoc array of arguments (usually your data)
     * @param   int $timeout Timeout limit for request in seconds
     * @return  array|false   Assoc array of API response, decoded from JSON
     */
    public function put($method, $args = array(), $timeout = self::TIMEOUT)
    {
        return $this->makeRequest('put', $method, $args, $timeout);
    }

    /**
     * Performs the underlying HTTP request. Not very exciting.
     * @param  string $http_verb The HTTP verb to use: get, post, put, patch, delete
     * @param  string $method The API method to be called
     * @param  array $args Assoc array of parameters to be passed
     * @param int $timeout
     * @return array|false Assoc array of decoded result
     * @throws \Exception
     */
    private function makeRequest($http_verb, $method, $args = array(), $timeout = self::TIMEOUT)
    {
        if (!function_exists('curl_init') || !function_exists('curl_setopt')) {
            throw new \Exception("cURL support is required, but can't be found.");
        }

        $url = $this->api_endpoint . '/' . $method;

        $this->last_error = '';
        $this->request_successful = false;
        $response = array(
            'headers'     => null, // array of details from curl_getinfo()
            'httpHeaders' => null, // array of HTTP headers
            'body'        => null // content of the response
        );
        $this->last_response = $response;

        $this->last_request = array(
            'method'  => $http_verb,
            'path'    => $method,
            'url'     => $url,
            'body'    => '',
            'timeout' => $timeout,
        );

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Accept: application/vnd.api+json',
            'Content-Type: application/vnd.api+json',
            'Authorization: apikey ' . $this->api_key
        ));
        curl_setopt($ch, CURLOPT_USERAGENT, 'DrewM/MailChimp-API/3.0 (github.com/drewm/mailchimp-api)');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_VERBOSE, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->verify_ssl);
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($ch, CURLOPT_ENCODING, '');
        curl_setopt($ch, CURLINFO_HEADER_OUT, true);

        switch ($http_verb) {
            case 'post':
                curl_setopt($ch, CURLOPT_POST, true);
                $this->attachRequestPayload($ch, $args);
                break;

            case 'get':
                $query = http_build_query($args, '', '&');
                curl_setopt($ch, CURLOPT_URL, $url . '?' . $query);
                break;

            case 'delete':
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
                break;

            case 'patch':
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
                $this->attachRequestPayload($ch, $args);
                break;

            case 'put':
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
                $this->attachRequestPayload($ch, $args);
                break;
        }
       
        $responseContent = curl_exec($ch);
       
        $response['headers'] = curl_getinfo($ch);
        if ($responseContent === false) {
            $this->last_error = curl_error($ch);
        } else {
            $headerSize = $response['headers']['header_size'];
           
            $response['httpHeaders'] = $this->getHeadersAsArray(substr($responseContent, 0, $headerSize));
            $response['body'] = substr($responseContent, $headerSize);

            if (isset($response['headers']['request_header'])) {
                $this->last_request['headers'] = $response['headers']['request_header'];
            }
        }

        curl_close($ch);

        $formattedResponse = $this->formatResponse($response);

        $this->determineSuccess($response, $formattedResponse, $timeout);

        return $formattedResponse;
    }

    /**
     * @return string The url to the API endpoint
     */
    public function getApiEndpoint()
    {
        return $this->api_endpoint;
    }

    /**
     * Get the HTTP headers as an array of header-name => header-value pairs.
     *
     * The "Link" header is parsed into an associative array based on the
     * rel names it contains. The original value is available under
     * the "_raw" key.
     *
     * @param string $headersAsString
     * @return array
     */
    private function getHeadersAsArray($headersAsString)
    {
        $headers = array();
       
        foreach (explode("\r\n", $headersAsString) as $i => $line) {
            if ($i === 0) { // HTTP code
                continue;
            }
           
            $line = trim($line);
            if (empty($line)) {
                continue;
            }
           
            list($key, $value) = explode(': ', $line);
           
            if ($key == 'Link') {
                $value = array_merge(
                    array('_raw' => $value),
                    $this->getLinkHeaderAsArray($value)
                );
            }
           
            $headers[$key] = $value;
        }

        return $headers;
    }

    /**
     * Extract all rel => URL pairs from the provided Link header value
     *
     * Mailchimp only implements the URI reference and relation type from
     * RFC 5988, so the value of the header is something like this:
     *
     * 'https://us13.api.mailchimp.com/schema/3.0/Lists/Instance.json; rel="describedBy", <https://us13.admin.mailchimp.com/lists/members/?id=XXXX>; rel="dashboard"'
     *
     * @param string $linkHeaderAsString
     * @return array
     */
    private function getLinkHeaderAsArray($linkHeaderAsString)
    {
        $urls = array();
       
        if (preg_match_all('/<(.*?)>\s*;\s*rel="(.*?)"\s*/', $linkHeaderAsString, $matches)) {
            foreach ($matches[2] as $i => $relName) {
                $urls[$relName] = $matches[1][$i];
            }
        }
       
        return $urls;
    }

    /**
     * Encode the data and attach it to the request
     * @param   resource $ch cURL session handle, used by reference
     * @param   array $data Assoc array of data to attach
     */
    private function attachRequestPayload(&$ch, $data)
    {
        $encoded = json_encode($data);
        $this->last_request['body'] = $encoded;
        curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded);
    }

    /**
     * Decode the response and format any error messages for debugging
     * @param array $response The response from the curl request
     * @return array|false    The JSON decoded into an array
     */
    private function formatResponse($response)
    {
        $this->last_response = $response;

        if (!empty($response['body'])) {
            return json_decode($response['body'], true);
        }

        return false;
    }

    /**
     * Check if the response was successful or a failure. If it failed, store the error.
     * @param array $response The response from the curl request
     * @param array|false $formattedResponse The response body payload from the curl request
     * @param int $timeout The timeout supplied to the curl request.
     * @return bool     If the request was successful
     */
    private function determineSuccess($response, $formattedResponse, $timeout)
    {
        $status = $this->findHTTPStatus($response, $formattedResponse);

        if ($status >= 200 && $status <= 299) {
            $this->request_successful = true;
            return true;
        }

        if (isset($formattedResponse['detail'])) {
            $this->last_error = sprintf('%d: %s', $formattedResponse['status'], $formattedResponse['detail']);
            return false;
        }

        if( $timeout > 0 && $response['headers'] && $response['headers']['total_time'] >= $timeout ) {
            $this->last_error = sprintf('Request timed out after %f seconds.', $response['headers']['total_time'] );
            return false;
        }

        $this->last_error = 'Unknown error, call getLastResponse() to find out what happened.';
        return false;
    }

    /**
     * Find the HTTP status code from the headers or API response body
     * @param array $response The response from the curl request
     * @param array|false $formattedResponse The response body payload from the curl request
     * @return int  HTTP status code
     */
    private function findHTTPStatus($response, $formattedResponse)
    {
        if (!empty($response['headers']) && isset($response['headers']['http_code'])) {
            return (int) $response['headers']['http_code'];
        }

        if (!empty($response['body']) && isset($formattedResponse['status'])) {
            return (int) $formattedResponse['status'];
        }

        return 418;
    }
}


newsletter.php:
Code: Select all
<?php require_once( 'cms/cms.php' ); ?>
<?php require_once( 'MailChimp.php' ); ?>

<cms:template title='Newsletter'>
    <cms:editable label='MailChimp API Key' name='mc_api_key' required='1' type='text'/>
    <cms:editable label='MailChimp List ID' name='mc_list_id' required='1' type='text'/>
</cms:template>

<?php COUCH::invoke(); ?>


Code for Newsletter form in index.php (index.php = Template where I am placing the newsletter subscription form):
Code: Select all
<cms:form method='post' name="newsletter_form" id="newsletter_form" accept-charset="utf-8" anchor='1' class="newsletter">
                                        <cms:if k_success>
                                            <cms:php>
                                                $MailChimp = new \DrewM\MailChimp('<cms:get_custom_field 'mc_api_key' masterpage='newsletter.php'/>');
                                   
                                                $result = $MailChimp->call('lists/subscribe', array(
                                                    'id'    => '<cms:show mc_list_id/>',
                                                    'email' => array('email' => '<cms:get_custom_field 'mc_list_id' masterpage='newsletter.php'/>')
                                                ));
                                   
                                                if (isset($result['email'])) {
                                                    echo "<div class=\"success\" id=\"message-news\">Please check your inbox for a confirmation email.</div>";
                                                } else if (isset($result['status']) &&
                                                           $result['status'] === 'error' &&
                                                           $result['name'] !== 'List_AlreadySubscribed') {
                                                    echo "<div class=\"error\"><strong>" . $result['name'] . " (" . $result['code'] . "):</strong> " . $result['error'] . "</div>";
                                                } else {
                                                    echo "<div class=\"error\">An unknown error was encountered. Please try again later or contact us.</div>";
                                                }
                                            </cms:php>
                                        <cms:else/>
                                            <cms:if k_error>
                                                <div class="error" id="error_news">Please enter a valid email address.</div>
                                            </cms:if>
                                            <cms:input name='email' placeholder='Email Address' required='1' type='text' validator='email'/>
                                            <input type="submit" value="Subscribe to Newsletter"  class="btn btn-default btn-rounded" >
                                        </cms:if>
                                    </cms:form>


On execution I get the following error (error description in the image attached in this post):
Fatal error: Class 'DrewM\MailChimp' not found in C:\wamp64\www\GenXCoders-CTO\YanaWebsite\couch\tags.php(2931) : eval()'d code on line 1
Image
where innovation meets technology
Hi,

You are trying to invoke new \DrewM\MailChimp() from within index.php and that class in not available in that template.
You should first reference the class by placing the following within index.php also -
Code: Select all
<?php require_once( 'MailChimp.php' ); ?>

Hope this helps.
@KK Sir,
I am still encountering the same error. As in the image in my last post.
I added the
Code: Select all
<?php require_once( 'MailChimp.php' ); ?>

line just below the
Code: Select all
<?php require_once( 'couch/cms.php' ); ?>
statement.
Image
where innovation meets technology
@KK Sir,

I found a small error in the code I copied from the forum. I used:
Code: Select all
<?php require_once( 'cms/cms.php' ); ?>


in place of
Code: Select all
<?php require_once( 'couch/cms.php' ); ?>

as my couch installation is in the folder couch itself.

With this corrected, I also followed your suggestion:
You are trying to invoke new \DrewM\MailChimp() from within index.php and that class in not available in that template.
You should first reference the class by placing the following within index.php also -
Code: Select all
Code: Select all
<?php require_once( 'MailChimp.php' ); ?>



I find that the code:
Code: Select all
<?php require_once( 'MailChimp.php' ); ?>

is available in two templates, viz.:
1. index,php
2. newsletter.php (containing the editable regions for API Key and List Id only)

When i try on localhost, i encounter the problem as described in my first post. So I thought to give it a try on live server. I got the following error:
The genxcoders.in page isn’t working

genxcoders.in is currently unable to handle this request.
HTTP ERROR 500


I am currently having the following structure of the files:
1. MailChimp.php (containing the code for MailChimp API from MailChimp Raw)
2. newsletter.php having the code:
Code: Select all
<?php require_once( 'couch/cms.php' ); ?>
<?php require_once( 'MailChimp.php' ); ?>

<cms:template title='Newsletter'>
    <cms:editable label='MailChimp API Key' name='mc_api_key' required='1' type='text'/>
    <cms:editable label='MailChimp List ID' name='mc_list_id' required='1' type='text'/>
</cms:template>

<?php COUCH::invoke(); ?>

3. index.php (contains the HTML-Couchified page with an embedded "footer.html" )
4. footer.html (containing the newsletter form and the newsletter.php code from viewtopic.php?f=8&t=7384

Also I have made one change in the MailChimp.php for SSL Verification and have set it to:
Code: Select all
public $verify_ssl = false;


Please advise.

Regards,
Aashish
Image
where innovation meets technology
I had a look at your site, Aashish (thanks for entrusting me with the creds).

Could spot two problems -
1. The 'MailChimp.php' had the following namespace -
namespace DrewM\MailChimp\MailChimp;

It should have been the following -
namespace DrewM\MailChimp;

So I suppose you made changes to the original code and then forgot to revert back. Anyway, that would explain the 'Class not found' error as you were calling the class with the wrong namespace.

I have rectified the code so you don't have to make any changes now.

2. The second problem was with the PHP code you were using within the form.
Instead of wrestling with it, I simply copied and used the code in the original post by @cheesypoof (viewtopic.php?f=8&t=7384#p10642). Had to modify it just a bit to fetch variables defined in newsletter.php. The revised code now becomes -
Code: Select all
<cms:php>
    global $CTX;
    use \DrewM\MailChimp\MailChimp;
    $MailChimp = new MailChimp('<cms:get_custom_field 'mc_api_key' masterpage='newsletter.php'/>');

    $result = $MailChimp->post('lists/<cms:get_custom_field 'mc_list_id' masterpage='newsletter.php'/>/members', array(
        'email_address' => $CTX->get('frm_email'),
        'status'        => 'pending'
    ));

    if (isset($result['id'])) {
        echo "<p class=\"success\">Please check your inbox for a confirmation email.</p>";
    } else if (isset($result['type'])) {
        echo "<p class=\"error\"><strong>" . $result['title'] . " (" . $result['status'] . "):</strong> " . $result['detail'] . "<br><br>" . $result['type'] . "</p>";
    } else {
        echo "<p class=\"error\">An unknown error was encountered. Please try again later or contact us.</p>";
    }
</cms:php>

And that did the job. I could successfully subscribe myself to your list.
Please check.
Thanks a ton KK sir. It is working fluently.

Regards,
Aashish
Image
where innovation meets technology
6 posts Page 1 of 1
cron