1<?php
2/**
3 * Horde_Service_Facebook class abstracts communication with Facebook's
4 * rest interface.
5 *
6 * This code was originally a Hordified version of Facebook's official PHP
7 * client. However, since that client was very buggy and incomplete, very little
8 * of the original code or design is left. I left the original copyright notice
9 * intact below.
10 *
11 * Copyright 2009-2017 Horde LLC (http://www.horde.org/)
12 *
13 * @author Michael J. Rubinsky <mrubinsk@horde.org>
14 * @category Horde
15 * @package Service_Facebook
16 */
17
18/**
19 * Facebook Platform PHP5 client
20 *
21 * Copyright 2004-2009 Facebook. All Rights Reserved.
22 *
23 * Copyright (c) 2007 Facebook, Inc.
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 *
30 * 1. Redistributions of source code must retain the above copyright
31 *    notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 *    notice, this list of conditions and the following disclaimer in the
34 *    documentation and/or other materials provided with the distribution.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
37 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
39 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
40 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 *
47 * For help with this library, contact developers-help@facebook.com
48 */
49class Horde_Service_Facebook
50{
51    /**
52     * Use only ssl resource flag
53     *
54     * @var boolean
55     */
56    public $useSslResources = false;
57
58    /**
59     * The API Secret Key
60     *
61     * @var string
62     */
63    protected $_secret;
64
65    /**
66     * Holds an optional logger object
67     *
68     * @var Horde_Log_Logger
69     */
70    protected $_logger;
71
72    /**
73     *
74     * @var Horde_Http_Client
75     */
76    protected $_http;
77
78
79    /**
80     * Cache for the various objects we lazy load in __get()
81     *
82     * @var hash of Horde_Service_Facebook_* objects
83     */
84     protected $_objCache = array();
85
86
87    const API_VALIDATION_ERROR = 1;
88    const REST_SERVER_ADDR = 'https://api.facebook.com/method/';
89    const GRAPH_SERVER_ADDR = 'https://graph.facebook.com';
90
91    /**
92     * Const'r
93     *
94     * @param string $appId    Application ID.
95     * @param string $secret   Developer API secret.
96     * @param array $context   Array of context information containing:
97     *  <pre>
98     *      http_client - required
99     *      logger
100     *      use_ssl
101     * </pre>
102     */
103    public function __construct($appId, $secret, $context)
104    {
105        // We require a http client object.
106        if (empty($context['http_client'])) {
107            throw new InvalidArgumentException('A http client object is required');
108        } else {
109            $this->_http = $context['http_client'];
110        }
111
112        // Optional Horde_Log_Logger
113        if (!empty($context['logger'])) {
114            $this->_logger = $context['logger'];
115        } else {
116            $this->_logger = new Horde_Support_Stub();
117        }
118
119        $this->_logger->debug('Initializing Horde_Service_Facebook');
120
121        $this->_appId = $appId;
122        $this->secret = $secret;
123
124        if (!empty($context['use_ssl'])) {
125            $this->useSslResources = true;
126        }
127    }
128
129    /**
130     * Lazy load the facebook classes.
131     *
132     * @param string $value  The lowercase representation of the subclass.
133     *
134     * @return mixed
135     * @throws Horde_Service_Facebook_Exception
136     */
137    public function __get($value)
138    {
139        // First, see if it's an allowed protected value.
140        switch ($value) {
141        case 'appId':
142            return $this->_appId;
143        case 'secret':
144            return $this->_secret;
145        case 'http':
146            return $this->_http;
147        case 'logger':
148            return $this->_logger;
149        }
150
151        // If not, assume it's a method/action class...
152        $class = 'Horde_Service_Facebook_' . Horde_String::ucfirst($value);
153        if (!class_exists($class)) {
154            throw new Horde_Service_Facebook_Exception(sprintf("%s class not found", $class));
155        }
156
157        if (empty($this->_objCache[$class])) {
158            $this->_objCache[$class] = new $class($this);
159        }
160
161        return $this->_objCache[$class];
162    }
163
164    /**
165     * Helper function to get the appropriate facebook url
166     *
167     * @param string $subdomain  The subdomain to use (www).
168     *
169     * @return string
170     */
171    public static function getFacebookUrl($subdomain = 'www')
172    {
173        return 'https://' . $subdomain . '.facebook.com';
174    }
175
176    /**
177     * Calls the specified normal REST API method.
178     *
179     * @param string $method  Name of the Facebook method to invoke
180     * @param array $params   A map of param names => param values
181     *
182     * @return mixed  Result of method call
183     */
184    public function callMethod($method, array $params = array())
185    {
186        $this->_logger->debug(sprintf('Calling method %s with parameters %s', $method, print_r($params, true)));
187        $request = new Horde_Service_Facebook_Request_Rest($this, $method, $params);
188        return $request->run();
189    }
190
191    /**
192     * Call the Facebook Graph API.
193     *
194     * @param string $method  The endpoint (method) to call.
195     * @param array $params   An array of parameters to pass along with the call.
196     * @param array $options  Additional request options:
197     *   - request: (string) 'POST', 'GET', 'DELETE' etc..
198     *
199     * @return mixed  The results of the API call.
200     */
201    public function callGraphApi(
202        $method = '', array $params = array(), array $options = array())
203    {
204        $request = new Horde_Service_Facebook_Request_Graph(
205            $this,
206            $method,
207            $params,
208            $options);
209
210        return $request->run();
211    }
212
213}