api.telepathy.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. <?php
  2. /**
  3. * Prophetic guessing login by the address/surname/realname
  4. */
  5. class Telepathy {
  6. /**
  7. * Contains system alter config as key=>value
  8. *
  9. * @var array
  10. */
  11. protected $altCfg = array();
  12. /**
  13. * Contains all available user address
  14. *
  15. * @var array
  16. */
  17. protected $alladdress = array();
  18. /**
  19. * Contains all available users realnames
  20. *
  21. * @var array
  22. */
  23. protected $allrealnames = array();
  24. /**
  25. * Contains preprocessed users surnames
  26. *
  27. * @var array
  28. */
  29. protected $allsurnames = array();
  30. /**
  31. * Contains all available user mobiles
  32. *
  33. * @var array
  34. */
  35. protected $allMobiles = array();
  36. /**
  37. * Contains all available additional user mobiles
  38. *
  39. * @var array
  40. */
  41. protected $allExtMobiles = array();
  42. /**
  43. * Contains all available user phones
  44. *
  45. * @var array
  46. */
  47. protected $allPhones = array();
  48. /**
  49. * Contains all available user mobiles with doubles
  50. *
  51. * @var array
  52. */
  53. protected $allMobilesFull = array();
  54. /**
  55. * Contains all available additional user mobiles with doubles
  56. *
  57. * @var array
  58. */
  59. protected $allExtMobilesFull = array();
  60. /**
  61. * Contains all available user phones with doubles
  62. *
  63. * @var array
  64. */
  65. protected $allPhonesFull = array();
  66. /**
  67. * Case sensitivity flag
  68. *
  69. * @var bool
  70. */
  71. protected $caseSensitive = false;
  72. /**
  73. * Cached address usage flag
  74. *
  75. * @var bool
  76. */
  77. protected $cachedAddress = true;
  78. /**
  79. * Use phones caching or not?
  80. *
  81. * @var bool
  82. */
  83. protected $cachedPhones = false;
  84. /**
  85. * Return only uniq login when telepaty by phones
  86. *
  87. * @var bool
  88. */
  89. protected $uniqLogin = false;
  90. /**
  91. * City display flag
  92. *
  93. * @var array
  94. */
  95. protected $citiesAddress = false;
  96. /**
  97. * System caching object placeholder
  98. *
  99. * @var object
  100. */
  101. protected $cache = '';
  102. /**
  103. * Contains users previously detected by phone number as number=>login
  104. *
  105. * @var array
  106. */
  107. protected $phoneTelepathyCache = array();
  108. /**
  109. * Contains phone data caching time in seconds
  110. */
  111. const PHONE_CACHE_TIME = 86400;
  112. /**
  113. * Creates new telepathy instance
  114. *
  115. * @param bool $caseSensitive
  116. * @param bool $cachedAddress
  117. * @param bool $citiesAddress
  118. * @param bool $cachedPhones
  119. * @param bool $uniqLogin
  120. *
  121. * @return void
  122. */
  123. public function __construct($caseSensitive = false, $cachedAddress = true, $citiesAddress = false, $cachedPhones = false, $uniqLogin = false) {
  124. $this->caseSensitive = $caseSensitive;
  125. $this->cachedAddress = $cachedAddress;
  126. $this->citiesAddress = $citiesAddress;
  127. $this->cachedPhones = $cachedPhones;
  128. $this->uniqLogin = $uniqLogin;
  129. $this->loadConfig();
  130. $this->initCache();
  131. $this->loadAddress();
  132. if (!$this->caseSensitive) {
  133. $this->addressToLowerCase();
  134. }
  135. if (!empty($this->alladdress)) {
  136. $this->alladdress = array_flip($this->alladdress);
  137. }
  138. }
  139. /**
  140. * Loads system alter.ini config into protected property for further usage
  141. *
  142. * @global object $ubillingConfig
  143. *
  144. * @return void
  145. */
  146. protected function loadConfig() {
  147. global $ubillingConfig;
  148. $this->altCfg = $ubillingConfig->getAlter();
  149. }
  150. /**
  151. * Inits system cache
  152. *
  153. * @return void
  154. */
  155. protected function initCache() {
  156. $this->cache = new UbillingCache();
  157. }
  158. /**
  159. * Loads cached address data to private data property
  160. *
  161. * @return void
  162. */
  163. protected function loadAddress() {
  164. if (!$this->citiesAddress) {
  165. if ($this->cachedAddress) {
  166. $this->alladdress = zb_AddressGetFulladdresslistCached();
  167. } else {
  168. $this->alladdress = zb_AddressGetFulladdresslist();
  169. }
  170. } else {
  171. $this->alladdress = zb_AddressGetFullCityaddresslist();
  172. }
  173. }
  174. /**
  175. * Loads all user realnames from database into private prop
  176. *
  177. * @return void
  178. */
  179. protected function loadRealnames() {
  180. $this->allrealnames = zb_UserGetAllRealnames();
  181. }
  182. /**
  183. * Normalizes mobile number to +380 format.
  184. * May be not acceptable for countries other than Ukraine.
  185. *
  186. * @param string $mobile
  187. *
  188. * @return string/void on error
  189. */
  190. protected function normalizePhoneFormat($mobile) {
  191. $mobile = vf($mobile, 3);
  192. $len = strlen($mobile);
  193. //all is ok
  194. if ($len != 12) {
  195. switch ($len) {
  196. case 11:
  197. $mobile = '3' . $mobile;
  198. break;
  199. case 10:
  200. $mobile = '38' . $mobile;
  201. break;
  202. case 9:
  203. $mobile = '380' . $mobile;
  204. break;
  205. }
  206. }
  207. $newLen = strlen($mobile);
  208. if ($newLen == 12) {
  209. $mobile = '+' . $mobile;
  210. } else {
  211. $mobile = '';
  212. }
  213. return ($mobile);
  214. }
  215. /**
  216. * Loads all existing phone data into protected props for further usage
  217. *
  218. * @return void
  219. */
  220. public function usePhones() {
  221. //init previously detected phones cache
  222. $this->phoneTelepathyCache = $this->cache->get('PHONETELEPATHY', self::PHONE_CACHE_TIME);
  223. if (empty($this->phoneTelepathyCache)) {
  224. $this->phoneTelepathyCache = array();
  225. }
  226. //loading user phones data
  227. if ($this->cachedPhones) {
  228. $allPhoneData = $this->cache->get('PHONEDATA', self::PHONE_CACHE_TIME);
  229. if (empty($allPhoneData)) {
  230. $allPhoneData = zb_UserGetAllPhoneData();
  231. $this->cache->set('PHONEDATA', $allPhoneData, self::PHONE_CACHE_TIME);
  232. }
  233. } else {
  234. $allPhoneData = zb_UserGetAllPhoneData();
  235. }
  236. if (!empty($allPhoneData)) {
  237. foreach ($allPhoneData as $login => $each) {
  238. $cleanMobile = vf($each['mobile'], 3);
  239. if (!empty($cleanMobile)) {
  240. if ($this->uniqLogin) {
  241. $this->allMobilesFull[$cleanMobile][] = $login;
  242. } else {
  243. $this->allMobiles[$cleanMobile] = $login;
  244. }
  245. }
  246. $cleanPhone = vf($each['phone'], 3);
  247. if (!empty($cleanPhone)) {
  248. if ($this->uniqLogin) {
  249. $this->allMobilesFull[$cleanPhone][] = $login;
  250. } else {
  251. $this->allMobiles[$cleanPhone] = $login;
  252. }
  253. }
  254. }
  255. }
  256. //additional mobiles loading if enabled
  257. if ($this->altCfg['MOBILES_EXT']) {
  258. if ($this->cachedPhones) {
  259. $allExtTmp = $this->cache->get('EXTMOBILES', self::PHONE_CACHE_TIME);
  260. if (empty($allExtTmp)) {
  261. $extMob = new MobilesExt();
  262. $allExtTmp = $extMob->getAllMobilesUsers();
  263. $this->cache->set('EXTMOBILES', $allExtTmp, self::PHONE_CACHE_TIME);
  264. }
  265. } else {
  266. $extMob = new MobilesExt();
  267. $allExtTmp = $extMob->getAllMobilesUsers();
  268. }
  269. if (!empty($allExtTmp)) {
  270. foreach ($allExtTmp as $eachExtMobile => $login) {
  271. $cleanExtMobile = vf($eachExtMobile, 3);
  272. if ($this->uniqLogin) {
  273. $this->allMobilesFull[$cleanExtMobile][] = $login;
  274. } else {
  275. $this->allMobiles[$cleanExtMobile] = $login;
  276. }
  277. }
  278. }
  279. }
  280. }
  281. /**
  282. * Preprocess all user surnames into usable data
  283. *
  284. * @return void
  285. */
  286. protected function surnamesExtract() {
  287. if (!empty($this->allrealnames)) {
  288. foreach ($this->allrealnames as $login => $realname) {
  289. $raw = explode(' ', $realname);
  290. if (!empty($raw)) {
  291. $this->allsurnames[$login] = $raw[0];
  292. }
  293. }
  294. }
  295. }
  296. /**
  297. * external passive constructor for name realname login detection
  298. *
  299. * @return void
  300. */
  301. public function useNames() {
  302. $this->loadRealnames();
  303. $this->surnamesExtract();
  304. if (!empty($this->allrealnames)) {
  305. $this->allrealnames = array_flip($this->allrealnames);
  306. }
  307. if (!empty($this->allrealnames)) {
  308. $this->allsurnames = array_flip($this->allsurnames);
  309. }
  310. }
  311. /**
  312. * preprocess available address data into lower case
  313. *
  314. * @return void
  315. */
  316. protected function addressToLowerCase() {
  317. global $ubillingConfig;
  318. $alterconf = $ubillingConfig->getAlter();
  319. $cacheTime = $alterconf['ADDRESS_CACHE_TIME'];
  320. $cacheTime = time() - ($cacheTime * 60);
  321. if (!$this->citiesAddress) {
  322. $cacheName = 'exports/fulladdresslistlowercache.dat';
  323. } else {
  324. $cacheName = 'exports/fullcityaddresslistlowercache.dat';
  325. }
  326. $updateCache = false;
  327. if (file_exists($cacheName)) {
  328. $updateCache = false;
  329. if ((filemtime($cacheName) > $cacheTime)) {
  330. $updateCache = false;
  331. } else {
  332. $updateCache = true;
  333. }
  334. } else {
  335. $updateCache = true;
  336. }
  337. if (($alterconf['ADDRESS_CACHE_TIME']) AND ( $this->cachedAddress)) {
  338. if ($updateCache) {
  339. $tmpArr = array();
  340. if (!empty($this->alladdress)) {
  341. foreach ($this->alladdress as $eachlogin => $eachaddress) {
  342. $tmpArr[$eachlogin] = strtolower_utf8($eachaddress);
  343. }
  344. $this->alladdress = $tmpArr;
  345. $tmpArr = array();
  346. }
  347. //store property to cache
  348. $cacheStoreData = serialize($this->alladdress);
  349. file_put_contents($cacheName, $cacheStoreData);
  350. $cacheStoreData = '';
  351. } else {
  352. $rawCacheData = file_get_contents($cacheName);
  353. $rawCacheData = unserialize($rawCacheData);
  354. $this->alladdress = $rawCacheData;
  355. $rawCacheData = array();
  356. }
  357. } else {
  358. $tmpArr = array();
  359. if (!empty($this->alladdress)) {
  360. foreach ($this->alladdress as $eachlogin => $eachaddress) {
  361. $tmpArr[$eachlogin] = strtolower_utf8($eachaddress);
  362. }
  363. $this->alladdress = $tmpArr;
  364. $tmpArr = array();
  365. }
  366. }
  367. }
  368. /**
  369. * detects user login by its address
  370. *
  371. * @param string $address address to guess
  372. *
  373. * @return string
  374. */
  375. public function getLogin($address) {
  376. if (!$this->caseSensitive) {
  377. $address = strtolower_utf8($address);
  378. }
  379. if (isset($this->alladdress[$address])) {
  380. return ($this->alladdress[$address]);
  381. } else {
  382. return(false);
  383. }
  384. }
  385. /**
  386. * returns user login by surname
  387. *
  388. * @param string $surname
  389. *
  390. * @return string
  391. */
  392. public function getBySurname($surname) {
  393. if (isset($this->allsurnames[$surname])) {
  394. return ($this->allsurnames[$surname]);
  395. } else {
  396. return(false);
  397. }
  398. }
  399. /**
  400. * Get user login by some phone number
  401. *
  402. * @param string $phoneNumber
  403. * @param bool $onlyMobile
  404. * @param bool $normalizeMobile
  405. *
  406. * @return string
  407. */
  408. public function getByPhone($phoneNumber, $onlyMobile = false, $normalizeMobile = false) {
  409. $result = '';
  410. /**
  411. * Come with us speeding through the night
  412. * As fast as any bird in flight
  413. * Silhouettes against the Mother Moon
  414. * We will be there
  415. * I think it's a bad idea to normalize the phone by code, since this piece of code works current for Ukraine
  416. */
  417. $phoneNumber = ($normalizeMobile) ? $this->normalizePhoneFormat($phoneNumber) : $phoneNumber;
  418. if (!empty($phoneNumber)) {
  419. if (!$onlyMobile) {
  420. if (!empty($this->allPhones) and ! $this->uniqLogin) {
  421. foreach ($this->allPhones as $baseNumber => $userLogin) {
  422. if (ispos((string) $phoneNumber, (string) $baseNumber)) {
  423. $result = $userLogin;
  424. }
  425. }
  426. }
  427. }
  428. if (!empty($this->allExtMobiles) and ! $this->uniqLogin) {
  429. foreach ($this->allExtMobiles as $baseNumber => $userLogin) {
  430. if (ispos((string) $phoneNumber, (string) $baseNumber)) {
  431. $result = $userLogin;
  432. }
  433. }
  434. }
  435. if (!empty($this->allMobiles) and ! $this->uniqLogin) {
  436. foreach ($this->allMobiles as $baseNumber => $userLogin) {
  437. if (ispos((string) $phoneNumber, (string) $baseNumber)) {
  438. $result = $userLogin;
  439. }
  440. }
  441. }
  442. if ($this->uniqLogin) {
  443. $resultTempUniq = array_merge_recursive($this->allPhonesFull, $this->allExtMobilesFull, $this->allMobilesFull);
  444. // Try remove duplicate phone and mobile from one users
  445. foreach ($resultTempUniq as $phone => $dataArr) {
  446. $rawArr = array_unique($dataArr);
  447. if (count($rawArr) == 1 and substr($phone, -10) == substr($phoneNumber, -10)) {
  448. $result = $rawArr[0];
  449. return ($result);
  450. }
  451. }
  452. }
  453. }
  454. return ($result);
  455. }
  456. /**
  457. * Get user login by some phone number. After all calls you must finalize cache with savePhoneTelepathyCache().
  458. *
  459. * @param string $phoneNumber
  460. * @param bool $onlyMobile
  461. * @param bool $normalizeMobile
  462. *
  463. * @return string
  464. */
  465. public function getByPhoneFast($phoneNumber, $onlyMobile = false, $normalizeMobile = false) {
  466. $result = '';
  467. if (isset($this->phoneTelepathyCache[$phoneNumber])) {
  468. $result = $this->phoneTelepathyCache[$phoneNumber];
  469. } else {
  470. $detectedLogin = $this->getByPhone($phoneNumber, $onlyMobile, $normalizeMobile);
  471. $result = $detectedLogin;
  472. $this->phoneTelepathyCache[$phoneNumber] = $detectedLogin;
  473. }
  474. return ($result);
  475. }
  476. /**
  477. * Saves previously detected by phone logins cache
  478. *
  479. * @return void
  480. */
  481. public function savePhoneTelepathyCache() {
  482. $this->cache->set('PHONETELEPATHY', $this->phoneTelepathyCache, self::PHONE_CACHE_TIME);
  483. }
  484. /**
  485. * Cleans phone telepathy cache
  486. *
  487. * @return void
  488. */
  489. public function flushPhoneTelepathyCache() {
  490. $this->cache->delete('PHONETELEPATHY');
  491. }
  492. }
  493. ?>