1 | <?php |
||||||
2 | /** |
||||||
3 | * @link https://dukt.net/twitter/ |
||||||
4 | * @copyright Copyright (c) Dukt |
||||||
5 | * @license https://github.com/dukt/twitter/blob/master/LICENSE.md |
||||||
6 | */ |
||||||
7 | |||||||
8 | namespace dukt\twitter\helpers; |
||||||
9 | |||||||
10 | use Craft; |
||||||
11 | use craft\helpers\FileHelper; |
||||||
12 | use DateInterval; |
||||||
13 | use DateTime; |
||||||
14 | use dukt\twitter\Plugin; |
||||||
15 | use GuzzleHttp\Exception\GuzzleException; |
||||||
16 | |||||||
17 | /** |
||||||
18 | * Twitter Helper |
||||||
19 | * |
||||||
20 | * @author Dukt <[email protected]> |
||||||
21 | * @since 3.0 |
||||||
22 | */ |
||||||
23 | class TwitterHelper |
||||||
24 | { |
||||||
25 | // Public Methods |
||||||
26 | // ========================================================================= |
||||||
27 | |||||||
28 | /** |
||||||
29 | * Returns a user image from a Twitter user ID for given size. Default size is 48. |
||||||
30 | * |
||||||
31 | * @param int $remoteUserId |
||||||
32 | * @param int $size |
||||||
33 | * |
||||||
34 | * @return string|null |
||||||
35 | * @throws GuzzleException |
||||||
36 | * @throws \craft\errors\ImageException |
||||||
37 | * @throws \yii\base\Exception |
||||||
38 | */ |
||||||
39 | public static function getUserProfileImageResourceUrl($remoteUserId, $size = 48) |
||||||
40 | { |
||||||
41 | $baseDir = Craft::$app->getPath()->getRuntimePath().DIRECTORY_SEPARATOR.'twitter'.DIRECTORY_SEPARATOR.'userimages'.DIRECTORY_SEPARATOR.$remoteUserId; |
||||||
42 | $originalDir = $baseDir.DIRECTORY_SEPARATOR.'original'; |
||||||
43 | $dir = $baseDir.DIRECTORY_SEPARATOR.$size; |
||||||
44 | $file = null; |
||||||
45 | |||||||
46 | if (is_dir($dir)) { |
||||||
47 | $files = FileHelper::findFiles($dir); |
||||||
48 | |||||||
49 | if (count($files) > 0) { |
||||||
50 | $file = $files[0]; |
||||||
51 | } |
||||||
52 | } |
||||||
53 | |||||||
54 | if (!$file) { |
||||||
55 | // Retrieve original image |
||||||
56 | $originalPath = null; |
||||||
57 | |||||||
58 | if (is_dir($originalDir)) { |
||||||
59 | $originalFiles = FileHelper::findFiles($originalDir); |
||||||
60 | |||||||
61 | if (count($originalFiles) > 0) { |
||||||
62 | $originalPath = $originalFiles[0]; |
||||||
63 | } |
||||||
64 | } |
||||||
65 | if (!$originalPath) { |
||||||
66 | $user = Plugin::getInstance()->getApi()->getUserById($remoteUserId); |
||||||
67 | |||||||
68 | $url = str_replace('_normal', '', $user['profile_image_url_https']); |
||||||
69 | $name = pathinfo($url, PATHINFO_BASENAME); |
||||||
70 | $originalPath = $originalDir.DIRECTORY_SEPARATOR.$name; |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
71 | |||||||
72 | FileHelper::createDirectory($originalDir); |
||||||
73 | $client = new \GuzzleHttp\Client(); |
||||||
74 | $response = $client->request('GET', $url, [ |
||||||
75 | 'sink' => $originalPath, |
||||||
76 | ]); |
||||||
77 | |||||||
78 | if ($response->getStatusCode() != 200) { |
||||||
79 | return null; |
||||||
80 | } |
||||||
81 | } else { |
||||||
82 | $name = pathinfo($originalPath, PATHINFO_BASENAME); |
||||||
83 | } |
||||||
84 | |||||||
85 | // Generate the thumb |
||||||
86 | $path = $dir.DIRECTORY_SEPARATOR.$name; |
||||||
87 | FileHelper::createDirectory($dir); |
||||||
88 | Craft::$app->getImages()->loadImage($originalPath, false, $size) |
||||||
89 | ->scaleToFit($size, $size) |
||||||
90 | ->saveAs($path); |
||||||
91 | } else { |
||||||
92 | $name = pathinfo($file, PATHINFO_BASENAME); |
||||||
93 | } |
||||||
94 | |||||||
95 | return Craft::$app->getAssetManager()->getPublishedUrl($dir, true)."/{$name}"; |
||||||
0 ignored issues
–
show
The call to
yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() Are you sure
Craft::app->getAssetMana...ublishedUrl($dir, true) of type false|mixed|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
96 | } |
||||||
97 | |||||||
98 | /** |
||||||
99 | * Extract the tweet ID from a tweet URL, or simply returns the ID. |
||||||
100 | * |
||||||
101 | * @param $urlOrId |
||||||
102 | * |
||||||
103 | * @return int|null |
||||||
104 | */ |
||||||
105 | public static function extractTweetId($urlOrId) |
||||||
106 | { |
||||||
107 | if (preg_match('/^\d+$/', $urlOrId)) { |
||||||
108 | // If the string is a number, return it right away |
||||||
109 | return (int)$urlOrId; |
||||||
110 | } |
||||||
111 | |||||||
112 | if (preg_match('/\/status(es)?\/(\d+)\/?$/', $urlOrId, $matches)) { |
||||||
113 | // Extract the tweet ID from the URL |
||||||
114 | return (int)$matches[2]; |
||||||
115 | } |
||||||
116 | |||||||
117 | return null; |
||||||
118 | } |
||||||
119 | |||||||
120 | /** |
||||||
121 | * Formats a duration to seconds. |
||||||
122 | * |
||||||
123 | * @param string $duration |
||||||
124 | * |
||||||
125 | * @return int |
||||||
126 | * @throws \Exception |
||||||
127 | */ |
||||||
128 | public static function durationToSeconds($duration): int |
||||||
129 | { |
||||||
130 | $date = new DateTime; |
||||||
131 | $current = $date->getTimestamp(); |
||||||
132 | $date->add(new DateInterval($duration)); |
||||||
133 | |||||||
134 | return $date->getTimestamp() - $current; |
||||||
135 | } |
||||||
136 | |||||||
137 | /** |
||||||
138 | * Formats a date to a time ago string like “3 days ago”. |
||||||
139 | * |
||||||
140 | * @param DateTime|string $date |
||||||
141 | * |
||||||
142 | * @return string |
||||||
143 | */ |
||||||
144 | public static function timeAgo($date): string |
||||||
145 | { |
||||||
146 | if (is_string($date)) { |
||||||
147 | $date = new DateTime($date); |
||||||
148 | } |
||||||
149 | |||||||
150 | $now = new DateTime(); |
||||||
151 | |||||||
152 | $difference = $now->getTimestamp() - $date->getTimestamp(); |
||||||
153 | |||||||
154 | $duration = self::secondsToHumanTimeDuration($difference); |
||||||
155 | |||||||
156 | return Craft::t('twitter', '{duration} ago', ['duration' => $duration]); |
||||||
157 | } |
||||||
158 | |||||||
159 | /** |
||||||
160 | * Seconds to human duration. |
||||||
161 | * |
||||||
162 | * @param int $seconds The number of seconds. |
||||||
163 | * @return string The duration. |
||||||
164 | */ |
||||||
165 | public static function secondsToHumanTimeDuration($seconds): string |
||||||
166 | { |
||||||
167 | $periods = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year', 'decade']; |
||||||
168 | $lengths = ['60', '60', '24', '7', '4.35', '12', '10']; |
||||||
169 | |||||||
170 | $difference = $seconds; |
||||||
171 | |||||||
172 | for ($j = 0; $difference >= $lengths[$j] && $j < count($lengths) - 1; $j++) { |
||||||
173 | $difference /= $lengths[$j]; |
||||||
174 | } |
||||||
175 | |||||||
176 | $difference = round($difference); |
||||||
177 | |||||||
178 | if ($difference != 1) { |
||||||
179 | $periods[$j] .= 's'; |
||||||
180 | } |
||||||
181 | |||||||
182 | return Craft::t('twitter', '{difference} {period}', ['difference' => $difference, 'period' => $periods[$j]]); |
||||||
183 | } |
||||||
184 | } |
||||||
185 |