RPCClient.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2015 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\service\impl;
12 
17 
18 /**
19  * RPCClient is used to do calls to other wCMF instances on the same mashine.
20  * @see RemotingServer
21  *
22  * @author ingo herwig <ingo@wemove.com>
23  */
24 class RPCClient implements RemotingClient {
25 
26  // constants
27  const SIDS_SESSION_VARNAME = 'RPCClient.sids';
28 
29  private static $_logger = null;
30 
31  private $_serverCli = null;
32  private $_php = null;
33  private $_user = null;
34 
35  /**
36  * Constructor
37  * @param $serverCli The command line interface of the other server instance.
38  * @param $user The remote user instance.
39  */
40  public function __construct($serverCli, $user) {
41  if (self::$_logger == null) {
42  self::$_logger = LogManager::getLogger(__CLASS__);
43  }
44  $this->_serverCli = realpath($serverCli);
45  if (!file_exists($this->_serverCli)) {
46  throw new \RuntimeException("Could not setup RPCClient: ".$this->_serverCli." not found.");
47  }
48 
49  // locate the php executable
50  $config = ObjectFactory::getInstance('configuration');
51  $this->_php = $config->getValue('php', 'system');
52 
53  // initialize the session variable for storing session
54  $session = ObjectFactory::getInstance('session');
55  if (!$session->exist(self::SIDS_SESSION_VARNAME)) {
56  $var = array();
57  $session->set(self::SIDS_SESSION_VARNAME, $var);
58  }
59  $this->_user = $user;
60  }
61 
62  /**
63  * Do a call to the remote server.
64  * @param $request A Request instance
65  * @return A Response instance
66  */
67  public function call(Request $request) {
68  $response = $this->doRemoteCall($request, false);
69  return $response;
70  }
71 
72  /**
73  * Do a remote call.
74  * @param $request The Request instance
75  * @param $isLogin Boolean whether this request is a login request or not
76  * @return The Response instance
77  */
78  protected function doRemoteCall(Request $request, $isLogin) {
79  // initially login, if no sessionId is set
80  $sessionId = $this->getSessionId();
81  if (!$isLogin && $sessionId == null) {
82  $response = $this->doLogin();
83  if ($response) {
84  $sessionId = $this->getSessionId();
85  }
86  }
87 
88  $jsonResponse = null;
89  $returnValue = -1;
90 
91  $request->setResponseFormat('json');
92  $serializedRequest = base64_encode(serialize($request));
93 
94  $arguments = array(
95  $serializedRequest,
96  $sessionId
97  );
98  $currentDir = getcwd();
99  chdir(dirname($this->_serverCli));
100  if (self::$_logger->isDebugEnabled()) {
101  self::$_logger->debug("Do remote call to: ".$this->_serverCli);
102  self::$_logger->debug("Request:\n".$request->toString());
103  }
104  // store and reopen the session (see http://bugs.php.net/bug.php?id=44942)
105  session_write_close();
106  exec($this->_php.' '.$this->_serverCli.' '.join(' ', $arguments), $jsonResponse, $returnValue);
107  session_start();
108  if (self::$_logger->isDebugEnabled()) {
109  self::$_logger->debug("Response [JSON]:\n".$jsonResponse[0]);
110  }
111  chdir($currentDir);
112 
113  $responseData = json_decode($jsonResponse[0], true);
114  $response = ObjectFactory::getInstance('response');
115  $response->setValues($responseData);
116  $response->setFormat('json');
117  $formatter = ObjectFactory::getInstance('formatter');
118  $formatter->deserialize($response);
119  if (self::$_logger->isDebugEnabled()) {
120  self::$_logger->debug("Response:\n".$response->toString());
121  }
122 
123  if (!$response->getValue('success')) {
124  // if the session expired, try to relogin
125  if (strpos('Authorization failed', $response->getValue('errorMsg')) === 0 && !$isLogin) {
126  $this->doLogin($url);
127  }
128  else {
129  $this->handleError($response);
130  }
131  }
132  return $response;
133  }
134 
135  /**
136  * Do the login request. If the request is successful,
137  * the session id will be set.
138  * @return True on success
139  */
140  protected function doLogin() {
141  if ($this->_user) {
142  $request = ObjectFactory::getInstance('request');
143  $request->setAction('login');
144  $request->setValues(
145  array(
146  'login' => $this->_user['login'],
147  'password' => $this->_user['password']
148  )
149  );
150  $response = $this->doRemoteCall($request, true);
151  if ($response->getValue('success')) {
152  // store the session id in the session
153  $this->setSessionId($response->getValue('sid'));
154  return true;
155  }
156  }
157  else {
158  throw new \RuntimeException("Remote user required for remote call.");
159  }
160  }
161 
162  /**
163  * Store the session id for our server in the local session
164  * @return The session id or null
165  */
166  protected function setSessionId($sessionId) {
167  $session = ObjectFactory::getInstance('session');
168  $sids = $session->get(self::SIDS_SESSION_VARNAME);
169  $sids[$this->_serverCli] = $sessionId;
170  $session->set(self::SIDS_SESSION_VARNAME, $sids);
171  }
172 
173  /**
174  * Get the session id for our server from the local session
175  * @return The session id or null
176  */
177  protected function getSessionId() {
178  // check if we already have a session with the server
179  $session = ObjectFactory::getInstance('session');
180  $sids = $session->get(self::SIDS_SESSION_VARNAME);
181  if (isset($sids[$this->_serverCli])) {
182  return $sids[$this->_serverCli];
183  }
184  return null;
185  }
186 
187  /**
188  * Error handling method
189  * @param $response The Response instance
190  */
191  protected function handleError($response) {
192  $errorMsg = $response->getValue('errorMsg');
193  self::$_logger->error("Error in remote call to ".$this->_serverCli.": ".$errorMsg."\n".$response->toString());
194  throw new \RuntimeException("Error in remote call to ".$this->_serverCli.": ".$errorMsg);
195  }
196 }
197 ?>
setSessionId($sessionId)
Store the session id for our server in the local session.
Definition: RPCClient.php:166
handleError($response)
Error handling method.
Definition: RPCClient.php:191
static getLogger($name)
Get the logger with the given name.
Definition: LogManager.php:35
setResponseFormat($format)
Set the desired response format.
call(Request $request)
Do a call to the remote server.
Definition: RPCClient.php:67
__construct($serverCli, $user)
Constructor.
Definition: RPCClient.php:40
RPCClient is used to do calls to other wCMF instances on the same mashine.
Definition: RPCClient.php:24
static getInstance($name, $dynamicConfiguration=array())
Request holds the request values that are used as input to Controller instances.
Definition: Request.php:20
RemotingClient defines the interface for clients to be used with RemotingServer.
doLogin()
Do the login request.
Definition: RPCClient.php:140
doRemoteCall(Request $request, $isLogin)
Do a remote call.
Definition: RPCClient.php:78
getSessionId()
Get the session id for our server from the local session.
Definition: RPCClient.php:177