1: <?php
  2: 
  3:   4:   5:   6:   7: 
  8: class Syspay_Merchant_EMS
  9: {
 10:     protected $secrets = array();
 11:     protected $skipAuthCheck;
 12:     protected  = array();
 13:     protected $content;
 14: 
 15:      16:  17:  18:  19: 
 20:     public function __construct(array $secrets, $skipAuthCheck = false)
 21:     {
 22:         $this->secrets       = $secrets;
 23:         $this->skipAuthCheck = $skipAuthCheck;
 24: 
 25:         $this->headers['content-type'] = isset($_SERVER['CONTENT_TYPE'])?
 26:                                             $_SERVER['CONTENT_TYPE']:'application/x-www-form-urlencoded';
 27:         $this->headers['x-merchant']   = isset($_SERVER['HTTP_X_MERCHANT'])?$_SERVER['HTTP_X_MERCHANT']:null;
 28:         $this->headers['x-checksum']   = isset($_SERVER['HTTP_X_CHECKSUM'])?$_SERVER['HTTP_X_CHECKSUM']:null;
 29:         $this->headers['x-event-id']   = isset($_SERVER['HTTP_X_EVENT_ID'])?$_SERVER['HTTP_X_EVENT_ID']:null;
 30:         $this->headers['x-event-date'] = isset($_SERVER['HTTP_X_EVENT_DATE'])?$_SERVER['HTTP_X_EVENT_DATE']:null;
 31: 
 32:         $this->content = file_get_contents('php://input');
 33:     }
 34: 
 35:      36:  37:  38:  39: 
 40:     public function getEvent()
 41:     {
 42:         if (!$this->skipAuthCheck) {
 43:             $this->checkChecksum();
 44:         }
 45: 
 46:         $content = $this->getContent();
 47: 
 48:         if (!isset($content->type)) {
 49:             throw new Syspay_Merchant_EMSException(
 50:                 'Unable to get event type',
 51:                 Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
 52:             );
 53:         }
 54: 
 55:         if (!isset($content->data)) {
 56:             throw new Syspay_Merchant_EMSException(
 57:                 'Unable to get data from content',
 58:                 Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
 59:             );
 60:         }
 61: 
 62:         switch ($content->type) {
 63:             case 'payment':
 64:                 if (!isset($content->data->payment)) {
 65:                     throw new Syspay_Merchant_EMSException(
 66:                         'Payment event received with no payment data',
 67:                         Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
 68:                     );
 69:                 }
 70: 
 71:                 return Syspay_Merchant_Entity_Payment::buildFromResponse($content->data->payment);
 72:                 break;
 73:             case 'refund':
 74:                 if (!isset($content->data->refund)) {
 75:                     throw new Syspay_Merchant_EMSException(
 76:                         'Refund event received with no refund data',
 77:                         Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
 78:                     );
 79:                 }
 80: 
 81:                 return Syspay_Merchant_Entity_Refund::buildFromResponse($content->data->refund);
 82:                 break;
 83:             case 'chargeback':
 84:                 if (!isset($content->data->chargeback)) {
 85:                     throw new Syspay_Merchant_EMSException(
 86:                         'Chargeback event received with no chargeback data',
 87:                         Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
 88:                     );
 89:                 }
 90: 
 91:                 return Syspay_Merchant_Entity_Chargeback::buildFromResponse($content->data->chargeback);
 92:                 break;
 93:             case 'billing_agreement':
 94:                 if (!isset($content->data->billing_agreement)) {
 95:                     throw new Syspay_Merchant_EMSException(
 96:                         'Billing agreement event received with no billing_agreement data',
 97:                         Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
 98:                     );
 99:                 }
100: 
101:                 return Syspay_Merchant_Entity_BillingAgreement::buildFromResponse($content->data->billing_agreement);
102:                 break;
103:             case 'subscription':
104:                 if (!isset($content->data->subscription)) {
105:                     throw new Syspay_Merchant_EMSException(
106:                         'Subscription event received with no subscription data',
107:                         Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
108:                     );
109:                 }
110: 
111:                 return Syspay_Merchant_Entity_Subscription::buildFromResponse($content->data->subscription);
112:             default:
113:                 throw new Syspay_Merchant_EMSException(
114:                     'Unknown type: ' . $content->type,
115:                     Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
116:                 );
117:         }
118:     }
119: 
120:     121: 122: 123: 
124:     private function checkChecksum()
125:     {
126:         if (empty($this->headers['x-merchant'])) {
127:             throw new Syspay_Merchant_EMSException(
128:                 'Missing x-merchant header',
129:                 Syspay_Merchant_EMSException::CODE_MISSING_HEADER
130:             );
131:         }
132: 
133:         if (empty($this->headers['x-checksum'])) {
134:             throw new Syspay_Merchant_EMSException(
135:                 'Missing x-checksum header',
136:                 Syspay_Merchant_EMSException::CODE_MISSING_HEADER
137:             );
138:         }
139: 
140:         if (!isset($this->secrets[$this->headers['x-merchant']])) {
141:             throw new Syspay_Merchant_EMSException(
142:                 'Unknown merchant: ' . $this->headers['x-merchant'],
143:                 Syspay_Merchant_EMSException::CODE_UNKNOWN_MERCHANT
144:             );
145:         }
146: 
147:         if (!Syspay_Merchant_Utils::checkChecksum(
148:             $this->content,
149:             $this->secrets[$this->headers['x-merchant']],
150:             $this->headers['x-checksum']
151:         )) {
152:             throw new Syspay_Merchant_EMSException(
153:                 'Invalid checksum',
154:                 Syspay_Merchant_EMSException::CODE_INVALID_CHECKSUM
155:             );
156:         }
157:     }
158: 
159:     160: 161: 162: 163: 
164:     private function getContent()
165:     {
166:         switch ($this->headers['content-type']) {
167:             case 'application/json':
168:                 $content = json_decode($this->content);
169:                 if (false === $content) {
170:                     throw new Syspay_Merchant_EMSException(
171:                         'Unable to parse request body, invalid json',
172:                         Syspay_Merchant_EMSException::CODE_INVALID_CONTENT
173:                     );
174:                 }
175: 
176:                 return $content;
177:             case 'application/x-www-form-urlencoded':
178:             default:
179:                 return self::toObject($_POST);
180:         }
181:     }
182: 
183:     184: 185: 186: 
187:     public function getEventId()
188:     {
189:         return $this->headers['x-event-id'];
190:     }
191: 
192:     193: 194: 195: 
196:     public function getEventDate()
197:     {
198:         if (isset($this->headers['x-event-date'])) {
199:             $date = new DateTime();
200:             $date->setTimestamp($this->headers['x-event-date']);
201:             return $date;
202:         }
203: 
204:         return null;
205:     }
206: 
207: 
208:     209: 210: 211: 212: 213: 
214:     private static function toObject($a)
215:     {
216:         if (is_array($a)) {
217:             return (object) array_map(array('Syspay_Merchant_EMS', 'toObject'), $a);
218:         }
219: 
220:         return $a;
221:     }
222: }
223: