| 1 |
<?php |
| 2 |
|
| 3 |
// Exit if accessed directly |
| 4 |
if (!defined('ABSPATH')) { |
| 5 |
exit(); |
| 6 |
} |
| 7 |
|
| 8 |
class Vimeography_Helpers |
| 9 |
{ |
| 10 |
/** |
| 11 |
* [apply_common_formatting description] |
| 12 |
* @param [type] $data [description] |
| 13 |
* @return [type] [description] |
| 14 |
*/ |
| 15 |
public function apply_common_formatting($data) |
| 16 |
{ |
| 17 |
$items = array(); |
| 18 |
|
| 19 |
$should_linkify_descriptions = apply_filters( |
| 20 |
'vimeography.settings.linkify_descriptions', |
| 21 |
true, |
| 22 |
$data |
| 23 |
); |
| 24 |
|
| 25 |
foreach ($data as $item) { |
| 26 |
// status can be one of the following: |
| 27 |
// 'available';'uploading''transcoding';'uploading_error';'transcoding_error'; |
| 28 |
if ($item->status !== 'available') { |
| 29 |
continue; |
| 30 |
} |
| 31 |
|
| 32 |
/** |
| 33 |
* Deprecated, use `id` below instead |
| 34 |
* @var [type] |
| 35 |
*/ |
| 36 |
$item->video_id = str_replace('/', '', strrchr($item->link, '/')); |
| 37 |
|
| 38 |
/** |
| 39 |
* @since 2.0 |
| 40 |
* @var $id Video ID |
| 41 |
*/ |
| 42 |
$item->id = absint(str_replace('/', '', strrchr($item->uri, '/'))); |
| 43 |
|
| 44 |
if ($item->duration && !strpos($item->duration, ':')) { |
| 45 |
$item->duration = $this->seconds_to_minutes($item->duration); |
| 46 |
} |
| 47 |
|
| 48 |
$item->human_created_time = date( |
| 49 |
'F j, Y', |
| 50 |
strtotime($item->created_time) |
| 51 |
); |
| 52 |
|
| 53 |
$item = $this->format_video_thumbnails($item); |
| 54 |
|
| 55 |
// Linkify any URLs in the description |
| 56 |
if ($should_linkify_descriptions) { |
| 57 |
$item->description = $this->link_urls(nl2br($item->description)); |
| 58 |
} |
| 59 |
|
| 60 |
/** |
| 61 |
* Deprecated, use filter below. |
| 62 |
* |
| 63 |
* @var [type] |
| 64 |
*/ |
| 65 |
$item = apply_filters('vimeography/edit-video/' . $item->video_id, $item); |
| 66 |
|
| 67 |
/** |
| 68 |
* @since 2.0 |
| 69 |
* @var [type] |
| 70 |
*/ |
| 71 |
$item = apply_filters('vimeography.video.edit', $item, $item->id); |
| 72 |
$items[] = $item; |
| 73 |
} |
| 74 |
|
| 75 |
/** |
| 76 |
* Deprecated, use filter below. |
| 77 |
* @var [type] |
| 78 |
*/ |
| 79 |
$items = apply_filters('vimeography/edit-videos', $items); |
| 80 |
|
| 81 |
/** |
| 82 |
* @since 2.0 |
| 83 |
* @var [type] |
| 84 |
*/ |
| 85 |
$items = apply_filters('vimeography.videos.edit', $items); |
| 86 |
|
| 87 |
return $items; |
| 88 |
} |
| 89 |
|
| 90 |
/** |
| 91 |
* Sort the Vimeo thumbnails into different keys based on their index |
| 92 |
* in the returned pictures array from Vimeo |
| 93 |
* |
| 94 |
* @param [type] $item [description] |
| 95 |
* @return [type] [description] |
| 96 |
*/ |
| 97 |
public function format_video_thumbnails($item) |
| 98 |
{ |
| 99 |
$sizes = $item->pictures->sizes; |
| 100 |
|
| 101 |
// Format the video thumbnails |
| 102 |
$count = count($sizes); |
| 103 |
|
| 104 |
for ($i = 0; $i < $count; $i++) { |
| 105 |
switch ($i) { |
| 106 |
case 2: |
| 107 |
$item->thumbnail_tiny = $sizes[$i]->link; |
| 108 |
$item->thumbnail_tiny_with_play_button = |
| 109 |
$sizes[$i]->link_with_play_button; |
| 110 |
break; |
| 111 |
case 3: |
| 112 |
$item->thumbnail_small = $sizes[$i]->link; |
| 113 |
$item->thumbnail_small_with_play_button = |
| 114 |
$sizes[$i]->link_with_play_button; |
| 115 |
break; |
| 116 |
case 4: |
| 117 |
$item->thumbnail_medium = $sizes[$i]->link; |
| 118 |
$item->thumbnail_medium_with_play_button = |
| 119 |
$sizes[$i]->link_with_play_button; |
| 120 |
break; |
| 121 |
case 5: |
| 122 |
$item->thumbnail_large = $sizes[$i]->link; |
| 123 |
$item->thumbnail_large_with_play_button = |
| 124 |
$sizes[$i]->link_with_play_button; |
| 125 |
break; |
| 126 |
default: |
| 127 |
break; |
| 128 |
} |
| 129 |
} |
| 130 |
|
| 131 |
return $item; |
| 132 |
} |
| 133 |
|
| 134 |
/** |
| 135 |
* Converts the video's duration in seconds to the MM:SS format. |
| 136 |
* |
| 137 |
* @access public |
| 138 |
* @param mixed $seconds |
| 139 |
* @return void |
| 140 |
*/ |
| 141 |
public function seconds_to_minutes($seconds) |
| 142 |
{ |
| 143 |
/// get minutes |
| 144 |
$minResult = floor($seconds / 60); |
| 145 |
|
| 146 |
/// if minutes is between 0-9, add a "0" --> 00-09 |
| 147 |
if ($minResult < 10) { |
| 148 |
$minResult = 0 . $minResult; |
| 149 |
} |
| 150 |
|
| 151 |
/// get sec |
| 152 |
// HT: Clark Bilorusky http://clarkbilorusky.com |
| 153 |
$secResult = floor(($seconds / 60 - $minResult) * 60); |
| 154 |
|
| 155 |
/// if secondes is between 0-9, add a "0" --> 00-09 |
| 156 |
if ($secResult < 10) { |
| 157 |
$secResult = 0 . $secResult; |
| 158 |
} |
| 159 |
|
| 160 |
/// return result |
| 161 |
return $minResult . ":" . $secResult; |
| 162 |
} |
| 163 |
|
| 164 |
/** |
| 165 |
* [get_featured_embed description] |
| 166 |
* @param [type] $link [description] |
| 167 |
* @return [type] [description] |
| 168 |
*/ |
| 169 |
public function get_featured_embed($link) |
| 170 |
{ |
| 171 |
$params = array( |
| 172 |
'url' => $link, |
| 173 |
'autoplay' => 0, |
| 174 |
'title' => 0, |
| 175 |
'portrait' => 0, |
| 176 |
'byline' => 0, |
| 177 |
'api' => 1, |
| 178 |
'player_id' => 'vimeography' . rand('1', '999999') |
| 179 |
); |
| 180 |
|
| 181 |
$query = http_build_query($params); |
| 182 |
|
| 183 |
$oembed = wp_remote_get('https://vimeo.com/api/oembed.json?' . $query); |
| 184 |
|
| 185 |
if (is_wp_error($oembed)) { |
| 186 |
throw new Vimeography_Exception( |
| 187 |
__( |
| 188 |
'Vimeography could not retrieve the featured video: ', |
| 189 |
'vimeography' |
| 190 |
) . $oembed->get_error_message() |
| 191 |
); |
| 192 |
} else { |
| 193 |
switch ($oembed['response']['code']) { |
| 194 |
case 200: |
| 195 |
$oembed = json_decode($oembed['body']); |
| 196 |
$oembed->html = str_replace( |
| 197 |
'<iframe', |
| 198 |
'<iframe id="' . $params['player_id'] . '"', |
| 199 |
$oembed->html |
| 200 |
); |
| 201 |
return $oembed->html; |
| 202 |
case 403: |
| 203 |
throw new Vimeography_Exception( |
| 204 |
__( |
| 205 |
'Your video privacy settings for must be adjusted to allow displaying this video on your site.', |
| 206 |
'vimeography' |
| 207 |
) |
| 208 |
); |
| 209 |
default: |
| 210 |
break; |
| 211 |
} |
| 212 |
} |
| 213 |
} |
| 214 |
|
| 215 |
/** |
| 216 |
* Truncate strings to defined limit. |
| 217 |
* Original PHP code by Chirp Internet: www.chirp.com.au |
| 218 |
* |
| 219 |
* @access public |
| 220 |
* @param mixed $string |
| 221 |
* @param mixed $limit |
| 222 |
* @param string $break (default: " ") |
| 223 |
* @param string $pad (default: "...") |
| 224 |
* @return void |
| 225 |
*/ |
| 226 |
public function truncate($string, $limit, $break = ' ', $pad = '...') |
| 227 |
{ |
| 228 |
// return with no change if string is shorter than $limit |
| 229 |
if (strlen($string) <= $limit) { |
| 230 |
return $string; |
| 231 |
} |
| 232 |
|
| 233 |
$string = substr($string, 0, $limit); |
| 234 |
|
| 235 |
if (false !== ($breakpoint = strrpos($string, $break))) { |
| 236 |
$string = substr($string, 0, $breakpoint); |
| 237 |
} |
| 238 |
|
| 239 |
return $string . $pad; |
| 240 |
} |
| 241 |
|
| 242 |
/** |
| 243 |
* Restore HTML tags to truncated strings. |
| 244 |
* Original PHP code by Chirp Internet: www.chirp.com.au |
| 245 |
* |
| 246 |
* @access public |
| 247 |
* @param mixed $input |
| 248 |
* @return void |
| 249 |
*/ |
| 250 |
public function restore_tags($input) |
| 251 |
{ |
| 252 |
$opened = array(); |
| 253 |
// loop through opened and closed tags in order |
| 254 |
if (preg_match_all("/<(\/?[a-z]+)>?/i", $input, $matches)) { |
| 255 |
foreach ($matches[1] as $tag) { |
| 256 |
if (preg_match("/^[a-z]+$/i", $tag, $regs)) { |
| 257 |
// a tag has been opened |
| 258 |
if (strtolower($regs[0]) != 'br') { |
| 259 |
$opened[] = $regs[0]; |
| 260 |
} |
| 261 |
} elseif (preg_match("/^\/([a-z]+)$/i", $tag, $regs)) { |
| 262 |
// a tag has been closed |
| 263 |
unset($opened[array_pop(array_keys($opened, $regs[1]))]); |
| 264 |
} |
| 265 |
} |
| 266 |
} |
| 267 |
// close tags that are still open |
| 268 |
if ($opened) { |
| 269 |
$tagstoclose = array_reverse($opened); |
| 270 |
foreach ($tagstoclose as $tag) { |
| 271 |
$input .= "</$tag>"; |
| 272 |
} |
| 273 |
} |
| 274 |
return $input; |
| 275 |
} |
| 276 |
|
| 277 |
/** |
| 278 |
* UrlLinker - facilitates turning plain text URLs into HTML links. |
| 279 |
* |
| 280 |
* Author: Søren Løvborg |
| 281 |
* |
| 282 |
* To the extent possible under law, Søren Løvborg has waived all copyright |
| 283 |
* and related or neighboring rights to UrlLinker. |
| 284 |
* http://creativecommons.org/publicdomain/zero/1.0/ |
| 285 |
* |
| 286 |
* Transforms plain text into valid HTML, escaping special characters and |
| 287 |
* turning URLs into links. |
| 288 |
* |
| 289 |
* Can be used in any Vimeography theme file. EG: |
| 290 |
* $item->description = $helpers->link_urls($item->description); |
| 291 |
*/ |
| 292 |
public function link_urls($text) |
| 293 |
{ |
| 294 |
/* |
| 295 |
* Regular expression bits used by link_urls() to match URLs. |
| 296 |
*/ |
| 297 |
$rexScheme = 'https?://'; |
| 298 |
// $rexScheme = "$rexScheme|ftp://"; // Uncomment this line to allow FTP addresses. |
| 299 |
$rexDomain = '(?:[-a-zA-Z0-9]{1,63}\.)+[a-zA-Z][-a-zA-Z0-9]{1,62}'; |
| 300 |
$rexIp = '(?:[1-9][0-9]{0,2}\.|0\.){3}(?:[1-9][0-9]{0,2}|0)'; |
| 301 |
$rexPort = '(:[0-9]{1,5})?'; |
| 302 |
$rexPath = '(/[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]*?)?'; |
| 303 |
$rexQuery = '(\?[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?'; |
| 304 |
$rexFragment = '(#[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?'; |
| 305 |
$rexUsername = '[^]\\\\\x00-\x20\"(),:-<>[\x7f-\xff]{1,64}'; |
| 306 |
$rexPassword = $rexUsername; // allow the same characters as in the username |
| 307 |
$rexUrl = "($rexScheme)?(?:($rexUsername)(:$rexPassword)?@)?($rexDomain|$rexIp)($rexPort$rexPath$rexQuery$rexFragment)"; |
| 308 |
$rexTrailPunct = "[)'?.!,;:]"; // valid URL characters which are not part of the URL if they appear at the very end |
| 309 |
$rexNonUrl = "[^-_$+.!*'(),;/?:@=&a-zA-Z0-9]"; // characters that should never appear in a URL |
| 310 |
$rexUrlLinker = "{\\b$rexUrl(?=$rexTrailPunct*($rexNonUrl|$))}"; |
| 311 |
// $rexUrlLinker .= 'i'; // Uncomment this line to allow uppercase URL schemes (e.g. "HTTP://google.com"). |
| 312 |
|
| 313 |
/** |
| 314 |
* $validTlds is an associative array mapping valid TLDs to the value true. |
| 315 |
* Since the set of valid TLDs is not static, this array should be updated |
| 316 |
* from time to time. |
| 317 |
* |
| 318 |
* List source: http://data.iana.org/TLD/tlds-alpha-by-domain.txt |
| 319 |
* Last updated: 2012-09-06 |
| 320 |
*/ |
| 321 |
$validTlds = array_fill_keys( |
| 322 |
explode( |
| 323 |
" ", |
| 324 |
".ac .ad .ae .aero .af .ag .ai .al .am .an .ao .aq .ar .arpa .as .asia .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .biz .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cat .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .com .coop .cr .cu .cv .cw .cx .cy .cz .de .dj .dk .dm .do .dz .ec .edu .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gov .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .info .int .io .iq .ir .is .it .je .jm .jo .jobs .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mil .mk .ml .mm .mn .mo .mobi .mp .mq .mr .ms .mt .mu .museum .mv .mw .mx .my .mz .na .name .nc .ne .net .nf .ng .ni .nl .no .np .nr .nu .nz .om .org .pa .pe .pf .pg .ph .pk .pl .pm .pn .post .pr .pro .ps .pt .pw .py .qa .re .ro .rs .ru .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sx .sy .sz .tc .td .tel .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .travel .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .xn--0zwm56d .xn--11b5bs3a9aj6g .xn--3e0b707e .xn--45brj9c .xn--80akhbyknj4f .xn--80ao21a .xn--90a3ac .xn--9t4b11yi5a .xn--clchc0ea0b2g2a9gcd .xn--deba0ad .xn--fiqs8s .xn--fiqz9s .xn--fpcrj9c3d .xn--fzc2c9e2c .xn--g6w251d .xn--gecrj9c .xn--h2brj9c .xn--hgbk6aj7f53bba .xn--hlcj6aya9esc7a .xn--j6w193g .xn--jxalpdlp .xn--kgbechtv .xn--kprw13d .xn--kpry57d .xn--lgbbat1ad8j .xn--mgb9awbf .xn--mgbaam7a8h .xn--mgbayh7gpa .xn--mgbbh1a71e .xn--mgbc0a9azcg .xn--mgberp4a5d4ar .xn--o3cw4h .xn--ogbpf8fl .xn--p1ai .xn--pgbs0dh .xn--s9brj9c .xn--wgbh1c .xn--wgbl6a .xn--xkc2al3hye2a .xn--xkc2dl3a5ee0h .xn--yfro4i67o .xn--ygbi2ammx .xn--zckzah .xxx .ye .yt .za .zm .zw" |
| 325 |
), |
| 326 |
true |
| 327 |
); |
| 328 |
|
| 329 |
$html = ''; |
| 330 |
|
| 331 |
$position = 0; |
| 332 |
while ( |
| 333 |
preg_match($rexUrlLinker, $text, $match, PREG_OFFSET_CAPTURE, $position) |
| 334 |
) { |
| 335 |
list($url, $urlPosition) = $match[0]; |
| 336 |
|
| 337 |
// Add the text leading up to the URL. |
| 338 |
$html .= substr($text, $position, $urlPosition - $position); |
| 339 |
|
| 340 |
$scheme = $match[1][0]; |
| 341 |
$username = $match[2][0]; |
| 342 |
$password = $match[3][0]; |
| 343 |
$domain = $match[4][0]; |
| 344 |
$afterDomain = $match[5][0]; // everything following the domain |
| 345 |
$port = $match[6][0]; |
| 346 |
$path = $match[7][0]; |
| 347 |
|
| 348 |
// Check that the TLD is valid or that $domain is an IP address. |
| 349 |
$tld = strtolower(strrchr($domain, '.')); |
| 350 |
if (preg_match('{^\.[0-9]{1,3}$}', $tld) || isset($validTlds[$tld])) { |
| 351 |
// Do not permit implicit scheme if a password is specified, as |
| 352 |
// this causes too many errors (e.g. "my email:foo@example.org"). |
| 353 |
if (!$scheme && $password) { |
| 354 |
$html .= htmlspecialchars($username); |
| 355 |
|
| 356 |
// Continue text parsing at the ':' following the "username". |
| 357 |
$position = $urlPosition + strlen($username); |
| 358 |
continue; |
| 359 |
} |
| 360 |
|
| 361 |
if (!$scheme && $username && !$password && !$afterDomain) { |
| 362 |
// Looks like an email address. |
| 363 |
$completeUrl = "mailto:$url"; |
| 364 |
$linkText = $url; |
| 365 |
} else { |
| 366 |
// Prepend http:// if no scheme is specified |
| 367 |
$completeUrl = $scheme ? $url : "http://$url"; |
| 368 |
$linkText = "$domain$port$path"; |
| 369 |
} |
| 370 |
|
| 371 |
$linkHtml = |
| 372 |
'<a href="' . |
| 373 |
htmlspecialchars($completeUrl) . |
| 374 |
'" target="_blank">' . |
| 375 |
htmlspecialchars($linkText) . |
| 376 |
'</a>'; |
| 377 |
|
| 378 |
// Cheap e-mail obfuscation to trick the dumbest mail harvesters. |
| 379 |
$linkHtml = str_replace('@', '@', $linkHtml); |
| 380 |
|
| 381 |
// Add the hyperlink. |
| 382 |
$html .= $linkHtml; |
| 383 |
} else { |
| 384 |
// Not a valid URL. |
| 385 |
$html .= htmlspecialchars($url); |
| 386 |
} |
| 387 |
|
| 388 |
// Continue text parsing from after the URL. |
| 389 |
$position = $urlPosition + strlen($url); |
| 390 |
} |
| 391 |
|
| 392 |
// Add the remainder of the text. |
| 393 |
$html .= substr($text, $position); |
| 394 |
return $html; |
| 395 |
} |
| 396 |
|
| 397 |
/** |
| 398 |
* Remove videos from the video set if there is an imposing limit. |
| 399 |
* |
| 400 |
* @return array of Vimeo videos. |
| 401 |
*/ |
| 402 |
public function limit_video_set($video_set, $limit) |
| 403 |
{ |
| 404 |
if ($limit < count($video_set) && $limit != 0) { |
| 405 |
for ( |
| 406 |
$video_to_delete = count($video_set) - 1; |
| 407 |
$video_to_delete >= $limit; |
| 408 |
$video_to_delete-- |
| 409 |
) { |
| 410 |
unset($video_set[$video_to_delete]); |
| 411 |
} |
| 412 |
} |
| 413 |
|
| 414 |
return $video_set; |
| 415 |
} |
| 416 |
} |
| 417 |
|