imdbwebparser.class.php 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858
  1. <?php
  2. /**
  3. * PHP IMDb.com Grabber
  4. *
  5. * This PHP library enables you to scrape data from IMDB.com.
  6. *
  7. *
  8. * If you want to thank me for this library, please buy me something at Amazon
  9. * (https://www.amazon.de/hz/wishlist/ls/8840JITISN9L/) or use
  10. * https://www.paypal.me/FabianBeiner. Thank you!
  11. *
  12. * @author Fabian Beiner <fb@fabianbeiner.de>
  13. * @license https://opensource.org/licenses/MIT The MIT License
  14. * @link https://github.com/FabianBeiner/PHP-IMDB-Grabber/ GitHub Repository
  15. * @version 6.2.0
  16. *
  17. *
  18. * Functionality is the same but modified heavily to remove the does-not-make-sense static helper
  19. * which was not static since it depended on the IMDB class. Also some could not be extended or overwritten
  20. *
  21. */
  22. class IMDB
  23. {
  24. /**
  25. * Set this to true if you run into problems.
  26. */
  27. private bool $IMDB_DEBUG = false;
  28. /**
  29. * @var string Set the preferred language for the User Agent.
  30. */
  31. private string $IMDB_BROWSER_LANG;
  32. /**
  33. * Set this to true if you want to start with normal search and
  34. * if you get no result, it will use the advanced method
  35. */
  36. const IMDB_SEARCH_ORIGINAL = true;
  37. /**
  38. * Set this to true if you want to search for exact titles
  39. * it falls back to false if theres no result
  40. */
  41. const IMDB_EXACT_SEARCH = true;
  42. /**
  43. * Set the sensitivity for search results in percentage.
  44. */
  45. const IMDB_SENSITIVITY = 85;
  46. /**
  47. * @var string The accept string for curl call
  48. */
  49. private string $IMDB_BROWSER_ACCEPT;
  50. /**
  51. * @var string The user-agent string fpr curl call
  52. */
  53. private string $IMDB_BROWSER_AGENT;
  54. /**
  55. * Define the timeout for cURL requests.
  56. */
  57. private int $IMDB_TIMEOUT = 15;
  58. /**
  59. * These are the regular expressions used to extract the data.
  60. * If you don’t know what you’re doing, you shouldn’t touch them.
  61. */
  62. const IMDB_AKA = '~<td[^>]*>\s*Also\s*Known\s*As\s*</td>\s*<td>(.+)</td>~Uis';
  63. const IMDB_ASPECT_RATIO = '~<td[^>]*>Aspect\s*Ratio</td>\s*<td>(.+)</td>~Uis';
  64. const IMDB_AWARDS = '~<div\s*class="titlereference-overview-section">\s*Awards:(.+)</div>~Uis';
  65. const IMDB_BUDGET = '~<td[^>]*>Budget<\/td>\s*<td>\s*(.*)(?:\(estimated\))\s*<\/td>~Ui';
  66. const IMDB_CAST = '~<td[^>]*itemprop="actor"[^>]*>\s*<a\s*href="/name/([^/]*)/\?[^"]*"[^>]*>\s*<span.+>(.+)</span~Ui';
  67. const IMDB_CAST_IMAGE = '~(loadlate="(.*)"[^>]*><\/a>\s+<\/td>\s+)?<td[^>]*itemprop="actor"[^>]*>\s*<a\s*href="\/name\/([^/]*)\/\?[^"]*"[^>]*>\s*<span.+>(.+)<\/span+~Uis';
  68. const IMDB_CERTIFICATION = '~<td[^>]*>\s*Certification\s*</td>\s*<td>(.+)</td>~Ui';
  69. const IMDB_CHAR = '~<td class="character">(?:\s+)<div>(.*)(?:\s+)(?: /| \(.*\)|<\/div>)~Ui';
  70. const IMDB_COLOR = '~<a href="\/search\/title\?colors=(?:.*)">(.*)<\/a>~Ui';
  71. const IMDB_COMPANIES = '~production_companies&ref_=(?:.*)">Edit</a>\s+</header>\s+<ul class="simpleList">(.*)Distributors</h4>~Uis';
  72. const IMDB_COMPANY = '~<li>\s+<a href="\/company\/(co[0-9]+)\/">(.*?)</a>~';
  73. const IMDB_COUNTRY = '~<a href="/country/(\w+)">(.*)</a>~Ui';
  74. const IMDB_CREATOR = '~<div[^>]*>\s*(?:Creator|Creators)\s*:\s*<ul[^>]*>(.+)</ul>~Uxsi';
  75. const IMDB_DISTRIBUTOR = '@href="[^"]*update=[t0-9]+:distributors[^"]*">Edit</a>\s*</header>\s*<ul\s*class="simpleList">(.*):special_effects_companies@Uis';
  76. const IMDB_DISTRIBUTORS = '@\/company\/(co[0-9]+)\/">(.*?)<\/a>\s+(?:\(([0-9]+)\))?\s+(?:\((.*?)\))?\s+(?:\((.*?)\))?\s+(?:\((?:.*?)\))?\s+</li>@';
  77. const IMDB_DIRECTOR = '~<div[^>]*>\s*(?:Director|Directors)\s*:\s*<ul[^>]*>(.+)</ul>~Uxsi';
  78. const IMDB_GENRE = '~href="/genre/([a-zA-Z_-]*)/?">([a-zA-Z_ -]*)</a>~Ui';
  79. const IMDB_GROSS = '~pl-zebra-list__label">Cumulative Worldwide Gross<\/td>\s+<td>\s+(.*)\s+<~Uxsi';
  80. const IMDB_ID = '~((?:tt\d{6,})|(?:itle\?\d{6,}))~';
  81. const IMDB_LANGUAGE = '~<a href="\/language\/(\w+)">(.*)<\/a>~Ui';
  82. const IMDB_LOCATION = '~href="\/search\/title\?locations=(.*)">(.*)<\/a>~Ui';
  83. const IMDB_LOCATIONS = '~href="\/search\/title\?locations=[^>]*>\s?(.*)\s?<\/a>[^"]*<dd>\s?(.*)\s<\/dd>~Ui';
  84. const IMDB_MPAA = '~<li class="ipl-inline-list__item">(?:\s+)(TV-Y|TV-Y7|TV-G|TV-PG|TV-14|TV-MA|G|PG|PG-13|R|NC-17|NR|UR)(?:\s+)<\/li>~Ui';
  85. const IMDB_MUSIC = '~Music by\s*<\/h4>.*<table class=.*>(.*)</table>~Us';
  86. const IMDB_NAME = '~href="/name/(.+)/?(?:\?[^"]*)?"[^>]*>(.+)</a>~Ui';
  87. const IMDB_MOVIE_DESC = '~<section class="titlereference-section-overview">\s+<div>\s+(.*)\s*?</div>\s+<hr>\s+<div class="titlereference-overview-section">~Ui';
  88. const IMDB_SERIES_DESC = '~<div>\s+(?:.*?</a>\s+</span>\s+</div>\s+<hr>\s+<div>\s+)(.*)\s+</div>\s+<hr>\s+<div class="titlereference-overview-section">~Ui';
  89. const IMDB_SERIESEP_DESC = '~All Episodes(?:.*?)</li>\s+(?:.*?)?</ul>\s+</span>\s+<hr>\s+</div>\s+<div>\s+(.*?)\s+</div>\s+<hr>~';
  90. const IMDB_NOT_FOUND_ADV = '~<span>No results.</span>~Ui';
  91. const IMDB_NOT_FOUND_DES = 'Know what this is about';
  92. const IMDB_NOT_FOUND_ORG = '~<h1 class="findHeader">No results found for ~Ui';
  93. const IMDB_PLOT = '~<td[^>]*>\s*Plot\s*Summary\s*</td>\s*<td>\s*<p>\s*(.*)\s*</p>~Ui';
  94. const IMDB_PLOT_KEYWORDS = '~<td[^>]*>Plot\s*Keywords</td>\s*<td>(.+)(?:<a\s*href="/title/[^>]*>[^<]*</a>\s*</li>\s*</ul>\s*)?</td>~Ui';
  95. const IMDB_POSTER = '~<link\s*rel=\'image_src\'\s*href="(.*)">~Ui';
  96. const IMDB_RATING = '~class="ipl-rating-star__rating">(.*)<~Ui';
  97. const IMDB_RATING_COUNT = '~class="ipl-rating-star__total-votes">\((.*)\)<~Ui';
  98. const IMDB_RELEASE_DATE = '~href="/title/[t0-9]*/releaseinfo">(.*)<~Ui';
  99. const IMDB_RUNTIME = '~<td[^>]*>\s*Runtime\s*</td>\s*<td>(.+)</td>~Ui';
  100. const IMDB_SEARCH_ADV = '~text-primary">1[.]</span>\s*<a.href="\/title\/(tt\d{6,})\/(?:.*?)"(?:\s*)>(?:.*?)<\/a>~Ui';
  101. const IMDB_SEARCH_ORG = '~find-title-result">(?:.*?)alt="(.*?)"(?:.*?)href="\/title\/(tt\d{6,})\/(?:.*?)">(.*?)<\/a>~';
  102. const IMDB_SEASONS = '~episodes\?season=(?:\d+)">(\d+)<~Ui';
  103. const IMDB_SOUND_MIX = '~<td[^>]*>\s*Sound\s*Mix\s*</td>\s*<td>(.+)</td>~Ui';
  104. const IMDB_TAGLINE = '~<td[^>]*>\s*Taglines\s*</td>\s*<td>(.+)</td>~Ui';
  105. const IMDB_TITLE = '~itemprop="name">(.*)(<\/h3>|<span)~Ui';
  106. const IMDB_TITLE_EP = '~titlereference-watch-ribbon"(?:.*)itemprop="name">(.*?)\s+<span\sclass="titlereference-title-year">~Ui';
  107. const IMDB_TITLE_ORIG = '~</h3>(?:\s+)(.*)(?:\s+)<span class=\"titlereference-original-title-label~Ui';
  108. const IMDB_TOP250 = '~href="/chart/top(?:tv)?".class(?:.*?)#([0-9]{1,})</a>~Ui';
  109. const IMDB_TRAILER = '~href="/title/(?:tt\d+)/videoplayer/(vi[0-9]*)"~Ui';
  110. const IMDB_TYPE = '~href="/genre/(?:[a-zA-Z_-]*)/?">(?:[a-zA-Z_ -]*)</a>\s+</li>\s+(?:.*item">)\s+(?:<a href="(?:.*)</a>\s+</li>\s+(?:.*item">)\s+)?([a-zA-Z_ -]*)\s+</li>~Ui';
  111. const IMDB_URL = '~https?://(?:.*\.|.*)imdb.com/(?:t|T)itle(?:\?|/)(..\d+)~i';
  112. const IMDB_USER_REVIEW = '~href="/title/[t0-9]*/reviews"[^>]*>([^<]*)\s*User~Ui';
  113. const IMDB_VOTES = '~"ipl-rating-star__total-votes">\s*\((.*)\)\s*<~Ui';
  114. const IMDB_WRITER = '~<div[^>]*>\s*(?:Writer|Writers)\s*:\s*<ul[^>]*>(.+)</ul>~Ui';
  115. const IMDB_YEAR = '~og:title\' content="(?:.*)\((?:.*)(\d{4})(?:.*)\)~Ui';
  116. /**
  117. * @var string The string returned, if nothing is found.
  118. */
  119. public string $sNotFound = 'n/A';
  120. /**
  121. * @var string The ID of the movie.
  122. */
  123. public string $iId = '';
  124. /**
  125. * @var bool Is the content ready?
  126. */
  127. public bool $isReady = false;
  128. /**
  129. * @var string Char that separates multiple entries.
  130. */
  131. public string $sSeparator = ' / ';
  132. /**
  133. * @var string The URL to the movie.
  134. */
  135. public string $sUrl = '';
  136. /**
  137. * @var bool Return responses enclosed in array
  138. */
  139. public bool $bArrayOutput = false;
  140. /**
  141. * @var int Maximum cache time.
  142. */
  143. private int $iCache = 1440;
  144. /**
  145. * @var string The root of the script.
  146. */
  147. private string $sRoot = '';
  148. /**
  149. * @var string Holds the source.
  150. */
  151. private string $sSource = '';
  152. /**
  153. * @var string What to search for?
  154. */
  155. private mixed $sSearchFor = 'all';
  156. /**
  157. * @var array The fields to return at getAll
  158. */
  159. private array $_showFields;
  160. /**
  161. * IMDB constructor. Can now set some options
  162. *
  163. * @param $options array with the following options
  164. * int iCache Custom cache time in minutes.
  165. * string sSearchFor What type to search for?
  166. * string storage Where to store data. Absolute path
  167. * boolean debug Show debug messages or not
  168. */
  169. public function __construct(array $options) {
  170. if(isset($options['debug']) && !empty($options['debug'])) {
  171. $this->IMDB_DEBUG = true;
  172. }
  173. if(isset($options['iCache']) && !empty($options['iCache'])) $this->iCache = (int) $options['iCache'];
  174. $this->sRoot = dirname(__FILE__);
  175. if(isset($options['storage']) && !empty($options['storage'])) {
  176. $this->sRoot = $options['storage'];
  177. }
  178. if(isset($options['sSearchFor']) && !empty($options['sSearchFor'])) {
  179. if (in_array(
  180. $options['sSearchFor'],
  181. [
  182. 'movie',
  183. 'tv',
  184. 'episode',
  185. 'game',
  186. 'documentary',
  187. 'all',
  188. ]
  189. )) {
  190. $this->sSearchFor = $options['sSearchFor'];
  191. }
  192. }
  193. $this->IMDB_BROWSER_AGENT = $options['browserAgent'];
  194. $this->IMDB_BROWSER_LANG = $options['browserLang'];
  195. $this->IMDB_BROWSER_ACCEPT = $options['browserAccept'];
  196. $this->_showFields = array();
  197. if(isset($options['showFields']) && !empty($options['showFields'])) {
  198. $this->_showFields = $options['showFields'];
  199. }
  200. }
  201. /**
  202. * @param string $sSearch
  203. * @throws Exception
  204. */
  205. public function search(string $sSearch): void {
  206. $sSearch = trim($sSearch);
  207. if(empty($sSearch)) {
  208. throw new Exception('Missing search term');
  209. }
  210. if ( ! is_writable($this->sRoot . '/posters') && ! mkdir($this->sRoot . '/posters')) {
  211. throw new Exception('The directory “' . $this->sRoot . '/posters” isn’t writable.');
  212. }
  213. if ( ! is_writable($this->sRoot . '/cache') && ! mkdir($this->sRoot . '/cache')) {
  214. throw new Exception('The directory “' . $this->sRoot . '/cache” isn’t writable.');
  215. }
  216. if ( ! is_writable($this->sRoot . '/cast') && ! mkdir($this->sRoot . '/cast')) {
  217. throw new Exception('The directory “' . $this->sRoot . '/cast” isn’t writable.');
  218. }
  219. if ( ! function_exists('curl_init')) {
  220. throw new Exception('You need to enable the PHP cURL extension.');
  221. }
  222. $this->fetchUrl($sSearch);
  223. }
  224. /**
  225. * @param string $sSearch IMDb URL or movie title to search for.
  226. *
  227. * @return bool True on success, false on failure.
  228. */
  229. private function fetchUrl(string $sSearch): bool {
  230. if ($this->IMDB_DEBUG) {
  231. echo '<pre><b>Running:</b> fetchUrl("' . $sSearch . '")</pre>';
  232. }
  233. // Try to find a valid URL.
  234. $sId = $this->matchRegex($sSearch, self::IMDB_ID, "1");
  235. if (false !== $sId) {
  236. $this->iId = preg_replace('~[\D]~', '', $sId);
  237. $this->sUrl = 'https://www.imdb.com/title/tt' . $this->iId . '/reference';
  238. $bSearch = false;
  239. } else {
  240. switch (strtolower($this->sSearchFor)) {
  241. case 'movie':
  242. $sParameters = '&s=tt&ttype=ft';
  243. break;
  244. case 'tv':
  245. $sParameters = '&s=tt&ttype=tv';
  246. break;
  247. case 'episode':
  248. $sParameters = '&s=tt&ttype=ep';
  249. break;
  250. case 'game':
  251. $sParameters = '&s=tt&ttype=vg';
  252. break;
  253. default:
  254. $sParameters = '&s=tt';
  255. }
  256. $this->sUrl = 'https://www.imdb.com/find/?q=' . rawurlencode(str_replace(' ', '+', $sSearch)) . $sParameters;
  257. $bSearch = true;
  258. // Was this search already performed and cached?
  259. $sRedirectFile = $this->sRoot . '/cache/' . sha1($this->sUrl) . '.redir';
  260. if (is_readable($sRedirectFile)) {
  261. if ($this->IMDB_DEBUG) {
  262. echo '<pre><b>Using redirect:</b> ' . basename($sRedirectFile) . '</pre>';
  263. }
  264. $sRedirect = file_get_contents($sRedirectFile);
  265. $this->sUrl = trim($sRedirect);
  266. $this->iId = preg_replace('~[\D]~', '', $this->matchRegex($sRedirect, self::IMDB_ID, "1"));
  267. $bSearch = false;
  268. }
  269. }
  270. // Does a cache of this movie exist?
  271. if(!empty($this->iId)) {
  272. $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '.cache';
  273. if (is_readable($sCacheFile)) {
  274. $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
  275. if ($iDiff < $this->iCache) {
  276. if ($this->IMDB_DEBUG) {
  277. echo '<pre><b>Using cache:</b> ' . basename($sCacheFile) . '</pre>';
  278. }
  279. $this->sSource = file_get_contents($sCacheFile);
  280. $this->isReady = true;
  281. return true;
  282. }
  283. }
  284. }
  285. // Run cURL on the URL.
  286. if ($this->IMDB_DEBUG) {
  287. echo '<pre><b>Running cURL:</b> ' . $this->sUrl . '</pre>';
  288. }
  289. $aCurlInfo = $this->runCurl($this->sUrl);
  290. $sSource = is_bool($aCurlInfo) ? $aCurlInfo : $aCurlInfo['contents'] ;
  291. if (false === $sSource) {
  292. if ($this->IMDB_DEBUG) {
  293. echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
  294. }
  295. return false;
  296. }
  297. // Was the movie found?
  298. $sMatch = $this->matchRegex($sSource, self::IMDB_SEARCH_ADV, "1");
  299. if (false !== $sMatch) {
  300. $sUrl = 'https://www.imdb.com/title/' . $sMatch . '/reference';
  301. if ($this->IMDB_DEBUG) {
  302. echo '<pre><b>New redirect saved:</b> ' . basename($sRedirectFile) . ' => ' . $sUrl . '</pre>';
  303. }
  304. file_put_contents($sRedirectFile, $sUrl);
  305. $this->sSource = '';
  306. $this->fetchUrl($sUrl);
  307. return true;
  308. }
  309. $sMatch = $this->matchRegex($sSource, self::IMDB_NOT_FOUND_ADV, "0");
  310. if (false !== $sMatch) {
  311. if ($this->IMDB_DEBUG) {
  312. echo '<pre><b>Movie not found:</b> ' . $sSearch . '</pre>';
  313. }
  314. return false;
  315. }
  316. $this->sSource = str_replace(
  317. [
  318. "\n",
  319. "\r\n",
  320. "\r",
  321. ],
  322. '',
  323. $sSource
  324. );
  325. $this->isReady = true;
  326. // Save cache.
  327. if (false === $bSearch) {
  328. if ($this->IMDB_DEBUG) {
  329. echo '<pre><b>Cache created:</b> ' . basename($sCacheFile) . '</pre>';
  330. }
  331. file_put_contents($sCacheFile, $this->sSource);
  332. }
  333. return true;
  334. }
  335. /**
  336. * @return array All data.
  337. */
  338. public function getAll(): array {
  339. $aData = [];
  340. foreach (get_class_methods(__CLASS__) as $method) {
  341. if (substr($method, 0, 3) === 'get' && $method !== 'getAll' && $method !== 'getCastImages') {
  342. if(!empty($this->_showFields) && !in_array($method,$this->_showFields)) continue;
  343. $aData[$method] = [
  344. 'name' => ltrim($method, 'get'),
  345. 'value' => $this->{$method}(),
  346. ];
  347. }
  348. }
  349. array_multisort($aData);
  350. return $aData;
  351. }
  352. /**
  353. * @return string “Also Known As” or $sNotFound.
  354. */
  355. public function getAka(): string {
  356. if (true === $this->isReady) {
  357. $sMatch = $this->matchRegex($this->sSource, self::IMDB_AKA, "1");
  358. if (false !== $sMatch) {
  359. return $this->cleanString($sMatch);
  360. }
  361. }
  362. return $this->sNotFound;
  363. }
  364. /**
  365. * Returns all local names
  366. *
  367. * @return string All local names.
  368. */
  369. public function getAkas()
  370. {
  371. if (true === $this->isReady) {
  372. // Does a cache of this movie exist?
  373. $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_akas.cache';
  374. $bUseCache = false;
  375. if (is_readable($sCacheFile)) {
  376. $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
  377. if ($iDiff < $this->iCache || false) {
  378. $bUseCache = true;
  379. }
  380. }
  381. if ($bUseCache) {
  382. $aRawReturn = file_get_contents($sCacheFile);
  383. $aReturn = unserialize($aRawReturn);
  384. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  385. } else {
  386. $fullAkas = sprintf('https://www.imdb.com/title/tt%s/releaseinfo', $this->iId);
  387. $aCurlInfo = $this->runCurl($fullAkas);
  388. $sSource = $aCurlInfo['contents'];
  389. if (false === $sSource) {
  390. if ($this->IMDB_DEBUG) {
  391. echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
  392. }
  393. return false;
  394. }
  395. $aReturned = $this->matchRegex($sSource, "~<td>(.*?)<\/td>\s+<td>(.*?)<\/td>~");
  396. if ($aReturned) {
  397. $aReturn = [];
  398. foreach ($aReturned[1] as $i => $strName) {
  399. if (strpos($strName, '(') === false) {
  400. $aReturn[] = [
  401. 'title' => $this->cleanString($aReturned[2][$i]),
  402. 'country' => $this->cleanString($strName),
  403. ];
  404. }
  405. }
  406. file_put_contents($sCacheFile, serialize($aReturn));
  407. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  408. }
  409. }
  410. }
  411. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  412. }
  413. /**
  414. * @return string “Aspect Ratio” or $sNotFound.
  415. */
  416. public function getAspectRatio()
  417. {
  418. if (true === $this->isReady) {
  419. $sMatch = $this->matchRegex($this->sSource, self::IMDB_ASPECT_RATIO, "1");
  420. if (false !== $sMatch) {
  421. return $this->cleanString($sMatch);
  422. }
  423. }
  424. return $this->sNotFound;
  425. }
  426. /**
  427. * @return string The awards of the movie or $sNotFound
  428. */
  429. public function getAwards()
  430. {
  431. if (true === $this->isReady) {
  432. $sMatch = $this->matchRegex($this->sSource, self::IMDB_AWARDS, "1");
  433. if (false !== $sMatch) {
  434. return $this->cleanString($sMatch);
  435. }
  436. }
  437. return $this->sNotFound;
  438. }
  439. /**
  440. * @param int $iLimit How many cast members should be returned?
  441. * @param bool $bMore Add … if there are more cast members than printed.
  442. * @param string $sTarget Add a target to the links?
  443. *
  444. * @return string A list with linked cast members or $sNotFound.
  445. */
  446. public function getCastAsUrl($iLimit = 0, $bMore = true, $sTarget = '')
  447. {
  448. if (true === $this->isReady) {
  449. $aMatch = $this->matchRegex($this->sSource, self::IMDB_CAST);
  450. $aReturn = [];
  451. if (count($aMatch[2])) {
  452. foreach ($aMatch[2] as $i => $sName) {
  453. if (0 !== $iLimit && $i >= $iLimit) {
  454. break;
  455. }
  456. $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
  457. $aMatch[1][$i]
  458. ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  459. $sName
  460. ) . '</a>';
  461. }
  462. $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
  463. return $this->arrayOutput(
  464. $this->bArrayOutput,
  465. $this->sSeparator,
  466. $this->sNotFound,
  467. $aReturn,
  468. $bHaveMore
  469. );
  470. }
  471. }
  472. return $this->sNotFound;
  473. }
  474. /**
  475. * @param int $iLimit How many cast members should be returned?
  476. * @param bool $bMore Add … if there are more cast members than printed.
  477. *
  478. * @return string A list with cast members or $sNotFound.
  479. */
  480. public function getCast($iLimit = 0, $bMore = true)
  481. {
  482. if (true === $this->isReady) {
  483. $aMatch = $this->matchRegex($this->sSource, self::IMDB_CAST);
  484. $aReturn = [];
  485. if (count($aMatch[2])) {
  486. foreach ($aMatch[2] as $i => $sName) {
  487. if (0 !== $iLimit && $i >= $iLimit) {
  488. break;
  489. }
  490. $aReturn[] = $this->cleanString($sName);
  491. }
  492. $bMore = (0 !== $iLimit && $bMore && (count($aMatch[2]) > $iLimit) ? '…' : '');
  493. $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
  494. return $this->arrayOutput(
  495. $this->bArrayOutput,
  496. $this->sSeparator,
  497. $this->sNotFound,
  498. $aReturn,
  499. $bHaveMore
  500. );
  501. }
  502. }
  503. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  504. }
  505. /**
  506. * @param int $iLimit How many cast images should be returned?
  507. * @param bool $bMore Add … if there are more cast members than printed.
  508. * @param string $sSize small, mid or big cast images
  509. * @param bool $bDownload Return URL or Download
  510. *
  511. * @return array Array with cast name as key, and image as value.
  512. */
  513. public function getCastImages($iLimit = 0, $bMore = true, $sSize = 'small', $bDownload = false)
  514. {
  515. if (true === $this->isReady) {
  516. $aMatch = $this->matchRegex($this->sSource, self::IMDB_CAST_IMAGE);
  517. $aReturn = [];
  518. if (count($aMatch[4])) {
  519. foreach ($aMatch[4] as $i => $sName) {
  520. if (0 !== $iLimit && $i >= $iLimit) {
  521. break;
  522. }
  523. $sMatch = $aMatch[2][$i];
  524. if ('big' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
  525. $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@.jpg';
  526. } elseif ('mid' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
  527. $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@._V1_UX214_AL_.jpg';
  528. }
  529. if (false === $bDownload) {
  530. $sMatch = $this->cleanString($sMatch);
  531. } else {
  532. $sLocal = $this->saveImageCast($sMatch, $aMatch[3][$i]);
  533. if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
  534. $sMatch = $sLocal;
  535. } else {
  536. //the 'big' image isn't available, try the 'mid' one (vice versa)
  537. if ('big' === strtolower($sSize) && false !== strstr($aMatch[2][$i], '@._')) {
  538. //trying the 'mid' one
  539. $sMatch = substr(
  540. $aMatch[2][$i],
  541. 0,
  542. strpos($aMatch[2][$i], '@._')
  543. ) . '@._V1_UX214_AL_.jpg';
  544. } else {
  545. //trying the 'big' one
  546. $sMatch = substr($aMatch[2][$i], 0, strpos($aMatch[2][$i], '@._')) . '@.jpg';
  547. }
  548. $sLocal = $this->saveImageCast($sMatch, $aMatch[3][$i]);
  549. if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
  550. $sMatch = $sLocal;
  551. } else {
  552. $sMatch = $this->cleanString($aMatch[2][$i]);
  553. }
  554. }
  555. }
  556. $aReturn[$this->cleanString($aMatch[4][$i])] = $sMatch;
  557. }
  558. $bMore = (0 !== $iLimit && $bMore && (count($aMatch[4]) > $iLimit) ? '…' : '');
  559. $bHaveMore = ($bMore && (count($aMatch[4]) > $iLimit));
  560. $aReturn = array_replace(
  561. $aReturn,
  562. array_fill_keys(
  563. array_keys($aReturn, $this->sNotFound),
  564. 'cast/not-found.jpg'
  565. )
  566. );
  567. return $aReturn;
  568. }
  569. }
  570. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  571. }
  572. /**
  573. * @param int $iLimit How many cast members should be returned?
  574. * @param bool $bMore Add … if there are more cast members than
  575. * printed.
  576. * @param string $sTarget Add a target to the links?
  577. *
  578. * @return string A list with linked cast members and their character or
  579. * $sNotFound.
  580. */
  581. public function getCastAndCharacterAsUrl($iLimit = 0, $bMore = true, $sTarget = '')
  582. {
  583. if (true === $this->isReady) {
  584. $aMatch = $this->matchRegex($this->sSource, self::IMDB_CAST);
  585. $aMatchChar = $this->matchRegex($this->sSource, self::IMDB_CHAR);
  586. $aReturn = [];
  587. if (count($aMatch[2])) {
  588. foreach ($aMatch[2] as $i => $sName) {
  589. if (0 !== $iLimit && $i >= $iLimit) {
  590. break;
  591. }
  592. $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
  593. $aMatch[1][$i]
  594. ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  595. $sName
  596. ) . '</a> as ' . $this->cleanString($aMatchChar[1][$i]);
  597. }
  598. $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
  599. return $this->arrayOutput(
  600. $this->bArrayOutput,
  601. $this->sSeparator,
  602. $this->sNotFound,
  603. $aReturn,
  604. $bHaveMore
  605. );
  606. }
  607. }
  608. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  609. }
  610. /**
  611. * @param int $iLimit How many cast members should be returned?
  612. * @param bool $bMore Add … if there are more cast members than printed.
  613. *
  614. * @return string A list with cast members and their character or
  615. * $sNotFound.
  616. */
  617. public function getCastAndCharacter($iLimit = 0, $bMore = true)
  618. {
  619. if (true === $this->isReady) {
  620. $aMatch = $this->matchRegex($this->sSource, self::IMDB_CAST);
  621. $aMatchChar = $this->matchRegex($this->sSource, self::IMDB_CHAR);
  622. $aReturn = [];
  623. if (count($aMatch[2])) {
  624. foreach ($aMatch[2] as $i => $sName) {
  625. if (0 !== $iLimit && $i >= $iLimit) {
  626. break;
  627. }
  628. $aReturn[] = $this->cleanString($sName) . ' as ' . $this->cleanString($aMatchChar[1][$i]);
  629. }
  630. $bHaveMore = ($bMore && (count($aMatch[2]) > $iLimit));
  631. return $this->arrayOutput(
  632. $this->bArrayOutput,
  633. $this->sSeparator,
  634. $this->sNotFound,
  635. $aReturn,
  636. $bHaveMore
  637. );
  638. }
  639. }
  640. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  641. }
  642. /**
  643. * @return string The certification of the movie or $sNotFound.
  644. */
  645. public function getCertification()
  646. {
  647. if (true === $this->isReady) {
  648. $sMatch = $this->matchRegex($this->sSource, self::IMDB_CERTIFICATION, "1");
  649. if (false !== $sMatch) {
  650. return $this->cleanString($sMatch);
  651. }
  652. }
  653. return $this->sNotFound;
  654. }
  655. /**
  656. * @return string Color or $sNotFound.
  657. */
  658. public function getColor()
  659. {
  660. if (true === $this->isReady) {
  661. $sMatch = $this->matchRegex($this->sSource, self::IMDB_COLOR, "1");
  662. if (false !== $sMatch) {
  663. return $this->cleanString($sMatch);
  664. }
  665. }
  666. return $this->sNotFound;
  667. }
  668. /**
  669. * @return string The company producing the movie or $sNotFound.
  670. */
  671. public function getCompany()
  672. {
  673. if (true === $this->isReady) {
  674. $sMatch = $this->getCompanyAsUrl();
  675. if ($this->sNotFound !== $sMatch) {
  676. return $this->cleanString($sMatch);
  677. }
  678. }
  679. return $this->sNotFound;
  680. }
  681. /**
  682. * @param string $sTarget Add a target to the links?
  683. *
  684. * @return string The linked company producing the movie or $sNotFound.
  685. */
  686. public function getCompanyAsUrl($sTarget = '')
  687. {
  688. if (true === $this->isReady) {
  689. $aMatch = $this->matchRegex($this->sSource, self::IMDB_COMPANY);
  690. if (isset($aMatch[2][0])) {
  691. return '<a href="https://www.imdb.com/company/' . $this->cleanString(
  692. $aMatch[1][0]
  693. ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  694. $aMatch[2][0]
  695. ) . '</a>';
  696. }
  697. }
  698. return $this->sNotFound;
  699. }
  700. /**
  701. * @return string A list with countries or $sNotFound.
  702. */
  703. public function getCountry()
  704. {
  705. if (true === $this->isReady) {
  706. $sMatch = $this->getCountryAsUrl();
  707. if ($this->sNotFound !== $sMatch) {
  708. return $this->cleanString($sMatch);
  709. }
  710. }
  711. return $this->sNotFound;
  712. }
  713. /**
  714. * @param string $sTarget Add a target to the links?
  715. *
  716. * @return string A list with linked countries or $sNotFound.
  717. */
  718. public function getCountryAsUrl($sTarget = '')
  719. {
  720. if (true === $this->isReady) {
  721. $aMatch = $this->matchRegex($this->sSource, self::IMDB_COUNTRY);
  722. $aReturn = [];
  723. if (count($aMatch[2])) {
  724. foreach ($aMatch[2] as $i => $sName) {
  725. $aReturn[] = '<a href="https://www.imdb.com/country/' . trim(
  726. $aMatch[1][$i]
  727. ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  728. $sName
  729. ) . '</a>';
  730. }
  731. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  732. }
  733. }
  734. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  735. }
  736. /**
  737. * @return string A list with the creators or $sNotFound.
  738. */
  739. public function getCreator()
  740. {
  741. if (true === $this->isReady) {
  742. $sMatch = $this->getCreatorAsUrl();
  743. if ($this->sNotFound !== $sMatch) {
  744. return $this->cleanString($sMatch);
  745. }
  746. }
  747. return $this->sNotFound;
  748. }
  749. /**
  750. * @param string $sTarget Add a target to the links?
  751. *
  752. * @return string A list with the linked creators or $sNotFound.
  753. */
  754. public function getCreatorAsUrl($sTarget = '')
  755. {
  756. if (true === $this->isReady) {
  757. $sMatch = $this->matchRegex($this->sSource, self::IMDB_CREATOR, "1");
  758. $aMatch = $this->matchRegex($sMatch, self::IMDB_NAME);
  759. $aReturn = [];
  760. if (count($aMatch[2])) {
  761. foreach ($aMatch[2] as $i => $sName) {
  762. $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
  763. $aMatch[1][$i]
  764. ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  765. $sName
  766. ) . '</a>';
  767. }
  768. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  769. }
  770. }
  771. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  772. }
  773. /**
  774. * @return string The description of the movie or $sNotFound.
  775. */
  776. public function getDescription()
  777. {
  778. if (true === $this->isReady) {
  779. $sMatch = $this->matchRegex($this->sSource, self::IMDB_MOVIE_DESC, "1");
  780. if (false !== $sMatch) {
  781. return $this->cleanString($sMatch);
  782. }
  783. }
  784. return $this->sNotFound;
  785. }
  786. /**
  787. * @return string A list with the directors or $sNotFound.
  788. */
  789. public function getDirector()
  790. {
  791. if (true === $this->isReady) {
  792. $sMatch = $this->getDirectorAsUrl();
  793. if ($this->sNotFound !== $sMatch) {
  794. return $this->cleanString($sMatch);
  795. }
  796. }
  797. return $this->sNotFound;
  798. }
  799. /**
  800. * @param string $sTarget Add a target to the links?
  801. *
  802. * @return string A list with the linked directors or $sNotFound.
  803. */
  804. public function getDirectorAsUrl($sTarget = '')
  805. {
  806. if (true === $this->isReady) {
  807. $sMatch = $this->matchRegex($this->sSource, self::IMDB_DIRECTOR, "1");
  808. $aMatch = $this->matchRegex($sMatch, self::IMDB_NAME);
  809. $aReturn = [];
  810. if (count($aMatch[2])) {
  811. foreach ($aMatch[2] as $i => $sName) {
  812. $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
  813. $aMatch[1][$i]
  814. ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  815. $sName
  816. ) . '</a>';
  817. }
  818. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  819. }
  820. }
  821. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  822. }
  823. /**
  824. * @return string A list with the genres or $sNotFound.
  825. */
  826. public function getGenre()
  827. {
  828. if (true === $this->isReady) {
  829. $sMatch = $this->getGenreAsUrl();
  830. if ($this->sNotFound !== $sMatch) {
  831. return $this->cleanString($sMatch);
  832. }
  833. }
  834. return $this->sNotFound;
  835. }
  836. /**
  837. * @param string $sTarget Add a target to the links?
  838. *
  839. * @return string A list with the linked genres or $sNotFound.
  840. */
  841. public function getGenreAsUrl($sTarget = '')
  842. {
  843. if (true === $this->isReady) {
  844. $aMatch = $this->matchRegex($this->sSource, self::IMDB_GENRE);
  845. $aReturn = [];
  846. if (count($aMatch[2])) {
  847. foreach (array_unique($aMatch[2]) as $i => $sName) {
  848. $aReturn[] = '<a href="https://www.imdb.com/search/title?genres=' . $this->cleanString(
  849. $aMatch[1][$i]
  850. ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  851. $sName
  852. ) . '</a>';
  853. }
  854. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  855. }
  856. }
  857. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  858. }
  859. /**
  860. * @return string cumulative worldwide gross or $sNotFound.
  861. */
  862. public function getGross()
  863. {
  864. if (true === $this->isReady) {
  865. $sMatch = $this->matchRegex($this->sSource, self::IMDB_GROSS, "1");
  866. if (false !== $sMatch) {
  867. return $this->cleanString($sMatch);
  868. }
  869. }
  870. return $this->sNotFound;
  871. }
  872. /**
  873. * @return string A list with the languages or $sNotFound.
  874. */
  875. public function getLanguage()
  876. {
  877. if (true === $this->isReady) {
  878. $sMatch = $this->getLanguageAsUrl();
  879. if ($this->sNotFound !== $sMatch) {
  880. return $this->cleanString($sMatch);
  881. }
  882. }
  883. return $this->sNotFound;
  884. }
  885. /**
  886. * @param string $sTarget Add a target to the links?
  887. *
  888. * @return string A list with the linked languages or $sNotFound.
  889. */
  890. public function getLanguageAsUrl($sTarget = '')
  891. {
  892. if (true === $this->isReady) {
  893. $aMatch = $this->matchRegex($this->sSource, self::IMDB_LANGUAGE);
  894. $aReturn = [];
  895. if (count($aMatch[2])) {
  896. foreach ($aMatch[2] as $i => $sName) {
  897. $aReturn[] = '<a href="https://www.imdb.com/language/' . $this->cleanString(
  898. $aMatch[1][$i]
  899. ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  900. $sName
  901. ) . '</a>';
  902. }
  903. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  904. }
  905. }
  906. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  907. }
  908. /**
  909. * @return string A list with the location or $sNotFound.
  910. */
  911. public function getLocation()
  912. {
  913. if (true === $this->isReady) {
  914. $sMatch = $this->getLocationAsUrl();
  915. if ($this->sNotFound !== $sMatch) {
  916. return $this->cleanString($sMatch);
  917. }
  918. }
  919. return $this->sNotFound;
  920. }
  921. /**
  922. * @param string $sTarget Add a target to the links?
  923. *
  924. * @return string A list with the linked location or $sNotFound.
  925. */
  926. public function getLocationAsUrl($sTarget = '')
  927. {
  928. if (true === $this->isReady) {
  929. $aMatch = $this->matchRegex($this->sSource, self::IMDB_LOCATION);
  930. $aReturn = [];
  931. if (count($aMatch[2])) {
  932. foreach ($aMatch[2] as $i => $sName) {
  933. $aReturn[] = '<a href="https://www.imdb.com/search/title?locations=' . $this->cleanString(
  934. $aMatch[1][$i]
  935. ) . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  936. $sName
  937. ) . '</a>';
  938. }
  939. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  940. }
  941. }
  942. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  943. }
  944. /**
  945. * Returns all locations
  946. *
  947. * @return string location
  948. * @return string specification
  949. */
  950. public function getLocations()
  951. {
  952. if (true === $this->isReady) {
  953. // Does a cache of this movie exist?
  954. $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_locations.cache';
  955. $bUseCache = false;
  956. if (is_readable($sCacheFile)) {
  957. $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
  958. if ($iDiff < $this->iCache || false) {
  959. $bUseCache = true;
  960. }
  961. }
  962. if ($bUseCache) {
  963. $aRawReturn = file_get_contents($sCacheFile);
  964. $aReturn = unserialize($aRawReturn);
  965. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  966. } else {
  967. $fullLocations = sprintf('https://www.imdb.com/title/tt%s/locations', $this->iId);
  968. $aCurlInfo = $this->runCurl($fullLocations);
  969. $sSource = $aCurlInfo['contents'];
  970. if (false === $sSource) {
  971. if ($this->IMDB_DEBUG) {
  972. echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
  973. }
  974. return false;
  975. }
  976. $aReturned = $this->matchRegex($sSource, self::IMDB_LOCATIONS);
  977. if ($aReturned) {
  978. $aReturn = [];
  979. foreach ($aReturned[1] as $i => $strName) {
  980. if (strpos($strName, '(') === false) {
  981. $aReturn[] = [
  982. 'location' => $this->cleanString($strName),
  983. ];
  984. }
  985. if (strpos($aReturned[2][$i], '(') !== false) {
  986. $aReturn[] = [
  987. 'specification' => $this->cleanString($aReturned[2][$i]),
  988. ];
  989. }
  990. }
  991. file_put_contents($sCacheFile, serialize($aReturn));
  992. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  993. }
  994. }
  995. }
  996. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  997. }
  998. /**
  999. * @return string The MPAA of the movie or $sNotFound.
  1000. */
  1001. public function getMpaa()
  1002. {
  1003. if (true === $this->isReady) {
  1004. $sMatch = $this->matchRegex($this->sSource, self::IMDB_MPAA, "1");
  1005. if (false !== $sMatch) {
  1006. return $this->cleanString($sMatch);
  1007. }
  1008. }
  1009. return $this->sNotFound;
  1010. }
  1011. /**
  1012. * @return string A list with the plot keywords or $sNotFound.
  1013. */
  1014. public function getPlotKeywords()
  1015. {
  1016. if (true === $this->isReady) {
  1017. $sMatch = $this->matchRegex($this->sSource, self::IMDB_PLOT_KEYWORDS, "1");
  1018. if (false !== $sMatch) {
  1019. $aReturn = explode('|', $this->cleanString($sMatch));
  1020. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  1021. }
  1022. }
  1023. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  1024. }
  1025. /**
  1026. * @param int $iLimit The limit.
  1027. *
  1028. * @return string The plot of the movie or $sNotFound.
  1029. */
  1030. public function getPlot($iLimit = 0)
  1031. {
  1032. if (true === $this->isReady) {
  1033. $sMatch = $this->matchRegex($this->sSource, self::IMDB_PLOT, "1");
  1034. if (false !== $sMatch) {
  1035. if ($iLimit !== 0) {
  1036. return $this->shortText($this->cleanString($sMatch), $iLimit);
  1037. }
  1038. return $this->cleanString($sMatch);
  1039. }
  1040. }
  1041. return $this->sNotFound;
  1042. }
  1043. /**
  1044. * @param string $sSize Small, big, xxs, xs, s poster?
  1045. * @param bool $bDownload Return URL to the poster or download it?
  1046. *
  1047. * @return bool|string Path to the poster.
  1048. */
  1049. public function getPoster($sSize = 'small', $bDownload = false)
  1050. {
  1051. if (true === $this->isReady) {
  1052. $sMatch = $this->matchRegex($this->sSource, self::IMDB_POSTER, "1");
  1053. if (false !== $sMatch) {
  1054. if ('big' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
  1055. $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@.jpg';
  1056. }
  1057. if ('xxs' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
  1058. $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UY67_CR0,0,45,67_AL_.jpg';
  1059. }
  1060. if ('xs' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
  1061. $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UY113_CR0,0,76,113_AL_.jpg';
  1062. }
  1063. if ('s' === strtolower($sSize) && false !== strstr($sMatch, '@._')) {
  1064. $sMatch = substr($sMatch, 0, strpos($sMatch, '@._')) . '@._V1_UX182_CR0,0,182,268_AL_.jpg';
  1065. }
  1066. if (false === $bDownload) {
  1067. return $this->cleanString($sMatch);
  1068. } else {
  1069. $sLocal = $this->saveImage($sMatch, $this->iId);
  1070. if (file_exists(dirname(__FILE__) . '/' . $sLocal)) {
  1071. return $sLocal;
  1072. } else {
  1073. return $sMatch;
  1074. }
  1075. }
  1076. }
  1077. }
  1078. return $this->sNotFound;
  1079. }
  1080. /**
  1081. * @return string The rating of the movie or $sNotFound.
  1082. */
  1083. public function getRating()
  1084. {
  1085. if (true === $this->isReady) {
  1086. $sMatch = $this->matchRegex($this->sSource, self::IMDB_RATING, "1");
  1087. if (false !== $sMatch) {
  1088. return $this->cleanString($sMatch);
  1089. }
  1090. }
  1091. return $this->sNotFound;
  1092. }
  1093. /**
  1094. * @return string The rating count of the movie or $sNotFound.
  1095. */
  1096. public function getRatingCount()
  1097. {
  1098. if (true === $this->isReady) {
  1099. $sMatch = $this->matchRegex($this->sSource, self::IMDB_RATING_COUNT, "1");
  1100. if (false !== $sMatch) {
  1101. return str_replace(',', '', $this->cleanString($sMatch));
  1102. }
  1103. }
  1104. return $this->sNotFound;
  1105. }
  1106. /**
  1107. * Release date doesn't contain all the information we need to create a media and
  1108. * we need this function that checks if users can vote target media (if can, it's released).
  1109. *
  1110. * @return true If the media is released
  1111. */
  1112. public function isReleased()
  1113. {
  1114. $strReturn = $this->getReleaseDate();
  1115. if ($strReturn == $this->sNotFound || $strReturn == 'Not yet released') {
  1116. return false;
  1117. }
  1118. return true;
  1119. }
  1120. /**
  1121. * @return string The release date of the movie or $sNotFound.
  1122. */
  1123. public function getReleaseDate()
  1124. {
  1125. if (true === $this->isReady) {
  1126. $sMatch = $this->matchRegex($this->sSource, self::IMDB_RELEASE_DATE, "1");
  1127. if (false !== $sMatch) {
  1128. return $this->cleanString($sMatch);
  1129. }
  1130. }
  1131. return $this->sNotFound;
  1132. }
  1133. /**
  1134. * Returns all local names
  1135. *
  1136. * @return string country
  1137. * @return string release date
  1138. */
  1139. public function getReleaseDates()
  1140. {
  1141. if (true === $this->isReady) {
  1142. // Does a cache of this movie exist?
  1143. $sCacheFile = $this->sRoot . '/cache/' . sha1($this->iId) . '_akas.cache';
  1144. $bUseCache = false;
  1145. if (is_readable($sCacheFile)) {
  1146. $iDiff = round(abs(time() - filemtime($sCacheFile)) / 60);
  1147. if ($iDiff < $this->iCache || false) {
  1148. $bUseCache = true;
  1149. }
  1150. }
  1151. if ($bUseCache) {
  1152. $aRawReturn = file_get_contents($sCacheFile);
  1153. $aReturn = unserialize($aRawReturn);
  1154. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  1155. } else {
  1156. $fullAkas = sprintf('https://www.imdb.com/title/tt%s/releaseinfo', $this->iId);
  1157. $aCurlInfo = $this->runCurl($fullAkas);
  1158. $sSource = $aCurlInfo['contents'];
  1159. if (false === $sSource) {
  1160. if ($this->IMDB_DEBUG) {
  1161. echo '<pre><b>cURL error:</b> ' . var_dump($aCurlInfo) . '</pre>';
  1162. }
  1163. return false;
  1164. }
  1165. $aReturned = $this->matchRegex(
  1166. $sSource,
  1167. '~>(.*)<\/a><\/td>\s+<td class="release_date">(.*)<\/td>~'
  1168. );
  1169. if ($aReturned) {
  1170. $aReturn = [];
  1171. foreach ($aReturned[1] as $i => $strName) {
  1172. if (strpos($strName, '(') === false) {
  1173. $aReturn[] = [
  1174. 'country' => $this->cleanString($strName),
  1175. 'releasedate' => $this->cleanString($aReturned[2][$i]),
  1176. ];
  1177. }
  1178. }
  1179. file_put_contents($sCacheFile, serialize($aReturn));
  1180. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  1181. }
  1182. }
  1183. }
  1184. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  1185. }
  1186. /**
  1187. * @return string The runtime of the movie or $sNotFound.
  1188. */
  1189. public function getRuntime()
  1190. {
  1191. if (true === $this->isReady) {
  1192. $sMatch = $this->matchRegex($this->sSource, self::IMDB_RUNTIME, "1");
  1193. if (false !== $sMatch) {
  1194. return $this->cleanString($sMatch);
  1195. }
  1196. }
  1197. return $this->sNotFound;
  1198. }
  1199. /**
  1200. * @return string A list with the seasons or $sNotFound.
  1201. */
  1202. public function getSeasons()
  1203. {
  1204. if (true === $this->isReady) {
  1205. $sMatch = $this->getSeasonsAsUrl();
  1206. if ($this->sNotFound !== $sMatch) {
  1207. return $this->cleanString($sMatch);
  1208. }
  1209. }
  1210. return $this->sNotFound;
  1211. }
  1212. /**
  1213. * @param string $sTarget Add a target to the links?
  1214. *
  1215. * @return string A list with the linked seasons or $sNotFound.
  1216. */
  1217. public function getSeasonsAsUrl($sTarget = '')
  1218. {
  1219. if (true === $this->isReady) {
  1220. $aMatch = $this->matchRegex($this->sSource, self::IMDB_SEASONS);
  1221. $aReturn = [];
  1222. if (count($aMatch[1])) {
  1223. foreach (range(1, max($aMatch[1])) as $i => $sName) {
  1224. $aReturn[] = '<a href="https://www.imdb.com/title/tt' . $this->iId . '/episodes?season=' . $sName . '"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $sName . '</a>';
  1225. }
  1226. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  1227. }
  1228. }
  1229. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound);
  1230. }
  1231. /**
  1232. * @return string The sound mix of the movie or $sNotFound.
  1233. */
  1234. public function getSoundMix()
  1235. {
  1236. if (true === $this->isReady) {
  1237. $sMatch = $this->matchRegex($this->sSource, self::IMDB_SOUND_MIX, "1");
  1238. if (false !== $sMatch) {
  1239. return $this->cleanString($sMatch);
  1240. }
  1241. }
  1242. return $this->sNotFound;
  1243. }
  1244. /**
  1245. * @return string The tagline of the movie or $sNotFound.
  1246. */
  1247. public function getTagline()
  1248. {
  1249. if (true === $this->isReady) {
  1250. $sMatch = $this->matchRegex($this->sSource, self::IMDB_TAGLINE, "1");
  1251. if (false !== $sMatch) {
  1252. return $this->cleanString($sMatch);
  1253. }
  1254. }
  1255. return $this->sNotFound;
  1256. }
  1257. /**
  1258. * @param bool $bForceLocal Try to return the original name of the movie.
  1259. *
  1260. * @return string The title of the movie or $sNotFound.
  1261. */
  1262. public function getTitle($bForceLocal = false)
  1263. {
  1264. if (true === $this->isReady) {
  1265. if (true === $bForceLocal) {
  1266. $sMatch = $this->matchRegex($this->sSource, self::IMDB_TITLE_ORIG, "1");
  1267. if (false !== $sMatch && "" !== $sMatch) {
  1268. return $this->cleanString($sMatch);
  1269. }
  1270. }
  1271. $sMatch = $this->matchRegex($this->sSource, self::IMDB_TITLE, "1");
  1272. $sMatch = preg_replace('~\(\d{4}\)$~Ui', '', $sMatch);
  1273. if (false !== $sMatch && "" !== $sMatch) {
  1274. return $this->cleanString($sMatch);
  1275. }
  1276. }
  1277. return $this->sNotFound;
  1278. }
  1279. /**
  1280. * @param bool $bEmbed Link to player directly?
  1281. *
  1282. * @return string The URL to the trailer of the movie or $sNotFound.
  1283. */
  1284. public function getTrailerAsUrl($bEmbed = false)
  1285. {
  1286. if (true === $this->isReady) {
  1287. $sMatch = $this->matchRegex($this->sSource, self::IMDB_TRAILER, "1");
  1288. if (false !== $sMatch) {
  1289. $sUrl = 'https://www.imdb.com/video/imdb/' . $sMatch . '/' . ($bEmbed ? 'player' : '');
  1290. return $this->cleanString($sUrl);
  1291. }
  1292. }
  1293. return $this->sNotFound;
  1294. }
  1295. /**
  1296. * @return string The IMDb URL.
  1297. */
  1298. public function getUrl()
  1299. {
  1300. if (true === $this->isReady) {
  1301. return $this->cleanString(str_replace('reference', '', $this->sUrl));
  1302. }
  1303. return $this->sNotFound;
  1304. }
  1305. /**
  1306. * @return string The user review of the movie or $sNotFound.
  1307. */
  1308. public function getUserReview()
  1309. {
  1310. if (true === $this->isReady) {
  1311. $sMatch = $this->matchRegex($this->sSource, self::IMDB_USER_REVIEW, "1");
  1312. if (false !== $sMatch) {
  1313. return $this->cleanString($sMatch);
  1314. }
  1315. }
  1316. return $this->sNotFound;
  1317. }
  1318. /**
  1319. * @return string The votes of the movie or $sNotFound.
  1320. */
  1321. public function getVotes()
  1322. {
  1323. if (true === $this->isReady) {
  1324. $sMatch = $this->matchRegex($this->sSource, self::IMDB_VOTES, "1");
  1325. if (false !== $sMatch) {
  1326. return $this->cleanString($sMatch);
  1327. }
  1328. }
  1329. return $this->sNotFound;
  1330. }
  1331. /**
  1332. * @return string A list with the writers or $sNotFound.
  1333. */
  1334. public function getWriter()
  1335. {
  1336. if (true === $this->isReady) {
  1337. $sMatch = $this->getWriterAsUrl();
  1338. if ($this->sNotFound !== $sMatch) {
  1339. return $this->cleanString($sMatch);
  1340. }
  1341. }
  1342. return $this->sNotFound;
  1343. }
  1344. /**
  1345. * @param string $sTarget Add a target to the links?
  1346. *
  1347. * @return string A list with the linked writers or $sNotFound.
  1348. */
  1349. public function getWriterAsUrl($sTarget = '')
  1350. {
  1351. if (true === $this->isReady) {
  1352. $sMatch = $this->matchRegex($this->sSource, self::IMDB_WRITER, "1");
  1353. $aMatch = $this->matchRegex($sMatch, self::IMDB_NAME);
  1354. $aReturn = [];
  1355. if (count($aMatch[2])) {
  1356. foreach ($aMatch[2] as $i => $sName) {
  1357. $aReturn[] = '<a href="https://www.imdb.com/name/' . $this->cleanString(
  1358. $aMatch[1][$i]
  1359. ) . '/"' . ($sTarget ? ' target="' . $sTarget . '"' : '') . '>' . $this->cleanString(
  1360. $sName
  1361. ) . '</a>';
  1362. }
  1363. return $this->arrayOutput($this->bArrayOutput, $this->sSeparator, $this->sNotFound, $aReturn);
  1364. }
  1365. }
  1366. return $this->sNotFound;
  1367. }
  1368. /**
  1369. * @return string The year of the movie or $sNotFound.
  1370. */
  1371. public function getYear()
  1372. {
  1373. if (true === $this->isReady) {
  1374. $sMatch = $this->matchRegex($this->sSource, self::IMDB_YEAR, "1");
  1375. if (false !== $sMatch) {
  1376. return $this->cleanString($sMatch);
  1377. }
  1378. }
  1379. return $this->sNotFound;
  1380. }
  1381. /**
  1382. * @return string The budget of the movie or $sNotFound.
  1383. */
  1384. public function getBudget()
  1385. {
  1386. if (true === $this->isReady) {
  1387. $sMatch = $this->matchRegex($this->sSource, self::IMDB_BUDGET, "1");
  1388. if (false !== $sMatch) {
  1389. return $this->cleanString($sMatch);
  1390. }
  1391. }
  1392. return $this->sNotFound;
  1393. }
  1394. /**
  1395. * Regular expression helper.
  1396. *
  1397. * @param string $sContent The content to search in.
  1398. * @param string $sPattern The regular expression.
  1399. * @param string $iIndex The index to return.
  1400. *
  1401. * @return bool If no match was found.
  1402. * @return string If one match was found.
  1403. * @return array If more than one match was found.
  1404. */
  1405. private function matchRegex(string $sContent, string $sPattern, string $iIndex = '')
  1406. {
  1407. preg_match_all($sPattern, $sContent, $aMatches);
  1408. if ($aMatches === false) {
  1409. return false;
  1410. }
  1411. if (is_numeric($iIndex)) {
  1412. if (isset($aMatches[$iIndex][0])) {
  1413. return $aMatches[$iIndex][0];
  1414. }
  1415. return false;
  1416. }
  1417. return $aMatches;
  1418. }
  1419. /**
  1420. * Preferred output in responses with multiple elements
  1421. *
  1422. * @param bool $bArrayOutput Native array or string with separators.
  1423. * @param string $sSeparator String separator.
  1424. * @param string $sNotFound Not found text.
  1425. * @param array $aReturn Original input.
  1426. * @param bool $bHaveMore Have more elements indicator.
  1427. *
  1428. * @return string|array Multiple results separated by selected separator string, or enclosed into native array.
  1429. */
  1430. private function arrayOutput($bArrayOutput, $sSeparator, $sNotFound, $aReturn = '', $bHaveMore = false)
  1431. {
  1432. if ($bArrayOutput) {
  1433. if (empty($aReturn) || ! is_array($aReturn)) {
  1434. return [];
  1435. }
  1436. if ($bHaveMore) {
  1437. $aReturn[] = '…';
  1438. }
  1439. return $aReturn;
  1440. } else {
  1441. if (empty($aReturn) || ! is_array($aReturn)) {
  1442. return $sNotFound;
  1443. }
  1444. foreach ($aReturn as $i => $value) {
  1445. if (is_array($value)) {
  1446. $aReturn[$i] = implode($sSeparator, $value);
  1447. }
  1448. }
  1449. return implode($sSeparator, $aReturn) . (($bHaveMore) ? '…' : '');
  1450. }
  1451. }
  1452. /**
  1453. * @param string $sInput Input (eg. HTML).
  1454. *
  1455. * @return string Cleaned string.
  1456. */
  1457. private function cleanString($sInput)
  1458. {
  1459. $aSearch = [
  1460. 'Full summary &raquo;',
  1461. 'Full synopsis &raquo;',
  1462. 'Add summary &raquo;',
  1463. 'Add synopsis &raquo;',
  1464. 'See more &raquo;',
  1465. 'See why on IMDbPro.',
  1466. "\n",
  1467. "\r",
  1468. ];
  1469. $aReplace = [
  1470. '',
  1471. '',
  1472. '',
  1473. '',
  1474. '',
  1475. '',
  1476. '',
  1477. '',
  1478. ];
  1479. $sInput = str_replace('</li>', ' | ', $sInput);
  1480. $sInput = strip_tags($sInput);
  1481. $sInput = str_replace('&nbsp;', ' ', $sInput);
  1482. $sInput = str_replace($aSearch, $aReplace, $sInput);
  1483. $sInput = html_entity_decode($sInput, ENT_QUOTES | ENT_HTML5);
  1484. $sInput = preg_replace('/\s+/', ' ', $sInput);
  1485. $sInput = trim($sInput);
  1486. $sInput = rtrim($sInput, ' |');
  1487. return ($sInput ? trim($sInput) : $this->sNotFound);
  1488. }
  1489. /**
  1490. * @param string $sText The long text.
  1491. * @param int $iLength The maximum length of the text.
  1492. *
  1493. * @return string The shortened text.
  1494. */
  1495. private function shortText($sText, $iLength = 100)
  1496. {
  1497. if (mb_strlen($sText) <= $iLength) {
  1498. return $sText;
  1499. }
  1500. list($sShort) = explode("\n", wordwrap($sText, $iLength - 1));
  1501. if (substr($sShort, -1) !== '.') {
  1502. return $sShort . '…';
  1503. }
  1504. return $sShort;
  1505. }
  1506. /**
  1507. * @param string $sUrl The URL to the image to download.
  1508. * @param int $iId The ID of the movie.
  1509. *
  1510. * @return string Local path.
  1511. */
  1512. private function saveImage($sUrl, $iId)
  1513. {
  1514. if (preg_match('~title_addposter.jpg|imdb-share-logo.png~', $sUrl)) {
  1515. return 'posters/not-found.jpg';
  1516. }
  1517. $sFilename = $this->sRoot . '/posters/' . $iId . '.jpg';
  1518. if (file_exists($sFilename)) {
  1519. return 'posters/' . $iId . '.jpg';
  1520. }
  1521. $aCurlInfo = $this->runCurl($sUrl, true);
  1522. $sData = $aCurlInfo['contents'];
  1523. if (false === $sData) {
  1524. return 'posters/not-found.jpg';
  1525. }
  1526. $oFile = fopen($sFilename, 'x');
  1527. fwrite($oFile, $sData);
  1528. fclose($oFile);
  1529. return 'posters/' . $iId . '.jpg';
  1530. }
  1531. /**
  1532. * @param string $sUrl The URL to fetch.
  1533. * @param bool $bDownload Download?
  1534. *
  1535. * @return bool|mixed Array on success, false on failure.
  1536. */
  1537. private function runCurl($sUrl, $bDownload = false)
  1538. {
  1539. $oCurl = curl_init($sUrl);
  1540. curl_setopt_array(
  1541. $oCurl,
  1542. [
  1543. CURLOPT_CONNECTTIMEOUT => $this->IMDB_TIMEOUT,
  1544. CURLOPT_ENCODING => '',
  1545. CURLOPT_FOLLOWLOCATION => true,
  1546. CURLOPT_FRESH_CONNECT => 0,
  1547. CURLOPT_HEADER => ($bDownload ? false : true),
  1548. CURLOPT_HTTPHEADER => [
  1549. 'Accept: '.$this->IMDB_BROWSER_ACCEPT,
  1550. 'Accept-Language: ' . $this->IMDB_BROWSER_LANG,
  1551. ],
  1552. CURLOPT_REFERER => 'https://www.imdb.com',
  1553. CURLOPT_RETURNTRANSFER => 1,
  1554. CURLOPT_SSL_VERIFYHOST => 0,
  1555. CURLOPT_SSL_VERIFYPEER => 0,
  1556. CURLOPT_TIMEOUT => $this->IMDB_TIMEOUT,
  1557. CURLOPT_USERAGENT => $this->IMDB_BROWSER_AGENT,
  1558. CURLOPT_VERBOSE => 0
  1559. ]
  1560. );
  1561. $sOutput = curl_exec($oCurl);
  1562. $aCurlInfo = curl_getinfo($oCurl);
  1563. curl_close($oCurl);
  1564. $aCurlInfo['contents'] = $sOutput;
  1565. if (200 !== $aCurlInfo['http_code']) {
  1566. if ($this->IMDB_DEBUG) {
  1567. echo '<pre><b>cURL returned wrong HTTP code “' . $aCurlInfo['http_code'] . '”, aborting.</b></pre>';
  1568. }
  1569. return false;
  1570. }
  1571. return $aCurlInfo;
  1572. }
  1573. /**
  1574. * @param string $sUrl The URL to the image to download.
  1575. * @param int $cId The cast ID of the actor.
  1576. *
  1577. * @return string Local path.
  1578. */
  1579. private function saveImageCast($sUrl, $cId)
  1580. {
  1581. if ( ! preg_match('~http~', $sUrl)) {
  1582. return 'cast/not-found.jpg';
  1583. }
  1584. $sFilename = $this->sRoot . '/cast/' . $cId . '.jpg';
  1585. if (file_exists($sFilename)) {
  1586. return 'cast/' . $cId . '.jpg';
  1587. }
  1588. $aCurlInfo = $this->runCurl($sUrl, true);
  1589. $sData = $aCurlInfo['contents'];
  1590. if (false === $sData) {
  1591. return 'cast/not-found.jpg';
  1592. }
  1593. $oFile = fopen($sFilename, 'x');
  1594. fwrite($oFile, $sData);
  1595. fclose($oFile);
  1596. return 'cast/' . $cId . '.jpg';
  1597. }
  1598. /**
  1599. * Makes strings with $this->sSeparator as separator result in an array
  1600. *
  1601. * @param $string
  1602. * @return array|string
  1603. */
  1604. public function slashStringAsArray($string) {
  1605. $ret = $string;
  1606. if(strstr($string, $this->sSeparator)) {
  1607. $ret = array();
  1608. $_t = explode($this->sSeparator, $string);
  1609. foreach ($_t as $v) {
  1610. $v = trim($v);
  1611. if(!empty($v)) {
  1612. $ret[] = $v;
  1613. }
  1614. }
  1615. }
  1616. return $ret;
  1617. }
  1618. }