1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\OEmbedFiles;
9:
10: /**
11: * This module extends functionality of Files module.
12: * It provides ability to add shortcuts based on [oembed](http://oembed.com/) data format.
13: *
14: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
15: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
16: * @copyright Copyright (c) 2023, Afterlogic Corp.
17: *
18: * @property Settings $oModuleSettings
19: *
20: * @package Modules
21: */
22: class Module extends \Aurora\System\Module\AbstractModule
23: {
24: protected $aProviders = array();
25:
26: /***** private functions *****/
27: /**
28: * Initializes module.
29: *
30: * @ignore
31: */
32: public function init()
33: {
34: $this->loadProviders();
35:
36: $this->subscribeEvent('Files::GetLinkType', array($this, 'onGetLinkType'));
37: $this->subscribeEvent('Files::CheckUrl', array($this, 'onCheckUrl'));
38: $this->subscribeEvent('Files::PopulateFileItem::after', array($this, 'onAfterPopulateFileItem'));
39: }
40:
41: /**
42: * @return Module
43: */
44: public static function getInstance()
45: {
46: return parent::getInstance();
47: }
48:
49: /**
50: * @return Module
51: */
52: public static function Decorator()
53: {
54: return parent::Decorator();
55: }
56:
57: /**
58: * @return Settings
59: */
60: public function getModuleSettings()
61: {
62: return $this->oModuleSettings;
63: }
64:
65: /**
66: * Returns **true** if oembed file info for specified link was found.
67: *
68: * @ignore
69: * @param string $Link File link.
70: * @param boolean $Result Is passed by reference.
71: * @return boolean
72: */
73: public function onGetLinkType($Link, &$Result)
74: {
75: $Result = !!($this->getOembedFileInfo($Link));
76: return $Result; // break or not executing of event handlers
77: }
78:
79: /**
80: * Writes to $mResult variable information about link.
81: *
82: * @ignore
83: * @param array $aArgs
84: * @param array $mResult
85: */
86: public function onCheckUrl($aArgs, &$mResult)
87: {
88: $iUserId = \Aurora\System\Api::getAuthenticatedUserId();
89:
90: if ($iUserId) {
91: if (!empty($aArgs['Url'])) {
92: $oInfo = $this->getOembedFileInfo($aArgs['Url']);
93: if ($oInfo) {
94: $mResult['Size'] = isset($oInfo->fileSize) ? $oInfo->fileSize : '';
95: $mResult['Name'] = isset($oInfo->title) ? $oInfo->title : '';
96: $mResult['LinkType'] = 'oembeded';
97: $mResult['Thumb'] = isset($oInfo->thumbnailUrl) ? $oInfo->thumbnailUrl : null;
98: }
99: }
100: }
101: }
102:
103: /**
104: * Populates file item.
105: *
106: * @ignore
107: * @param \Aurora\Modules\Files\Classes\FileItem $oItem
108: * @return boolean
109: */
110: public function onAfterPopulateFileItem($aArgs, &$oItem)
111: {
112: $bBreak = false;
113: if ($oItem->IsLink) {
114: $Result = $this->getOembedFileInfo($oItem->LinkUrl);
115:
116: if ($Result) {
117: $oItem->LinkType = 'oembeded';
118: $oItem->Name = isset($Result->title) ? $Result->title : $oItem->Name;
119: $oItem->Size = isset($Result->fileSize) ? $Result->fileSize : $oItem->Size;
120: $oItem->OembedHtml = isset($Result->html) ? $Result->html : $oItem->OembedHtml;
121: $oItem->Thumb = true;
122: $oItem->ThumbnailUrl = $Result->thumbnailUrl;
123: $oItem->IsExternal = true;
124: }
125: $bBreak = !!$Result;
126: }
127: return $bBreak; // break or not executing of event handlers
128: }
129:
130: /**
131: * Returns Oembed information for file.
132: *
133: * @param string $sUrl
134: * @return \Aurora\Modules\OEmbedFiles\Classes\FileInfo
135: */
136: protected function getOembedFileInfo($sUrl)
137: {
138: $mResult = false;
139: $sOembedUrl = '';
140:
141: foreach ($this->aProviders as $aProvider) {
142: if (\preg_match("/" . $aProvider['patterns'] . "/", $sUrl)) {
143: $sOembedUrl = $aProvider['url'] . $sUrl;
144: break;
145: }
146: }
147:
148: if (false !== \strpos($sUrl, 'instagram.com')) {
149: $sUrl = \str_replace('instagram.com', 'instagr.am', $sUrl);
150: $sOembedUrl = 'https://api.instagram.com/oembed?url=' . $sUrl;
151: }
152:
153: if (\strlen($sOembedUrl) > 0) {
154: $oCurl = \curl_init();
155: \curl_setopt_array($oCurl, array(
156: CURLOPT_URL => $sOembedUrl,
157: CURLOPT_HEADER => 0,
158: CURLOPT_RETURNTRANSFER => true,
159: CURLOPT_FOLLOWLOCATION => true,
160: CURLOPT_ENCODING => '',
161: CURLOPT_AUTOREFERER => true,
162: CURLOPT_SSL_VERIFYPEER => false, //required for https urls
163: CURLOPT_CONNECTTIMEOUT => 5,
164: CURLOPT_TIMEOUT => 5,
165: CURLOPT_MAXREDIRS => 5
166: ));
167: $sResult = \curl_exec($oCurl);
168: \curl_close($oCurl);
169: $oResult = \json_decode($sResult);
170:
171: if ($oResult) {
172: $sSearch = $oResult->html;
173: $aPatterns = array('/ width="\d+."/', '/ height="\d+."/', '/(src="[^\"]+)/');
174: $aResults = array(' width="896"', ' height="504"', '$1?&autoplay=1&auto_play=true');
175: $oResult->html = \preg_replace($aPatterns, $aResults, $sSearch);
176:
177: $aRemoteFileInfo = \Aurora\System\Utils::GetRemoteFileInfo($sUrl);
178: $oResult->fileSize = $aRemoteFileInfo['size'];
179:
180: $oResult->thumbnailUrl = isset($oResult->thumbnail_url) ? $oResult->thumbnail_url : '';
181:
182: $mResult = new \Aurora\Modules\OEmbedFiles\Classes\FileInfo();
183: $mResult->html = $oResult->html;
184: $mResult->fileSize = $oResult->fileSize;
185: $mResult->thumbnailUrl = $oResult->thumbnailUrl;
186: }
187: }
188:
189: return $mResult;
190: }
191:
192: /**
193: * Loads providers from file.
194: */
195: protected function loadProviders()
196: {
197: $sFile = __DIR__ . DIRECTORY_SEPARATOR . 'providers.json';
198: if (\file_exists($sFile)) {
199: $sJsonData = \file_get_contents($sFile);
200: $aJsonData = \json_decode($sJsonData, true);
201: foreach ($aJsonData as $aProvider) {
202: $this->aProviders[$aProvider['title']] = array(
203: 'patterns' => $aProvider['url_re'],
204: 'url' => $aProvider['endpoint_url']
205: );
206: }
207: }
208: }
209: /***** private functions *****/
210: }
211: