'#f4f7f2','textColor'=>'#13201a','buttonColor'=>'#13935a','buttonText'=>'#ffffff','controlsBackground'=>'#ffffff','controlsText'=>'#13201a','accentColor'=>'#13935a','borderColor'=>'#e2e8de','radius'=>'16','buttonRadius'=>'100','padding'=>'24','fontSize'=>'16','titleSize'=>'22','width'=>'100','alignment'=>'left','showTitle'=>'0','showVolume'=>'1','showSpeed'=>'1','showFullscreen'=>'1','showDownload'=>'0','showTime'=>'1','poster'=>'','loop'=>'0'];} static function attributes(){return array_map(static fn($v)=>['type'=>'string','default'=>$v],self::defaults());} static function color($v,$transparent=false){if(is_string($v)&&preg_match('/^#[a-fA-F0-9]{6}(?:[a-fA-F0-9]{2})?$/D',$v))return true;if($transparent&&$v==='transparent')return true;if(is_string($v)&&preg_match('/^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*([0-9]*\.?[0-9]+))?\s*\)$/D',$v,$m))return (int)$m[1]<=255&&(int)$m[2]<=255&&(int)$m[3]<=255&&(!isset($m[4])||(float)$m[4]<=1);return false;} static function styles($a){$map=['background'=>'bg','textColor'=>'text','buttonColor'=>'button','buttonText'=>'button-text','controlsBackground'=>'controls-bg','controlsText'=>'controls-text','accentColor'=>'accent','borderColor'=>'border'];$s=[];foreach($map as $key=>$var){$v=$a[$key];if(!self::color($v,$key==='background'))$v=self::defaults()[$key];$s[]='--lfdrive-'.$var.':'.$v;} foreach(['radius'=>[0,80],'buttonRadius'=>[0,100],'padding'=>[0,80],'fontSize'=>[10,36],'titleSize'=>[12,60]] as $key=>$range){$v=max($range[0],min($range[1],(int)$a[$key]));$s[]='--lfdrive-'.strtolower(preg_replace('/([A-Z])/','-$1',$key)).':'.$v.'px';} $s[]='--lfdrive-width:'.max(20,min(100,(int)$a['width'])).'%';$s[]='text-align:'.(in_array($a['alignment'],['left','center','right'],true)?$a['alignment']:'left');return implode(';',$s);} static function register_assets(){ if(!wp_style_is('lfdrive-front','registered'))wp_register_style('lfdrive-front',plugins_url('assets/front.css',__FILE__),[],'1.2.4'); if(!wp_script_is('lfdrive-front','registered'))wp_register_script('lfdrive-front',plugins_url('assets/front.js',__FILE__),[],'1.2.4',true); } static function assets(){ self::register_assets();wp_enqueue_style('lfdrive-front');wp_enqueue_script('lfdrive-front'); if(!self::$configured){ self::$configured=true;$base=plugins_url('assets/pdfjs/',__FILE__); wp_add_inline_script('lfdrive-front','window.LFDriveFrontConfig='.wp_json_encode(['pdf'=>$base.'pdf.min.mjs','worker'=>$base.'pdf.worker.min.mjs','cmaps'=>$base.'cmaps/','fonts'=>$base.'standard_fonts/','wasm'=>$base.'wasm/']).';','before'); } } static function frontend_assets(){ if(is_admin())return; $post=get_post();if(!$post)return; $content=(string)$post->post_content;$needed=strpos($content,'wp:lfdrive/')!==false; foreach(['file','image','pdf','video','audio','sale','uploader'] as $type){if(has_shortcode($content,'lfdrive_'.$type)){$needed=true;break;}} if(!$needed){$elementor=get_post_meta($post->ID,'_elementor_data',true);$needed=is_string($elementor)&&preg_match('/"widgetType"\s*:\s*"lfdrive"/',$elementor)===1;} if($needed)self::assets(); } static function control($action,$label,$text){return '';} static function render($type,$attrs){$a=shortcode_atts(array_merge(['url'=>'','title'=>'','label'=>'','description'=>'','price'=>'','alt'=>'','height'=>'600'],self::defaults()),$attrs);if(!LFDrive_Plugin::safe_url($a['url']))return '';self::assets();$url=esc_url($a['url']);$open='
';$title=esc_html($a['title']);$heading=$title!==''?'

'.$title.'

':'';$height=max(200,min(1600,absint($a['height']?:600))); if($type==='image')return $open.''.esc_attr($a['alt']).'
'; if($type==='file'||$type==='sale'){return $open.$heading.($type==='sale'?'

'.esc_html($a['description']).'

'.esc_html($a['price']).' ₽':'').''.esc_html($a['label']?:($type==='sale'?'Купить файл':'Скачать файл')).'';} if($type==='video'||$type==='audio'){ $poster=$type==='video'&&LFDrive_Plugin::safe_url($a['poster'])?' poster="'.esc_url($a['poster']).'"':'';$media='<'.$type.' class="lfdrive-media" controls src="'.$url.'" preload="metadata"'.($type==='video'?' playsinline':'').($a['loop']==='1'?' loop':'').$poster.'>'; $controls=self::control('play','Воспроизвести','▶').''.($a['showTime']==='1'?'0:00 / 0:00':''); if($a['showVolume']==='1')$controls.=self::control('mute','Выключить звук','♫').''; if($a['showSpeed']==='1')$controls.=self::control('speed','Изменить скорость воспроизведения','1×');if($type==='video'&&$a['showFullscreen']==='1')$controls.=self::control('fullscreen','На весь экран','⛶');if($a['showDownload']==='1')$controls.='↓'; return $open.'
'.($a['showTitle']==='1'?$heading:'').$media.'
'.$controls.'

'; } if($type==='pdf'){$signature=hash_hmac('sha256',$a['url'],wp_salt('nonce'));$proxy=add_query_arg(['action'=>'lfdrive_pdf','url'=>$a['url'],'signature'=>$signature],admin_url('admin-ajax.php'));return $open.'
'.($a['showTitle']==='1'?$heading:'').'
'.self::control('previous','Предыдущая страница','←').'/ …'.self::control('next','Следующая страница','→').self::control('zoom-out','Уменьшить масштаб','−').'100%'.self::control('zoom-in','Увеличить масштаб','+').self::control('fit','По ширине','↔').($a['showDownload']==='1'?'↓':'').'

Загружаем документ…

Открыть PDF отдельно ↗
';} if($type==='uploader')return $open.'Открыть форму отдельно ↗'; return '';} static function proxy_url($url){if(!LFDrive_Plugin::safe_url($url)||wp_parse_url($url,PHP_URL_QUERY)!==null||wp_parse_url($url,PHP_URL_FRAGMENT)!==null||!preg_match('~^/f/[a-zA-Z0-9]{4,32}(?:\.pdf)?$~D',wp_parse_url($url,PHP_URL_PATH)?:''))return new WP_Error('lfdrive_pdf','Нужна публичная ссылка PDF из LF Drive');return add_query_arg(['action'=>'lfdrive_pdf','url'=>$url,'signature'=>hash_hmac('sha256',$url,wp_salt('nonce'))],admin_url('admin-ajax.php'));} static function pdf_proxy(){ // Public, read-only PDF endpoint: authorization uses the URL HMAC below, not an expiring login nonce. // phpcs:ignore WordPress.Security.NonceVerification.Recommended $url=isset($_GET['url'])&&is_string($_GET['url'])?esc_url_raw(wp_unslash($_GET['url'])):''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $sig=isset($_GET['signature'])&&is_string($_GET['signature'])?sanitize_text_field(wp_unslash($_GET['signature'])):''; $parts=wp_parse_url($url);if(!LFDrive_Plugin::safe_url($url)||isset($parts['query'])||isset($parts['fragment'])||!preg_match('~^/f/[a-zA-Z0-9]{4,32}(?:\.pdf)?$~D',$parts['path']??'')||!hash_equals(hash_hmac('sha256',$url,wp_salt('nonce')),$sig)){status_header(403);exit('Документ недоступен');} $ip=hash('sha256',sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR']??'')));$key='lfdrive_pdf_rate_'.substr($ip,0,30);$count=(int)get_transient($key);if($count>=20){status_header(429);exit('Повторите позже');}set_transient($key,$count+1,60); require_once ABSPATH.'wp-admin/includes/file.php';$tmp=wp_tempnam('lfdrive-pdf');if(!$tmp){status_header(503);exit('Повторите позже');} $max=32*1024*1024;$r=wp_safe_remote_get($url,['timeout'=>45,'redirection'=>5,'sslverify'=>true,'stream'=>true,'filename'=>$tmp,'limit_response_size'=>$max+1,'headers'=>['Accept'=>'application/pdf']]); require_once ABSPATH.'wp-admin/includes/class-wp-filesystem-base.php'; require_once ABSPATH.'wp-admin/includes/class-wp-filesystem-direct.php'; $filesystem=new WP_Filesystem_Direct(null); if(is_wp_error($r)||wp_remote_retrieve_response_code($r)!==200||$filesystem->size($tmp)>$max){wp_delete_file($tmp);status_header(502);exit('Open the document using its direct link');} $contents=$filesystem->get_contents($tmp); wp_delete_file($tmp); if(!is_string($contents)||strpos(substr($contents,0,1024),'%PDF-')===false){status_header(415);exit('PDF unavailable');} while(ob_get_level())ob_end_clean(); header('Content-Type: application/pdf'); header('X-Content-Type-Options: nosniff'); header('Cache-Control: private, no-store'); header('Content-Length: '.strlen($contents)); // Binary PDF bytes were validated above. HTML escaping would corrupt the document. // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $contents; exit; } static function allowed_html(){ $common=['class'=>true,'style'=>true,'title'=>true,'role'=>true,'aria-label'=>true,'aria-live'=>true]; return [ 'div'=>$common+['data-lfdrive-player'=>true,'data-lfdrive-pdf'=>true,'data-pdf-proxy'=>true], 'h3'=>$common,'p'=>$common,'strong'=>$common,'span'=>$common,'label'=>$common, 'a'=>$common+['href'=>true,'target'=>true,'rel'=>true], 'img'=>$common+['src'=>true,'alt'=>true,'loading'=>true,'decoding'=>true], 'video'=>$common+['controls'=>true,'src'=>true,'preload'=>true,'playsinline'=>true,'loop'=>true,'poster'=>true], 'audio'=>$common+['controls'=>true,'src'=>true,'preload'=>true,'loop'=>true], 'button'=>$common+['type'=>true,'data-action'=>true], 'input'=>$common+['type'=>true,'min'=>true,'max'=>true,'step'=>true,'value'=>true], 'canvas'=>$common,'noscript'=>$common, 'iframe'=>$common+['src'=>true,'loading'=>true,'referrerpolicy'=>true] ]; } }