source: branches/2.0singleton/lib/PayPal.inc.php @ 132

Last change on this file since 132 was 128, checked in by scdev, 18 years ago

finished /lib folder

File size: 12.0 KB
RevLine 
[1]1<?php
2/**
[42]3 * The PayPal:: class provides functions for creating PayPal buttons and for
[1]4 * receiving PayPal's Instant Payment Notification (IPN) service.
5 *
6 * @author  Quinn Comendant <quinn@strangecode.com>
7 * @version 1.0
8 */
9class PayPal {
[42]10
[1]11    // General object parameters.
12    var $_params = array(
13        'paypal_url' => 'https://www.paypal.com/cgi-bin/webscr',
14        'test_mode' => false,
15    );
[42]16
17    // Options used for specific buttons and links.
[1]18    var $_default_button_options = array();
[42]19
[1]20    // Array of buttons created by newButton().
21    var $_buttons = array();
[42]22
[1]23    // Store the response from the last IPN.
24    var $_ipn_response;
[42]25
[1]26    /**
27     * Constructor.
28     *
29     * @param   bool    $test_mode  Use PayPal sandbox for testing.
30     */
31    function PayPal($test_mode=false)
32    {
33        if ($test_mode) {
34            $this->setParam(array('test_mode' => true));
35            // Use PayPal sandbox when in test mode.
36            $url = 'www.sandbox.paypal.com';
37        } else {
38            $url = 'www.paypal.com';
39        }
[42]40
[1]41        $this->_default_button_options = array(
42            '_global' => array(
43                'business' => null,
44            ),
45            'web_accept' => array(
46                'cmd' => '_xclick',
47                'button_url' => 'https://' . $url . '/cgi-bin/webscr',
48                'link_url' => 'https://' . $url . '/xclick/',
49                'submit_img' => 'https://' . $url . '/en_US/i/btn/x-click-but23.gif',
50                'submit_text' => _("Pay with PayPal"),
51            ),
52            'subscriptions' => array(
53                'cmd' => '_xclick-subscriptions',
54                'button_url' => 'https://' . $url . '/cgi-bin/webscr',
55                'link_url' => 'https://' . $url . '/subscriptions/',
56                'submit_img' => 'https://' . $url . '/en_US/i/btn/x-click-but20.gif',
57                'submit_text' => _("Subscribe with PayPal"),
58            ),
59        );
60    }
[42]61
[1]62    /**
[42]63     * Updates the _default_button_options array with options used for
[1]64     * specific buttons, or all buttons if $type is null.
65     *
66     * @access  public
67     *
[42]68     * @param   mixed   $type       The type of button to set defaults. If null,
[1]69     *                              sets the global button types.
70     * @param   array   $options    Options to set for button.
71     *
72     * @return  bool    True on success, false on failure.
73     */
74    function setButtonDefaults($type, $options)
75    {
[128]76        $app =& App::getInstance();
77
[1]78        if (!is_array($options) || empty($options)) {
[128]79            $app->logMsg(sprintf('Invalid options: %s', getDump($options)), LOG_WARNING, __FILE__, __LINE__);
[1]80            return false;
81        }
[42]82
[1]83        if (is_null($type) || '_global' == $type) {
84            $this->_default_button_options['_global'] = array_merge($this->_default_button_options['_global'], $options);
85        } else if (!isset($this->_default_button_options[$type])) {
[128]86            $app->logMsg(sprintf('Invalid button type: %s', $type), LOG_WARNING, __FILE__, __LINE__);
[1]87            return false;
88        }
[42]89
[1]90        $this->_default_button_options[$type] = array_merge($this->_default_button_options[$type], $options);
91        return true;
92    }
[42]93
[1]94    /**
95     * Creates a new element in the _buttons array. Uses _default_button_options
96     * merged with provided options.
97     *
98     * @access  public
99     *
100     * @param   string  $type       Type of button to create.
101     * @param   string  $name       Name of button to create.
102     * @param   array   $options    Options of button. Overwrites _default_button_options.
103     *
104     * @return  bool    True on success, false on failure.
105     */
106    function newButton($type, $name, $options=null)
107    {
[128]108        $app =& App::getInstance();
109
[1]110        if (!isset($this->_default_button_options[$type])) {
[128]111            $app->logMsg(sprintf('Invalid button type: %s', $type), LOG_WARNING, __FILE__, __LINE__);
[1]112            return false;
113        }
[42]114
[1]115        if (!is_array($options) || empty($options)) {
[128]116            $app->logMsg(sprintf('Invalid options: %s', getDump($options)), LOG_WARNING, __FILE__, __LINE__);
[1]117            return false;
118        }
[42]119
[1]120        if (isset($this->_buttons[$name])) {
[128]121            $app->logMsg(sprintf('Overwriting existing button name: %s', getDump($this->_buttons[$name])), LOG_DEBUG, __FILE__, __LINE__);
[1]122        }
[42]123
[1]124        $this->_buttons[$name] = array(
125            'type' => $type,
126            'options' => array_merge($this->_default_button_options['_global'], $this->_default_button_options[$type], $options)
127        );
128
129        return true;
130    }
131
132    /**
133     * Returns the URL link for specified button.
134     *
135     * @access  public
136     *
137     * @param   string  $name   Name of button for which to generate link.
138     *
139     * @return  mixed   Link of button, or false on failure.
140     */
141    function getLink($name)
142    {
[128]143        $app =& App::getInstance();
144
[1]145        if (!isset($this->_buttons[$name])) {
[128]146            $app->logMsg(sprintf('Button does not exist: %s', $name), LOG_WARNING, __FILE__, __LINE__);
[1]147            return false;
148        }
[42]149
[1]150        $query_string = '';
151        $delim = '';
152        if (is_array($this->_buttons[$name]['options']) && !empty($this->_buttons[$name]['options'])) {
153            foreach ($this->_buttons[$name]['options'] as $key=>$val) {
154                if (!in_array($key, array('button_url', 'link_url', 'cmd', 'submit_img', 'submit_text'))) {
155                    $query_string .= $delim . $key . '=' . urlencode($val);
156                    $delim = '&';
157                }
158            }
159        }
160
161        // PayPal links do not like urlencoded slashes for some stupid reason.
162        $search = array('/%2F/');
163        $replace = array('/');
[42]164
[1]165        return $this->_buttons[$name]['options']['link_url'] . preg_replace($search, $replace, $query_string);
166    }
167
168    /**
169     * Prints the link returned by getLink().
170     *
171     * @access  public
172     *
173     * @param   string  $name   Name of button for which to generate link.
174     */
175    function printLink($name)
176    {
177        echo $this->getLink($name);
178    }
179
180    /**
181     * Prints button with specified name.
182     *
183     * @access  public
184     *
185     * @param   string  $name   Name of button to print.
186     */
187    function printButton($name)
188    {
189        ?>
190        <form action="<?php echo $this->_buttons[$name]['options']['button_url']; ?>" method="post">
[42]191        <?php
[1]192        if (is_array($this->_buttons[$name]['options']) && !empty($this->_buttons[$name]['options'])) {
193            foreach ($this->_buttons[$name]['options'] as $key=>$val) {
194                if (!in_array($key, array('button_url', 'link_url', 'submit_img', 'submit_text'))) {
195                    ?>
[20]196                    <input type="hidden" name="<?php echo $key; ?>" value="<?php echo $val; ?>" />
[1]197                    <?php
198                }
199            }
[42]200        }
[1]201        ?>
[20]202        <input type="image" src="<?php echo $this->_buttons[$name]['options']['submit_img']; ?>" border="0" name="submit" alt="<?php echo $this->_buttons[$name]['options']['submit_text']; ?>" />
[1]203        </form>
204        <?php
205    }
206
207    /**
208     * Set (or overwrite existing) parameters by passing an array of new parameters.
209     *
210     * @access public
211     * @param  array    $params     Array of parameters (key => val pairs).
212     */
213    function setParam($params)
214    {
[128]215        $app =& App::getInstance();
216
[1]217        if (isset($params) && is_array($params)) {
218            // Merge new parameters with old overriding only those passed.
219            $this->_params = array_merge($this->_params, $params);
220        } else {
[128]221            $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__);
[1]222        }
223    }
224
225    /**
226     * Return the value of a parameter, if it exists.
227     *
228     * @access public
229     * @param string $param        Which parameter to return.
230     * @return mixed               Configured parameter value.
231     */
232    function getParam($param)
233    {
[128]234        $app =& App::getInstance();
235
[1]236        if (isset($this->_params[$param])) {
237            return $this->_params[$param];
238        } else {
[128]239            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
[1]240            return null;
241        }
242    }
243
244    /**
245     * Tests if the HTTP request is a valid IPN request from PayPal.
246     *
247     * @access  public
248     *
249     * @return  bool    True if valid, false if invalid.
250     */
251    function incomingIPNRequest()
252    {
[42]253        if ($_SERVER['REQUEST_METHOD'] == 'POST'
[1]254        && $_SERVER['CONTENT_TYPE'] == 'application/x-www-form-urlencoded'
255        && !empty($_POST)) {
256            return true;
257        } else {
258            return false;
259        }
260    }
261
262    /**
263     * Process incoming IPN.
264     *
265     * @access  public
266     *
267     * @return  bool    True on success, false on failure.
268     */
269    function processIPN()
[42]270    {
[128]271        $app =& App::getInstance();
272
[1]273        if (getPost('test_ipn') == '1' || $this->getParam('test_mode')) {
[128]274            $app->logMsg(sprintf('Processing PayPal IPN in test mode: %s', getDump(getFormData())), LOG_DEBUG, __FILE__, __LINE__);
[1]275            $url = parse_url('https://www.sandbox.paypal.com/cgi-bin/webscr');
276        } else {
[128]277            $app->logMsg(sprintf('Processing PayPal IPN: %s', getDump(getFormData())), LOG_DEBUG, __FILE__, __LINE__);
[1]278            $url = parse_url($this->getParam('paypal_url'));
279        }
[42]280
[1]281        // Read POST request and add 'cmd'.
282        $received_data = getPost();
283        $return_data = 'cmd=_notify-validate';
284        foreach ($received_data as $post_key => $post_val) {
285            $return_data .= '&' . $post_key . '=' . urlencode($post_val);
286        }
[42]287
[1]288        // Set the port number based on the scheme.
[42]289        if ($url['scheme'] == "https") {
[1]290            $url['port'] = 443;
291            $ssl = 'ssl://';
292        } else {
293            $url['port'] = 80;
294            $ssl = '';
295        }
[42]296
[1]297        // Open connection to PayPal server.
[42]298        $fp = fsockopen($ssl . $url['host'], $url['port'], $errnum, $errstr, 30);
[1]299
300        if (!$fp) {
[128]301            $app->logMsg(sprintf('Connection to PayPal URL %s failed with error: %s (%s)', $ssl . $url['host'], $errstr, $errnum), LOG_WARNING, __FILE__, __LINE__);
[1]302            return false;
303        } else {
[42]304            fputs($fp, "POST {$url['path']} HTTP/1.1\r\n");
305            fputs($fp, "Host: {$url['host']}\r\n");
306            fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
307            fputs($fp, "Content-length: " . strlen($return_data) . "\r\n");
308            fputs($fp, "Connection: close\r\n\r\n");
309            fputs($fp, $return_data . "\r\n\r\n");
310
[1]311            // Loop through the response lines from the server.
312            $this->_ipn_response = '';
313            while (!feof($fp)) {
314                $this->_ipn_response .= fgets($fp, 1024);
315            }
316            fclose($fp);
[42]317
[128]318            $app->logMsg(sprintf('IPN response received: %s', $this->_ipn_response), LOG_NOTICE, __FILE__, __LINE__);
[1]319            return true;
320        }
321    }
[42]322
[1]323    /**
324     * Checks the response received from PayPal's IPN upon calling processIPN().
325     *
326     * @access  public
327     *
328     * @return  bool    True if response contains VERIFIED, false otherwise.
329     */
330    function verifiedIPN()
331    {
[128]332        $app =& App::getInstance();
333
[1]334        if (!isset($this->_ipn_response)) {
[128]335            $app->logMsg(sprintf('Cannot verify IPN, response not received.', null), LOG_WARNING, __FILE__, __LINE__);
[1]336            return false;
337        }
[42]338
[1]339        if (empty($this->_ipn_response)) {
[128]340            $app->logMsg(sprintf('Cannot verify IPN, response empty.', null), LOG_WARNING, __FILE__, __LINE__);
[1]341            return false;
342        }
[42]343
[1]344        if (preg_match('/VERIFIED/', $this->_ipn_response)) {
[128]345            $app->logMsg(sprintf('IPN verified!', null), LOG_DEBUG, __FILE__, __LINE__);
[1]346            return true;
347        } else if (preg_match('/INVALID/', $this->_ipn_response)) {
[128]348            $app->logMsg(sprintf('IPN invalid.', null), LOG_DEBUG, __FILE__, __LINE__);
[1]349            return false;
350        } else {
[128]351            $app->logMsg(sprintf('IPN unknown.', null), LOG_WARNING, __FILE__, __LINE__);
[1]352            return false;
353        }
354    }
[42]355
356
[1]357} // End of class.
358
359?>
Note: See TracBrowser for help on using the repository browser.