src/AppBundle/Twig/WebExtension.php line 586

Open in your IDE?
  1. <?php
  2. namespace AppBundle\Twig;
  3. use ApiBundle\Api\Util\AssetHelper;
  4. use AppBundle\Common\ArrayToolkit;
  5. use AppBundle\Common\ConvertIpToolkit;
  6. use AppBundle\Common\DeviceToolkit;
  7. use AppBundle\Common\ExtensionManager;
  8. use AppBundle\Common\FileToolkit;
  9. use AppBundle\Common\LoginToolkit;
  10. use AppBundle\Common\MathToolkit;
  11. use AppBundle\Common\NumberToolkit;
  12. use AppBundle\Common\PluginVersionToolkit;
  13. use AppBundle\Common\SimpleValidator;
  14. use AppBundle\Component\DeviceDetector\DeviceDetectorAdapter;
  15. use AppBundle\Component\ShareSdk\WeixinShare;
  16. use AppBundle\Util\CategoryBuilder;
  17. use AppBundle\Util\CdnUrl;
  18. use AppBundle\Util\UploadToken;
  19. use Biz\Account\Service\AccountProxyService;
  20. use Biz\CloudPlatform\CloudAPIFactory;
  21. use Biz\CloudPlatform\Service\ResourceFacadeService;
  22. use Biz\ReviewCenter\Service\ReviewCenterService;
  23. use Biz\Taxonomy\Service\TagService;
  24. use Biz\User\Service\TokenService;
  25. use Codeages\Biz\Framework\Context\Biz;
  26. use Codeages\Biz\Framework\Service\Exception\ServiceException;
  27. use CorporateTrainingBundle\Biz\User\Service\UserService;
  28. use Symfony\Component\DependencyInjection\ContainerInterface;
  29. use Topxia\Service\Common\ServiceKernel;
  30. use Twig\Extension\AbstractExtension;
  31. class WebExtension extends AbstractExtension
  32. {
  33.     /**
  34.      * @var ContainerInterface
  35.      */
  36.     protected $container;
  37.     /**
  38.      * @var Biz
  39.      */
  40.     protected $biz;
  41.     protected $pageScripts;
  42.     protected $locale;
  43.     protected $defaultCloudSdkHost;
  44.     public function __construct($containerBiz $biz)
  45.     {
  46.         $this->container $container;
  47.         $this->biz $biz;
  48.     }
  49.     public function getFilters()
  50.     {
  51.         return [
  52.             new \Twig\TwigFilter('smart_time', [$this'smarttimeFilter']),
  53.             new \Twig\TwigFilter('date_format', [$this'dateformatFilter']),
  54.             new \Twig\TwigFilter('time_range', [$this'timeRangeFilter']),
  55.             new \Twig\TwigFilter('time_diff', [$this'timeDiffFilter']),
  56.             new \Twig\TwigFilter('remain_time', [$this'remainTimeFilter']),
  57.             new \Twig\TwigFilter('time_formatter', [$this'timeFormatterFilter']),
  58.             new \Twig\TwigFilter('location_text', [$this'locationTextFilter']),
  59.             new \Twig\TwigFilter('tags_html', [$this'tagsHtmlFilter'], ['is_safe' => ['html']]),
  60.             new \Twig\TwigFilter('file_size', [$this'fileSizeFilter']),
  61.             new \Twig\TwigFilter('plain_text', [$this'plainTextFilter'], ['is_safe' => ['html']]),
  62.             new \Twig\TwigFilter('sub_text', [$this'subTextFilter'], ['is_safe' => ['html']]),
  63.             new \Twig\TwigFilter('mb_substr', [$this'mb_substr'], ['is_safe' => ['html']]),
  64.             new \Twig\TwigFilter('duration', [$this'durationFilter']),
  65.             new \Twig\TwigFilter('duration_text', [$this'durationTextFilter']),
  66.             new \Twig\TwigFilter('tags_join', [$this'tagsJoinFilter']),
  67.             new \Twig\TwigFilter('navigation_url', [$this'navigationUrlFilter']),
  68.             new \Twig\TwigFilter('chr', [$this'chrFilter']),
  69.             new \Twig\TwigFilter('bbCode2Html', [$this'bbCode2HtmlFilter']),
  70.             new \Twig\TwigFilter('score_text', [$this'scoreTextFilter']),
  71.             new \Twig\TwigFilter('simple_template', [$this'simpleTemplateFilter']),
  72.             new \Twig\TwigFilter('fill_question_stem_text', [$this'fillQuestionStemTextFilter']),
  73.             new \Twig\TwigFilter('fill_question_stem_html', [$this'fillQuestionStemHtmlFilter']),
  74.             new \Twig\TwigFilter('get_course_id', [$this'getCourseidFilter']),
  75.             new \Twig\TwigFilter('purify_html', [$this'getPurifyHtml']),
  76.             new \Twig\TwigFilter('purify_and_trim_html', [$this'getPurifyAndTrimHtml']),
  77.             new \Twig\TwigFilter('file_type', [$this'getFileType']),
  78.             new \Twig\TwigFilter('at', [$this'atFilter']),
  79.             new \Twig\TwigFilter('copyright_less', [$this'removeCopyright']),
  80.             new \Twig\TwigFilter('array_merge', [$this'arrayMerge']),
  81.             new \Twig\TwigFilter('space2nbsp', [$this'spaceToNbsp']),
  82.             new \Twig\TwigFilter('number_to_human', [$this'numberFilter']),
  83.             new \Twig\TwigFilter('array_column', [$this'arrayColumn']),
  84.             new \Twig\TwigFilter('rename_locale', [$this'renameLocale']),
  85.             new \Twig\TwigFilter('cdn', [$this'cdn']),
  86.             new \Twig\TwigFilter('wrap', [$this'wrap']),
  87.             new \Twig\TwigFilter('convert_absolute_url', [$this'convertAbsoluteUrl']),
  88.             new \Twig\TwigFilter('days_of_week', [$this'daysOfWeek']),
  89.             new \Twig\TwigFilter('filter_keys', [$this'filterArrayKeys']),
  90.             new \Twig\TwigFilter('exam_score', [$this'examScore']),
  91.             new \Twig\TwigFilter('learn_time_format', [$this'formatLearnTime']),
  92.             new \Twig\TwigFilter('group_by', [$this'groupBy']),
  93.         ];
  94.     }
  95.     public function getFunctions()
  96.     {
  97.         return [
  98.             new \Twig\TwigFunction('theme_global_script', [$this'getThemeGlobalScript']),
  99.             new \Twig\TwigFunction('file_uri_parse', [$this'parseFileUri']),
  100.             // file_path 即将废弃,不要再使用
  101.             new \Twig\TwigFunction('file_path', [$this'getFilePath']),
  102.             // default_path 即将废弃,不要再使用
  103.             new \Twig\TwigFunction('default_path', [$this'getDefaultPath']),
  104.             // file_url 即将废弃,不要再使用
  105.             new \Twig\TwigFunction('file_url', [$this'getFileUrl']),
  106.             // system_default_path,即将废弃,不要再使用
  107.             new \Twig\TwigFunction('system_default_path', [$this'getSystemDefaultPath']),
  108.             new \Twig\TwigFunction('fileurl', [$this'getFurl']),
  109.             new \Twig\TwigFunction('filepath', [$this'getFpath']),
  110.             new \Twig\TwigFunction('lazy_img', [$this'makeLazyImg'], ['is_safe' => ['html']]),
  111.             new \Twig\TwigFunction('avatar_path', [$this'avatarPath']),
  112.             new \Twig\TwigFunction('object_load', [$this'loadObject']),
  113.             new \Twig\TwigFunction('setting', [$this'getSetting']),
  114.             new \Twig\TwigFunction('set_price', [$this'getSetPrice']),
  115.             new \Twig\TwigFunction('percent', [$this'calculatePercent']),
  116.             new \Twig\TwigFunction('rate_format', [$this'rateFormat']),
  117.             new \Twig\TwigFunction('category_choices', [$this'getCategoryChoices']),
  118.             new \Twig\TwigFunction('category_choices_with_category_empty', [$this'getCategoryChoicesWithCategoryEmpty']),
  119.             new \Twig\TwigFunction('upload_max_filesize', [$this'getUploadMaxFilesize']),
  120.             new \Twig\TwigFunction('js_paths', [$this'getJsPaths']),
  121.             new \Twig\TwigFunction('is_plugin_installed', [$this'isPluginInstalled']),
  122.             new \Twig\TwigFunction('plugin_version', [$this'getPluginVersion']),
  123.             new \Twig\TwigFunction('version_compare', [$this'versionCompare']),
  124.             new \Twig\TwigFunction('is_exist_in_subarray_by_id', [$this'isExistInSubArrayById']),
  125.             new \Twig\TwigFunction('context_value', [$this'getContextValue']),
  126.             new \Twig\TwigFunction('is_feature_enabled', [$this'isFeatureEnabled']),
  127.             new \Twig\TwigFunction('parameter', [$this'getParameter']),
  128.             new \Twig\TwigFunction('upload_token', [$this'makeUpoadToken']),
  129.             new \Twig\TwigFunction('countdown_time', [$this'getCountdownTime']),
  130.             //todo covertIP 要删除
  131.             new \Twig\TwigFunction('convertIP', [$this'getConvertIP']),
  132.             new \Twig\TwigFunction('convert_ip', [$this'getConvertIP']),
  133.             new \Twig\TwigFunction('new_convert_ip', [$this'getNewConverIP']),
  134.             new \Twig\TwigFunction('isHide', [$this'isHideThread']),
  135.             new \Twig\TwigFunction('user_coin_amount', [$this'userCoinAmount']),
  136.             new \Twig\TwigFunction('user_balance', [$this'getBalance']),
  137.             new \Twig\TwigFunction('blur_user_name', [$this'blurUserName']),
  138.             new \Twig\TwigFunction('blur_phone_number', [$this'blur_phone_number']),
  139.             new \Twig\TwigFunction('blur_idcard_number', [$this'blur_idcard_number']),
  140.             new \Twig\TwigFunction('blur_number', [$this'blur_number']),
  141.             new \Twig\TwigFunction('sub_str', [$this'subStr']),
  142.             new \Twig\TwigFunction('convert_encoding_sub_str', [$this'convertEncodingSubStr']),
  143.             new \Twig\TwigFunction('load_script', [$this'loadScript']),
  144.             new \Twig\TwigFunction('export_scripts', [$this'exportScripts']),
  145.             new \Twig\TwigFunction('order_payment', [$this'getOrderPayment']),
  146.             new \Twig\TwigFunction('classroom_permit', [$this'isPermitRole']),
  147.             new \Twig\TwigFunction('crontab_next_executed_time', [$this'getNextExecutedTime']),
  148.             new \Twig\TwigFunction('finger_print', [$this'getFingerprint']),
  149.             new \Twig\TwigFunction('get_parameters_from_url', [$this'getParametersFromUrl']),
  150.             new \Twig\TwigFunction('is_trial', [$this'isTrial']),
  151.             new \Twig\TwigFunction('timestamp', [$this'timestamp']),
  152.             new \Twig\TwigFunction('get_user_vip_level', [$this'getUserVipLevel']),
  153.             new \Twig\TwigFunction('is_without_network', [$this'isWithoutNetwork']),
  154.             new \Twig\TwigFunction('get_admin_roles', [$this'getAdminRoles']),
  155.             new \Twig\TwigFunction('render_notification', [$this'renderNotification']),
  156.             new \Twig\TwigFunction('route_exsit', [$this'routeExists']),
  157.             new \Twig\TwigFunction('is_micro_messenger', [$this'isMicroMessenger']),
  158.             new \Twig\TwigFunction('wx_js_sdk_config', [$this'weixinConfig']),
  159.             new \Twig\TwigFunction('plugin_update_notify', [$this'pluginUpdateNotify']),
  160.             new \Twig\TwigFunction('tag_equal', [$this'tagEqual']),
  161.             new \Twig\TwigFunction('get_tag', [$this'getTag']),
  162.             new \Twig\TwigFunction('array_index', [$this'arrayIndex']),
  163.             new \Twig\TwigFunction('cdn', [$this'getCdn']),
  164.             new \Twig\TwigFunction('is_show_mobile_page', [$this'isShowMobilePage']),
  165.             new \Twig\TwigFunction('is_mobile_client', [$this'isMobileClient']),
  166.             new \Twig\TwigFunction('is_allow_browse', [$this'isAllowBrowse']),
  167.             new \Twig\TwigFunction('is_ES_copyright', [$this'isESCopyright']),
  168.             new \Twig\TwigFunction('get_classroom_name', [$this'getClassroomName']),
  169.             new \Twig\TwigFunction('pop_reward_point_notify', [$this'popRewardPointNotify']),
  170.             new \Twig\TwigFunction('array_filter', [$this'arrayFilter']),
  171.             new \Twig\TwigFunction('base_path', [$this'basePath']),
  172.             new \Twig\TwigFunction('get_login_email_address', [$this'getLoginEmailAddress']),
  173.             new \Twig\TwigFunction('cloud_sdk_url', [$this'getCloudSdkUrl']),
  174.             new \Twig\TwigFunction('math_format', [$this'mathFormat']),
  175.             new \Twig\TwigFunction('parse_user_agent', [$this'parseUserAgent']),
  176.             new \Twig\TwigFunction('wechat_login_bind_enabled', [$this'isWechatLoginBind']),
  177.             new \Twig\TwigFunction('can_send_message', [$this'canSendMessage']),
  178.             new \Twig\TwigFunction('is_hidden_video_header', [$this'isHiddenVideoHeader']),
  179.             new \Twig\TwigFunction('arrays_key_convert', [$this'arraysKeyConvert']),
  180.             new \Twig\TwigFunction('make_local_media_file_token', [$this'makeLocalMediaFileToken']),
  181.             new \Twig\TwigFunction('online_advisory_auth_info', [$this'onlineAdvisoryAuthInfo']),
  182.             new \Twig\TwigFunction('question_html_filter', [$this'questionHtmlFilter']),
  183.             new \Twig\TwigFunction('uniqid', [$this'uniqid']),
  184.             new \Twig\TwigFunction('can_operate_question', [$this'canOperateQuestion']),
  185.             new \Twig\TwigFunction('sync_mode_dict', [$this'getSyncModeDict']),
  186.             new \Twig\TwigFunction('show_feedback_bar', [$this'showFeedbackBar']),
  187.             new \Twig\TwigFunction('is_saas', [$this'isSaaS']),
  188.             new \Twig\TwigFunction('member_deadline', [$this'handleDeadline']),
  189.             new \Twig\TwigFunction('get_course_market_url', [$this'getCourseMarketUrl']),
  190.             new \Twig\TwigFunction('org_msg', [$this'getOrgMsg']),
  191.             new \Twig\TwigFunction('get_category_name', [$this'getCategoryName']),
  192.             new \Twig\TwigFunction('get_category_ids_by_categories', [$this'getCategoryIdsByCategories']),
  193.             new \Twig\TwigFunction('get_review_pending_total_num', [$this'getReviewPendingTotalNum']),
  194.             new \Twig\TwigFunction('get_remember_me_deadline_range_text', [$this'getRememberMeDeadlineRangeText']),
  195.         ];
  196.     }
  197.     public function getCourseMarketUrl()
  198.     {
  199.         return ServiceKernel::instance()->getParameter('security.course_market.url');
  200.     }
  201.     public function parseUserAgent($userAgent)
  202.     {
  203.         $deviceDetector = new DeviceDetectorAdapter($userAgent);
  204.         return [
  205.             'device' => $deviceDetector->getDevice(),
  206.             'client' => $deviceDetector->getClient(),
  207.             'os' => $deviceDetector->getOs(),
  208.         ];
  209.     }
  210.     public function handleDeadline($deadline$issueDate 0)
  211.     {
  212.         if (== $deadline) {
  213.             return 0;
  214.         }
  215.         if (== $issueDate) {
  216.             $time time();
  217.         } else {
  218.             $time $issueDate;
  219.         }
  220.         if (($deadline $time) < 0) {
  221.             return -1;
  222.         }
  223.         return floor(($deadline $time) / 3600 24);
  224.     }
  225.     public function arrayFilter($data$filterName)
  226.     {
  227.         if (empty($data) || !is_array($data)) {
  228.             return [];
  229.         }
  230.         return array_filter($data, function ($value) use ($filterName) {
  231.             foreach ($filterName as $name) {
  232.                 if ('' === $value[$name]) {
  233.                     return false;
  234.                 }
  235.             }
  236.             return true;
  237.         });
  238.     }
  239.     public function getReviewPendingTotalNum()
  240.     {
  241.         $user $this->getUserService()->getCurrentUser();
  242.         $reviewPendingCount $this->getReviewCenterService()->getPendingTabbar($user['id']);
  243.         return array_sum(array_column($reviewPendingCount'pendingCount'));
  244.     }
  245.     public function isShowMobilePage()
  246.     {
  247.         $wapSetting $this->getSetting('wap', []);
  248.         if (empty($wapSetting['enabled'])) {
  249.             return false;
  250.         }
  251.         $pcVersion $this->container->get('request_stack')->getMainRequest()->cookies->get('PCVersion'0);
  252.         if ($pcVersion) {
  253.             return false;
  254.         }
  255.         return DeviceToolkit::isMobileClient();
  256.     }
  257.     public function isMobileClient()
  258.     {
  259.         return DeviceToolkit::isMobileClient();
  260.     }
  261.     public function isAllowBrowse()
  262.     {
  263.         $userAgent $this->container->get('request_stack')->getMainRequest()->headers->get('User-Agent');
  264.         $allowedBrowse = ['MicroMessenger''wxwork''DingTalk''Feishu'];
  265.         $allow false;
  266.         foreach ($allowedBrowse as $browse) {
  267.             if (false !== strpos($userAgent$browse)) {
  268.                 $allow true;
  269.                 break;
  270.             }
  271.         }
  272.         return $allow;
  273.     }
  274.     public function isESCopyright()
  275.     {
  276.         $copyright $this->getSetting('copyright');
  277.         $request $this->container->get('request_stack')->getMainRequest();
  278.         $host $request->getHttpHost();
  279.         if ($copyright) {
  280.             $result = !(
  281.                 isset($copyright['owned'])
  282.                 && isset($copyright['thirdCopyright'])
  283.                 && != $copyright['thirdCopyright']
  284.                 && isset($copyright['licenseDomains'])
  285.                 && in_array($hostexplode(';'$copyright['licenseDomains']))
  286.                 || (isset($copyright['thirdCopyright']) && == $copyright['thirdCopyright'])
  287.             );
  288.             return $result;
  289.         }
  290.         return true;
  291.     }
  292.     public function getClassroomName()
  293.     {
  294.         return $this->getSetting('classroom.name'$this->container->get('translator')->trans('site.default.classroom'));
  295.     }
  296.     public function tagEqual($tags$targetTagId$targetTagGroupId)
  297.     {
  298.         foreach ($tags as $groupId => $tagId) {
  299.             if ($groupId == $targetTagGroupId && $tagId == $targetTagId) {
  300.                 return true;
  301.             }
  302.         }
  303.         return false;
  304.     }
  305.     public function getTag($tagId)
  306.     {
  307.         if (empty($tagId)) {
  308.             return null;
  309.         }
  310.         return $this->getTagService()->getTag($tagId);
  311.     }
  312.     public function arrayIndex($array$key)
  313.     {
  314.         if (empty($array) || !is_array($array)) {
  315.             return [];
  316.         }
  317.         return ArrayToolkit::index($array$key);
  318.     }
  319.     public function timeFormatterFilter($time)
  320.     {
  321.         if ($time <= 60) {
  322.             return $this->trans('site.twig.extension.time_interval.minute', ['%diff%' => 0]);
  323.         }
  324.         if ($time <= 3600) {
  325.             return $this->trans('site.twig.extension.time_interval.minute', ['%diff%' => round($time 60)]);
  326.         }
  327.         return $this->trans('site.twig.extension.time_interval.hour_minute', ['%diff_hour%' => floor($time 3600), '%diff_minute%' => round($time 3600 60)]);
  328.     }
  329.     public function pluginUpdateNotify()
  330.     {
  331.         $count $this->getAppService()->findAppCount();
  332.         $apps $this->getAppService()->findApps(0$count);
  333.         $apps array_filter($apps, function ($app) {
  334.             return 'EduSoho官方' == $app['developerName'];
  335.         });
  336.         $notifies array_reduce(
  337.             $apps,
  338.             function ($notifies$app) {
  339.                 if (!PluginVersionToolkit::dependencyVersion($app['code'], $app['version'])) {
  340.                     $notifies[$app['type']][] = $app['name'];
  341.                 } elseif ('TRAININGMAIN' !== $app['code'] && $app['protocol'] < 3) {
  342.                     $notifies[$app['type']][] = $app['name'];
  343.                 }
  344.                 return $notifies;
  345.             },
  346.             []
  347.         );
  348.         return $notifies;
  349.     }
  350.     public function getAdminRoles()
  351.     {
  352.         return $this->createService('Role:RoleService')->searchRoles([], 'created'01000);
  353.     }
  354.     public function getCdn($type 'default')
  355.     {
  356.         $cdn = new CdnUrl();
  357.         $cdnUrl $cdn->get($type);
  358.         return $cdnUrl;
  359.     }
  360.     public function cdn($content)
  361.     {
  362.         $cdn = new CdnUrl();
  363.         $cdnUrl $cdn->get('content');
  364.         if ($cdnUrl) {
  365.             $publicUrlPath $this->container->getParameter('topxia.upload.public_url_path');
  366.             $themeUrlPath $this->container->getParameter('topxia.web_themes_url_path');
  367.             $assetUrlPath $this->container->getParameter('topxia.web_assets_url_path');
  368.             $bundleUrlPath $this->container->getParameter('topxia.web_bundles_url_path');
  369.             $staticDistUrlPath $this->container->getParameter('front_end.web_static_dist_url_path');
  370.             preg_match_all('/<img[^>]*src=[\'"]?([^>\'"\s]*)[\'"]?[^>]*>/i'$content$imgs);
  371.             if ($imgs) {
  372.                 foreach ($imgs[1] as $img) {
  373.                     if (=== strpos($img$publicUrlPath)
  374.                         || === strpos($img$themeUrlPath)
  375.                         || === strpos($img$assetUrlPath)
  376.                         || === strpos($img$bundleUrlPath)
  377.                         || === strpos($img$staticDistUrlPath)) {
  378.                         $content str_replace('"'.$img'"'.$cdnUrl.$img$content);
  379.                     }
  380.                 }
  381.             }
  382.         }
  383.         return $content;
  384.     }
  385.     public function weixinConfig()
  386.     {
  387.         $weixinmob_enabled $this->getSetting('login_bind.weixinmob_enabled');
  388.         if (!(bool) $weixinmob_enabled) {
  389.             return null;
  390.         }
  391.         $jsApiTicket $this->createService('User:TokenService')->getTokenByType('jsapi.ticket');
  392.         $key $this->getSetting('login_bind.weixinmob_key');
  393.         $secret $this->getSetting('login_bind.weixinmob_secret');
  394.         if (empty($jsApiTicket)) {
  395.             $config = ['key' => $key'secret' => $secret];
  396.             $weixinshare = new WeixinShare($config);
  397.             $token $weixinshare->getJsApiTicket();
  398.             if (empty($token)) {
  399.                 return [];
  400.             }
  401.             $jsApiTicket $this->createService('User:TokenService')->makeToken(
  402.                 'jsapi.ticket',
  403.                 ['data' => $token'duration' => $token['expires_in']]
  404.             );
  405.         }
  406.         $config = [
  407.             'appId' => $key,
  408.             'timestamp' => time(),
  409.             'nonceStr' => uniqid($prefix 'edusoho'),
  410.             'jsApiList' => ['onMenuShareTimeline''onMenuShareAppMessage''onMenuShareQZone''onMenuShareQQ'],
  411.         ];
  412.         $jsapi_ticket $jsApiTicket['data']['ticket'];
  413.         $url $this->container->get('request_stack')->getMainRequest()->getUri();
  414.         $string 'jsapi_ticket='.$jsapi_ticket.'&noncestr='.$config['nonceStr'].'&timestamp='.$config['timestamp'].'&url='.$url;
  415.         $config['string'] = $string;
  416.         $config['signature'] = sha1($string);
  417.         return json_encode($config);
  418.     }
  419.     public function renderNotification($notification)
  420.     {
  421.         if ($notification) {
  422.             $manager ExtensionManager::instance();
  423.             $notification['message'] = $manager->renderNotification($notification);
  424.         }
  425.         return $notification;
  426.     }
  427.     public function routeExists($name)
  428.     {
  429.         $router $this->container->get('router');
  430.         return (null === $router->getRouteCollection()->get($name)) ? false true;
  431.     }
  432.     public function isWithoutNetwork()
  433.     {
  434.         $network $this->getSetting('developer.without_network'$default false);
  435.         return (bool) $network;
  436.     }
  437.     public function getUserVipLevel($userId)
  438.     {
  439.         return $this->createService('VipPlugin:Vip:VipService')->getMemberByUserId($userId);
  440.     }
  441.     public function getParametersFromUrl($url)
  442.     {
  443.         $BaseUrl parse_url($url);
  444.         if (isset($BaseUrl['query'])) {
  445.             if (strstr($BaseUrl['query'], '&')) {
  446.                 $parameter explode('&'$BaseUrl['query']);
  447.                 $parameters = [];
  448.                 foreach ($parameter as $key => $value) {
  449.                     $parameters[$key] = explode('='$value);
  450.                 }
  451.             } else {
  452.                 $parameter explode('='$BaseUrl['query']);
  453.                 $parameters = [];
  454.                 $parameters[0] = $parameter;
  455.             }
  456.         } else {
  457.             return null;
  458.         }
  459.         return $parameters;
  460.     }
  461.     public function spaceToNbsp($content)
  462.     {
  463.         $content str_replace(' ''&nbsp;'$content);
  464.         return $content;
  465.     }
  466.     public function isMicroMessenger()
  467.     {
  468.         return false !== strpos($this->container->get('request_stack')->getMainRequest()->headers->get('User-Agent'), 'MicroMessenger');
  469.     }
  470.     public function renameLocale($locale)
  471.     {
  472.         $locale strtolower($locale);
  473.         $locale str_replace('_''-'$locale);
  474.         return 'zh-cn' == $locale '' '-'.$locale;
  475.     }
  476.     public function getFingerprint()
  477.     {
  478.         $user $this->getUserService()->getCurrentUser();
  479.         if (!$user->isLogin()) {
  480.             return '';
  481.         }
  482.         $user $this->getUserService()->getUser($user['id']);
  483.         // @todo 如果配置用户的关键信息,这个方法存在信息泄漏风险,更换新播放器后解决这个问题。
  484.         $pattern $this->getSetting('magic.video_fingerprint');
  485.         if ($pattern) {
  486.             $fingerprint $this->parsePattern($pattern$user);
  487.         } else {
  488.             $request $this->container->get('request_stack')->getMainRequest();
  489.             $host $request->getHttpHost();
  490.             $fingerprint "{$host} {$user['nickname']}";
  491.         }
  492.         return $fingerprint;
  493.     }
  494.     public function popRewardPointNotify()
  495.     {
  496.         $session $this->container->get('session');
  497.         if (empty($session)) {
  498.             return '';
  499.         }
  500.         $message $session->get('Reward-Point-Notify');
  501.         $session->remove('Reward-Point-Notify');
  502.         return $message;
  503.     }
  504.     protected function parsePattern($pattern$user)
  505.     {
  506.         $profile $this->getUserService()->getUserProfile($user['id']);
  507.         $values array_merge($user$profile);
  508.         $values array_filter(
  509.             $values,
  510.             function ($value) {
  511.                 return !is_array($value);
  512.             }
  513.         );
  514.         return $this->simpleTemplateFilter($pattern$values);
  515.     }
  516.     public function subStr($text$start$length)
  517.     {
  518.         $text trim($text);
  519.         $length = (int) $length;
  520.         if (($length 0) && (mb_strlen($text) > $length)) {
  521.             $text mb_substr($text$start$length'UTF-8');
  522.         }
  523.         return $text;
  524.     }
  525.     public function convertEncodingSubStr($text$start$length)
  526.     {
  527.         $strlen = (strlen($text) + mb_strlen($text'UTF-8')) / 2;
  528.         if ($strlen <= $length) {
  529.             return $text;
  530.         }
  531.         $text mb_strcut(mb_convert_encoding($text'GBK''UTF-8'), 0$length'GBK');
  532.         return mb_convert_encoding($text'UTF-8''GBK').'...';
  533.     }
  534.     public function userCoinAmount($type$userId$startDateTime null$endDateTime null)
  535.     {
  536.         if (!empty($endDateTime)) {
  537.             $condition['created_time_LTE'] = strtotime($endDateTime);
  538.         }
  539.         if (!empty($startDateTime)) {
  540.             $condition['created_time_GTE'] = strtotime($startDateTime);
  541.         }
  542.         $condition = [
  543.             'user_id' => $userId,
  544.             'type' => $type,
  545.             'amount_type' => 'coin',
  546.         ];
  547.         $amount $this->getAccountProxyService()->sumColumnByConditions('amount'$condition);
  548.         return $amount;
  549.     }
  550.     public function getBalance($userId)
  551.     {
  552.         $balance $this->getAccountProxyService()->getUserBalanceByUserId($userId);
  553.         return $balance;
  554.     }
  555.     /**
  556.      * @return AccountProxyService
  557.      */
  558.     protected function getAccountProxyService()
  559.     {
  560.         return $this->createService('Account:AccountProxyService');
  561.     }
  562.     /**
  563.      * @return UserService
  564.      */
  565.     private function getUserService()
  566.     {
  567.         return $this->createService('User:UserService');
  568.     }
  569.     public function isExistInSubArrayById($currentTarget$targetArray)
  570.     {
  571.         foreach ($targetArray as $target) {
  572.             if ($currentTarget['id'] == $target['id']) {
  573.                 return true;
  574.             }
  575.         }
  576.         return false;
  577.     }
  578.     public function getThemeGlobalScript()
  579.     {
  580.         $theme $this->getSetting('theme.uri''default');
  581.         $filePath realpath(
  582.             $this->container->getParameter('kernel.root_dir')."/../web/themes/{$theme}/js/global-script.js"
  583.         );
  584.         if ($filePath) {
  585.             return 'theme/global-script';
  586.         }
  587.         return '';
  588.     }
  589.     public function isPluginInstalled($name)
  590.     {
  591.         return $this->container->get('kernel')->getPluginConfigurationManager()->isPluginInstalled($name);
  592.     }
  593.     public function getPluginVersion($name)
  594.     {
  595.         $plugins $this->container->get('kernel')->getPlugins();
  596.         foreach ($plugins as $plugin) {
  597.             if (strtolower($plugin['code']) == strtolower($name)) {
  598.                 return $plugin['version'];
  599.             }
  600.         }
  601.         return null;
  602.     }
  603.     public function versionCompare($version1$version2$operator)
  604.     {
  605.         return version_compare($version1$version2$operator);
  606.     }
  607.     public function getJsPaths($excludedCdnResources = [])
  608.     {
  609.         $cdnUrl = new CdnUrl();
  610.         $basePath $cdnUrl->get();
  611.         if (empty($basePath)) {
  612.             $basePath $this->container->get('request_stack')->getMainRequest()->getBasePath();
  613.         }
  614.         $theme $this->getSetting('theme.uri''default');
  615.         $plugins $this->container->get('kernel')->getPlugins();
  616.         $names = [];
  617.         $newPluginNames = [];
  618.         foreach ($plugins as $plugin) {
  619.             if (is_array($plugin)) {
  620.                 if ('plugin' != $plugin['type']) {
  621.                     continue;
  622.                 }
  623.                 if (isset($plugin['protocol']) && == $plugin['protocol']) {
  624.                     $newPluginNames[] = $plugin['code'].'plugin';
  625.                 } else {
  626.                     $names[] = $plugin['code'];
  627.                 }
  628.             } else {
  629.                 $names[] = $plugin;
  630.             }
  631.         }
  632.         $names[] = 'customweb';
  633.         $names[] = 'customadmin';
  634.         $names[] = 'custom';
  635.         $names[] = 'topxiaweb';
  636.         $names[] = 'topxiaadmin';
  637.         $names[] = 'classroom';
  638.         $names[] = 'materiallib';
  639.         $names[] = 'sensitiveword';
  640.         $names[] = 'permission';
  641.         $names[] = 'org';
  642.         $names[] = 'corporatetraining';
  643.         $paths = [
  644.             'common' => 'common',
  645.             'theme' => "{$basePath}/themes/{$theme}/js",
  646.         ];
  647.         foreach ($names as $name) {
  648.             $name strtolower($name);
  649.             if (!empty($excludedCdnResources) && in_array($name$excludedCdnResources)) {
  650.                 $paths["{$name}bundle"] = "/bundles/{$name}/js";
  651.             } else {
  652.                 $paths["{$name}bundle"] = "{$basePath}/bundles/{$name}/js";
  653.             }
  654.         }
  655.         foreach ($newPluginNames as $newPluginName) {
  656.             $newPluginName strtolower($newPluginName);
  657.             if (!empty($excludedCdnResources) && in_array($newPluginName$excludedCdnResources)) {
  658.                 $paths["{$newPluginName}"] = "/bundles/{$newPluginName}/js";
  659.             } else {
  660.                 $paths["{$newPluginName}"] = "{$basePath}/bundles/{$newPluginName}/js";
  661.             }
  662.         }
  663.         // $paths['balloon-video-player'] = 'http://player-cdn.edusoho.net/balloon-video-player';
  664.         return $paths;
  665.     }
  666.     public function getContextValue($context$key)
  667.     {
  668.         $keys explode('.'$key);
  669.         $value $context;
  670.         foreach ($keys as $key) {
  671.             if (!isset($value[$key])) {
  672.                 throw new \InvalidArgumentException(sprintf('Key `%s` is not in context with %s'$keyimplode(array_keys($context), ', ')));
  673.             }
  674.             $value $value[$key];
  675.         }
  676.         return $value;
  677.     }
  678.     public function isFeatureEnabled($feature)
  679.     {
  680.         $features $this->container->hasParameter('enabled_features') ? $this->container->getParameter(
  681.             'enabled_features'
  682.         ) : [];
  683.         return in_array($feature$features);
  684.     }
  685.     public function getParameter($name$default null)
  686.     {
  687.         if (!$this->container->hasParameter($name)) {
  688.             return $default;
  689.         }
  690.         return $this->container->getParameter($name);
  691.     }
  692.     public function makeUpoadToken($group$type 'image'$duration 18000)
  693.     {
  694.         $maker = new UploadToken();
  695.         return $maker->make($group$type$duration);
  696.     }
  697.     public function getConvertIP($ip)
  698.     {
  699.         if (!empty($ip)) {
  700.             $location ConvertIpToolkit::convertIp($ip);
  701.             if ('INNA' === $location) {
  702.                 return '未知区域';
  703.             }
  704.             return $location;
  705.         }
  706.         return '';
  707.     }
  708.     public function getNewConverIP($ip)
  709.     {
  710.         if (!empty($ip)) {
  711.             $location ConvertIpToolkit::newConvertIp($ip);
  712.             if ('INNA' === $location) {
  713.                 return '未知区域';
  714.             }
  715.             $location array_filter($location);
  716.             return implode(' '$location);
  717.         }
  718.         return '';
  719.     }
  720.     public function dateformatFilter($time$format '')
  721.     {
  722.         if (empty($time)) {
  723.             return;
  724.         }
  725.         if (empty($format)) {
  726.             return date('Y-m-d H:i'$time);
  727.         }
  728.         return date($format$time);
  729.     }
  730.     public function smarttimeFilter($time)
  731.     {
  732.         $diff time() - $time;
  733.         if ($diff 0) {
  734.             return $this->trans('site.twig.extension.smarttime.future');
  735.         }
  736.         if (== $diff) {
  737.             return $this->trans('site.twig.extension.smarttime.hardly');
  738.         }
  739.         if ($diff 60) {
  740.             return $this->trans('site.twig.extension.smarttime.previous_second', ['%diff%' => $diff]);
  741.         }
  742.         if ($diff 3600) {
  743.             return $this->trans('site.twig.extension.smarttime.previous_minute', ['%diff%' => round($diff 60)]);
  744.         }
  745.         if ($diff 86400) {
  746.             return $this->trans('site.twig.extension.smarttime.previous_hour', ['%diff%' => round($diff 3600)]);
  747.         }
  748.         if ($diff 2592000) {
  749.             return $this->trans('site.twig.extension.smarttime.previous_day', ['%diff%' => round($diff 86400)]);
  750.         }
  751.         if ($diff 31536000) {
  752.             return date('m-d'$time);
  753.         }
  754.         return date('Y-m-d'$time);
  755.     }
  756.     public function remainTimeFilter($value$timeType '')
  757.     {
  758.         $remainTime = [];
  759.         $remain $value time();
  760.         if ($remain <= && empty($timeType)) {
  761.             return $remainTime['second'] = '0'.$this->trans('site.date.minute');
  762.         }
  763.         if ($remain <= 3600 && empty($timeType)) {
  764.             return $remainTime['minutes'] = round($remain 60).$this->trans('site.date.minute');
  765.         }
  766.         if ($remain 86400 && empty($timeType)) {
  767.             return $remainTime['hours'] = round($remain 3600).$this->trans('site.date.hour');
  768.         }
  769.         $remainTime['day'] = round(($remain $remain) / 86400).$this->trans('site.date.day');
  770.         if (!empty($timeType)) {
  771.             return $remainTime[$timeType];
  772.         } else {
  773.             return $remainTime['day'];
  774.         }
  775.     }
  776.     public function getCountdownTime($value)
  777.     {
  778.         $countdown = ['days' => 0'hours' => 0'minutes' => 0'seconds' => 0];
  779.         $remain $value time();
  780.         if ($remain <= 0) {
  781.             return $countdown;
  782.         }
  783.         $countdown['days'] = intval($remain 86400);
  784.         $remain $remain 86400 $countdown['days'];
  785.         $countdown['hours'] = intval($remain 3600);
  786.         $remain $remain 3600 $countdown['hours'];
  787.         $countdown['minutes'] = intval($remain 60);
  788.         $remain $remain 60 $countdown['minutes'];
  789.         $countdown['seconds'] = $remain;
  790.         return $countdown;
  791.     }
  792.     public function durationFilter($value)
  793.     {
  794.         $minutes intval($value 60);
  795.         $seconds $value $minutes 60;
  796.         return sprintf('%02d'$minutes).':'.sprintf('%02d'$seconds);
  797.     }
  798.     public function durationTextFilter($value)
  799.     {
  800.         $minutes intval($value 60);
  801.         $seconds $value $minutes 60;
  802.         if (=== $minutes) {
  803.             return $seconds.$this->trans('site.date.second');
  804.         }
  805.         return $this->trans('site.twig.extension.time_interval.minute_second', ['%diff_minute%' => $minutes'%diff_second%' => $seconds]);
  806.     }
  807.     public function timeRangeFilter($start$end)
  808.     {
  809.         $range date('Y-n-d H:i'$start).' - ';
  810.         if ($this->container->get('topxia.timemachine')->inSameDay($start$end)) {
  811.             $range .= date('H:i'$end);
  812.         } else {
  813.             $range .= date('Y年n月d日 H:i'$end);
  814.         }
  815.         return $range;
  816.     }
  817.     public function timeDiffFilter($endTime$diffDay 0$startTime '')
  818.     {
  819.         $endSecond strtotime(date('Y-m-d'$endTime));
  820.         $startSecond = empty($startTime) ? strtotime(date('Y-m-d'time())) : $startTime;
  821.         $diffDay round(($endSecond $startSecond) / 864000PHP_ROUND_HALF_DOWN); // 丢弃小数点
  822.         return $diffDay $diffDay 0;
  823.     }
  824.     public function tagsJoinFilter($tagIds)
  825.     {
  826.         if (empty($tagIds) || !is_array($tagIds)) {
  827.             return '';
  828.         }
  829.         $tags $this->createService('Taxonomy:TagService')->findTagsByIds($tagIds);
  830.         $names ArrayToolkit::column($tags'name');
  831.         return join($names',');
  832.     }
  833.     public function navigationUrlFilter($url)
  834.     {
  835.         $url = (string) $url;
  836.         if (strpos($url'://')) {
  837.             return $url;
  838.         }
  839.         if (!empty($url[0]) && ('/' == $url[0])) {
  840.             return $url;
  841.         }
  842.         return $this->container->get('request_stack')->getMainRequest()->getBaseUrl().'/'.$url;
  843.     }
  844.     /**
  845.      *                            P -> 省全称,     p -> 省简称
  846.      *                            C -> 城市全称,    c -> 城市简称
  847.      *                            D -> 区全称,     d -> 区简称.
  848.      *
  849.      * @param [type] $districeId [description]
  850.      * @param string $format 格式,默认格式'P C D'
  851.      *
  852.      * @return [type] [description]
  853.      */
  854.     public function locationTextFilter($districeId$format 'P C D')
  855.     {
  856.         $text '';
  857.         $names $this->createService('Taxonomy:LocationService')->getLocationFullName($districeId);
  858.         $len strlen($format);
  859.         for ($i 0$i $len; ++$i) {
  860.             switch ($format[$i]) {
  861.                 case 'P':
  862.                     $text .= $names['province'];
  863.                     break;
  864.                 case 'p':
  865.                     $text .= $this->mb_trim($names['province'], '省');
  866.                     break;
  867.                 case 'C':
  868.                     $text .= $names['city'];
  869.                     break;
  870.                 case 'c':
  871.                     $text .= $this->mb_trim($names['city'], '市');
  872.                     break;
  873.                 case 'D':
  874.                 case 'd':
  875.                     $text .= $names['district'];
  876.                     break;
  877.                 default:
  878.                     $text .= $format[$i];
  879.                     break;
  880.             }
  881.         }
  882.         return $text;
  883.     }
  884.     public function tagsHtmlFilter($tags$class '')
  885.     {
  886.         $links = [];
  887.         $tags $this->createService('Taxonomy:TagService')->findTagsByIds($tags);
  888.         foreach ($tags as $tag) {
  889.             $url $this->container->get('router')->generate('course_explore', ['tagId' => $tag['id']]);
  890.             $links[] = "<a href=\"{$url}\" class=\"{$class}\">{$tag['name']}</a>";
  891.         }
  892.         return implode(' '$links);
  893.     }
  894.     public function parseFileUri($uri)
  895.     {
  896.         $kernel ServiceKernel::instance();
  897.         return $kernel->createService('Content:FileService')->parseFileUri($uri);
  898.     }
  899.     public function getFilePath($uri$default ''$absolute false)
  900.     {
  901.         $assets $this->container->get('assets.default_package_util');
  902.         $request $this->container->get('request_stack')->getMainRequest();
  903.         if (empty($uri)) {
  904.             $url $assets->getUrl('assets/img/default/'.$default);
  905.             // $url = $request->getBaseUrl() . '/assets/img/default/' . $default;
  906.             if ($absolute) {
  907.                 $url $request->getSchemeAndHttpHost().$url;
  908.             }
  909.             return $url;
  910.         }
  911.         if (false !== strpos($uri'http://')) {
  912.             return $uri;
  913.         }
  914.         $uri $this->parseFileUri($uri);
  915.         if ('public' == $uri['access']) {
  916.             $url rtrim($this->container->getParameter('topxia.upload.public_url_path'), ' /').'/'.$uri['path'];
  917.             $url ltrim($url' /');
  918.             $url $assets->getUrl($url);
  919.             if ($absolute) {
  920.                 $url $request->getSchemeAndHttpHost().$url;
  921.             }
  922.             return $url;
  923.         }
  924.     }
  925.     public function getDefaultPath($category$uri ''$size ''$absolute false)
  926.     {
  927.         $assets $this->container->get('assets.default_package_util');
  928.         $request $this->container->get('request_stack')->getMainRequest();
  929.         if (empty($uri)) {
  930.             $publicUrlpath 'assets/img/default/';
  931.             $url $assets->getUrl($publicUrlpath.$size.$category);
  932.             $defaultSetting $this->createService('System:SettingService')->get('default', []);
  933.             $key 'default'.ucfirst($category);
  934.             $fileName $key.'FileName';
  935.             if (array_key_exists($key$defaultSetting) && array_key_exists($fileName$defaultSetting)) {
  936.                 if (== $defaultSetting[$key]) {
  937.                     $url $assets->getUrl($publicUrlpath.$size.$defaultSetting[$fileName]);
  938.                 }
  939.             } elseif (array_key_exists($key$defaultSetting) && $defaultSetting[$key]) {
  940.                 $uri $defaultSetting[$size.'Default'.ucfirst($category).'Uri'];
  941.             } else {
  942.                 return $url;
  943.             }
  944.             if ($absolute) {
  945.                 $url $request->getSchemeAndHttpHost().$url;
  946.             }
  947.             return $url;
  948.         }
  949.         return $this->parseUri($uri$absolute);
  950.     }
  951.     public function avatarPath($user$type 'middle'$package 'user')
  952.     {
  953.         $avatar = !empty($user[$type.'Avatar']) ? $user[$type.'Avatar'] : null;
  954.         if (empty($avatar)) {
  955.             $avatar $this->getSetting('avatar.png');
  956.         }
  957.         return $this->getFpath($avatar'avatar.png'$package);
  958.     }
  959.     private function parseUri($uri$absolute false$package 'content')
  960.     {
  961.         if (false !== strpos($uri'http://') || false !== strpos($uri'https://')) {
  962.             return $uri;
  963.         }
  964.         $assets $this->container->get('assets.default_package_util');
  965.         $request $this->container->get('request_stack')->getMainRequest();
  966.         if (strpos($uri'://')) {
  967.             $uri $this->parseFileUri($uri);
  968.             $url '';
  969.             if ('public' == $uri['access']) {
  970.                 $url $uri['path'];
  971.             }
  972.             if ('themes' == $uri['access']) {
  973.                 return $this->addHost('/'.$uri['access'].'/'.$uri['path'], $absolute$package);
  974.             }
  975.         } else {
  976.             $url $uri;
  977.         }
  978.         $url rtrim($this->container->getParameter('topxia.upload.public_url_path'), ' /').'/'.$url;
  979.         return $this->addHost($url$absolute$package);
  980.     }
  981.     public function getSystemDefaultPath($defaultKey$absolute false)
  982.     {
  983.         $assets $this->container->get('assets.default_package_util');
  984.         $defaultSetting $this->getSetting('default', []);
  985.         if (array_key_exists($defaultKey$defaultSetting)
  986.             && $defaultSetting[$defaultKey]
  987.         ) {
  988.             $path $defaultSetting[$defaultKey];
  989.             return $this->parseUri($path$absolute);
  990.         } else {
  991.             $path $assets->getUrl('assets/img/default/'.$defaultKey);
  992.             return $this->addHost($path$absolute);
  993.         }
  994.     }
  995.     public function makeLazyImg($src$class ''$alt ''$img 'lazyload_course.png')
  996.     {
  997.         $imgpath $path $this->container->get('assets.default_package_util')->getUrl('assets/img/default/'.$img);
  998.         return sprintf('<img src="%s" alt="%s" class="%s" data-echo="%s" />'$imgpath$alt$class$src);
  999.     }
  1000.     public function loadScript($js)
  1001.     {
  1002.         $js is_array($js) ? $js : [$js];
  1003.         if ($this->pageScripts) {
  1004.             $this->pageScripts array_merge($this->pageScripts$js);
  1005.         } else {
  1006.             $this->pageScripts $js;
  1007.         }
  1008.     }
  1009.     public function exportScripts()
  1010.     {
  1011.         if (empty($this->pageScripts)) {
  1012.             $this->pageScripts = [];
  1013.         }
  1014.         return array_values(array_unique($this->pageScripts));
  1015.     }
  1016.     public function getFileUrl($uri$default ''$absolute false)
  1017.     {
  1018.         $assets $this->container->get('assets.default_package_util');
  1019.         $request $this->container->get('request_stack')->getMainRequest();
  1020.         if (empty($uri)) {
  1021.             $url $assets->getUrl('assets/img/default/'.$default);
  1022.             if ($absolute) {
  1023.                 $url $request->getSchemeAndHttpHost().$url;
  1024.             }
  1025.             return $url;
  1026.         }
  1027.         $url rtrim($this->container->getParameter('topxia.upload.public_url_path'), ' /').'/'.$uri;
  1028.         $url ltrim($url' /');
  1029.         $url $assets->getUrl($url);
  1030.         if ($absolute) {
  1031.             $url $request->getSchemeAndHttpHost().$url;
  1032.         }
  1033.         return $url;
  1034.     }
  1035.     public function getFurl($path$defaultKey false$package 'content')
  1036.     {
  1037.         return $this->getPublicFilePath($path$defaultKeytrue$package);
  1038.     }
  1039.     public function getFpath($path$defaultKey false$package 'content')
  1040.     {
  1041.         return $this->getPublicFilePath($path$defaultKeyfalse$package);
  1042.     }
  1043.     private function getPublicFilePath($path$defaultKey false$absolute false$package 'content')
  1044.     {
  1045.         $assets $this->container->get('assets.default_package_util');
  1046.         if (empty($path)) {
  1047.             $defaultSetting $this->getSetting('default', []);
  1048.             if ('user_avatar.png' == $defaultKey) {
  1049.                 $defaultKey 'avatar.png';
  1050.             }
  1051.             if ((('course.png' == $defaultKey && array_key_exists(
  1052.                             'defaultCoursePicture',
  1053.                             $defaultSetting
  1054.                         ) && == $defaultSetting['defaultCoursePicture'])
  1055.                     || ('avatar.png' == $defaultKey && array_key_exists(
  1056.                             'defaultAvatar',
  1057.                             $defaultSetting
  1058.                         ) && == $defaultSetting['defaultAvatar']))
  1059.                 && (array_key_exists($defaultKey$defaultSetting)
  1060.                     && $defaultSetting[$defaultKey])
  1061.             ) {
  1062.                 $path $defaultSetting[$defaultKey];
  1063.                 return $this->parseUri($path$absolute$package);
  1064.             } else {
  1065.                 return $this->addHost('/assets/img/default/'.$defaultKey$absolute$package);
  1066.             }
  1067.         }
  1068.         return $this->parseUri($path$absolute$package);
  1069.     }
  1070.     private function addHost($path$absolute$package 'content')
  1071.     {
  1072.         $cdn = new CdnUrl();
  1073.         $cdnUrl $cdn->get($package);
  1074.         if ($cdnUrl) {
  1075.             $isSecure $this->container->get('request_stack')->getMainRequest()->isSecure();
  1076.             $protocal $isSecure 'https:' 'http:';
  1077.             $path $protocal.$cdnUrl.$path;
  1078.         } elseif ($absolute) {
  1079.             $request $this->container->get('request_stack')->getMainRequest();
  1080.             $path $request->getSchemeAndHttpHost().$path;
  1081.         }
  1082.         return $path;
  1083.     }
  1084.     public function basePath($package 'content')
  1085.     {
  1086.         $cdn = new CdnUrl();
  1087.         $cdnUrl $cdn->get($package);
  1088.         if ($cdnUrl) {
  1089.             $isSecure $this->container->get('request_stack')->getMainRequest()->isSecure();
  1090.             $protocal $isSecure 'https:' 'http:';
  1091.             $path $protocal.$cdnUrl;
  1092.         } else {
  1093.             $request $this->container->get('request_stack')->getMainRequest();
  1094.             $path $request->getSchemeAndHttpHost();
  1095.         }
  1096.         return $path;
  1097.     }
  1098.     public function fileSizeFilter($size)
  1099.     {
  1100.         $currentValue $currentUnit null;
  1101.         $unitExps = ['B' => 0'KB' => 1'MB' => 2'GB' => 3];
  1102.         foreach ($unitExps as $unit => $exp) {
  1103.             $divisor pow(1024$exp);
  1104.             $currentUnit $unit;
  1105.             $currentValue $size $divisor;
  1106.             if ($currentValue 1024) {
  1107.                 break;
  1108.             }
  1109.         }
  1110.         return sprintf('%.2f'$currentValue).$currentUnit;
  1111.     }
  1112.     public function numberFilter($number)
  1113.     {
  1114.         if ($number <= 1000) {
  1115.             return $number;
  1116.         }
  1117.         $currentValue $currentUnit null;
  1118.         $unitExps = ['千' => 3'万' => 4'亿' => 8];
  1119.         foreach ($unitExps as $unit => $exp) {
  1120.             $divisor pow(10$exp);
  1121.             $currentUnit $unit;
  1122.             $currentValue $number $divisor;
  1123.             if ($currentValue 10) {
  1124.                 break;
  1125.             }
  1126.         }
  1127.         return sprintf('%.0f'$currentValue).$currentUnit;
  1128.     }
  1129.     public function loadObject($type$id)
  1130.     {
  1131.         $kernel ServiceKernel::instance();
  1132.         switch ($type) {
  1133.             case 'user':
  1134.                 return $kernel->createService('User:UserService')->getUser($id);
  1135.             case 'category':
  1136.                 return $this->getCategoryService()->getCategory($id);
  1137.             case 'course':
  1138.                 return $kernel->createService('Course:CourseService')->getCourse($id);
  1139.             case 'file_group':
  1140.                 return $kernel->createService('Content:FileService')->getFileGroup($id);
  1141.             default:
  1142.                 return null;
  1143.         }
  1144.     }
  1145.     public function plainTextFilter($text$length null)
  1146.     {
  1147.         $text strip_tags($text);
  1148.         $text str_replace(["\n""\r""\t"], ''$text);
  1149.         $text str_replace('&nbsp;'' '$text);
  1150.         $text trim($text);
  1151.         $length = (int) $length;
  1152.         if (($length 0) && (mb_strlen($text'UTF-8') > $length)) {
  1153.             $text mb_substr($text0$length'UTF-8');
  1154.             $text .= '...';
  1155.         }
  1156.         return $text;
  1157.     }
  1158.     public function subTextFilter($text$length null)
  1159.     {
  1160.         $text strip_tags($text);
  1161.         $text str_replace(["\n""\r""\t"], ''$text);
  1162.         $text str_replace('&nbsp;'' '$text);
  1163.         $text trim($text);
  1164.         $length = (int) $length;
  1165.         if (($length 0) && (mb_strlen($text'utf-8') > $length)) {
  1166.             $text mb_substr($text0$length'UTF-8');
  1167.             $text .= '...';
  1168.         }
  1169.         return $text;
  1170.     }
  1171.     public function mb_substr($text$length null)
  1172.     {
  1173.         $text strip_tags($text);
  1174.         $text str_replace(["\n""\r""\t"], ''$text);
  1175.         $text str_replace('&nbsp;'' '$text);
  1176.         $text trim($text);
  1177.         $length = (int) $length;
  1178.         if (($length 0) && (mb_strlen($text'utf-8') > $length)) {
  1179.             $text mb_substr($text0$length'UTF-8');
  1180.         }
  1181.         return $text;
  1182.     }
  1183.     public function getFileType($fileName$string null)
  1184.     {
  1185.         $fileName explode('.'$fileName);
  1186.         if ($string) {
  1187.             $name strtolower($fileName[count($fileName) - 1]).$string;
  1188.         }
  1189.         return $name;
  1190.     }
  1191.     public function getOrgMsg($orgId)
  1192.     {
  1193.         $orgService $this->createService('CorporateTrainingBundle:Org:OrgService');
  1194.         $org $orgService->getOrg($orgId);
  1195.         return $org;
  1196.     }
  1197.     public function getCategoryName($categoryId)
  1198.     {
  1199.         $categoryService $this->getCategoryService();
  1200.         if (empty($categoryId)) {
  1201.             return '';
  1202.         }
  1203.         $category $categoryService->getCategory($categoryId);
  1204.         if (empty($category)) {
  1205.             return '';
  1206.         }
  1207.         return $category['name'];
  1208.     }
  1209.     public function getCategoryIdsByCategories(array $categories)
  1210.     {
  1211.         if (empty($categories)) {
  1212.             return [];
  1213.         }
  1214.         return array_column($categories'id');
  1215.     }
  1216.     public function chrFilter($index)
  1217.     {
  1218.         return chr($index);
  1219.     }
  1220.     public function isHideThread($id)
  1221.     {
  1222.         $need $this->createService('Group:ThreadService')->sumGoodsCoinsByThreadId($id);
  1223.         $thread $this->createService('Group:ThreadService')->getThread($id);
  1224.         $data explode('[/hide]'$thread['content']);
  1225.         foreach ($data as $key => $value) {
  1226.             $value ' '.$value;
  1227.             sscanf($value'%[^[][hide=reply]%[^$$]'$replyContent$replyHideContent);
  1228.             if ($replyHideContent) {
  1229.                 return true;
  1230.             }
  1231.         }
  1232.         if ($need) {
  1233.             return true;
  1234.         }
  1235.         return false;
  1236.     }
  1237.     public function bbCode2HtmlFilter($bbCode)
  1238.     {
  1239.         $ext $this;
  1240.         $bbCode preg_replace_callback(
  1241.             '/\[image\](.*?)\[\/image\]/i',
  1242.             function ($matches) use ($ext) {
  1243.                 $src $ext->getFileUrl($matches[1]);
  1244.                 return "<img src='{$src}' />";
  1245.             },
  1246.             $bbCode
  1247.         );
  1248.         $bbCode preg_replace_callback(
  1249.             '/\[audio.*?id="(\d+)"\](.*?)\[\/audio\]/i',
  1250.             function ($matches) {
  1251.                 return "<span class='audio-play-trigger' href='javascript:;' data-file-id=\"{$matches[1]}\" data-file-type=\"audio\"></span>";
  1252.             },
  1253.             $bbCode
  1254.         );
  1255.         return $bbCode;
  1256.     }
  1257.     public function scoreTextFilter($text)
  1258.     {
  1259.         $text number_format($text1'.''');
  1260.         if ((int) $text == $text) {
  1261.             return (string) (int) $text;
  1262.         }
  1263.         return $text;
  1264.     }
  1265.     public function simpleTemplateFilter($text$variables)
  1266.     {
  1267.         foreach ($variables as $key => $value) {
  1268.             $text str_replace('{{'.$key.'}}'$value$text);
  1269.         }
  1270.         return $text;
  1271.     }
  1272.     public function fillQuestionStemTextFilter($stem)
  1273.     {
  1274.         return preg_replace('/\[\[.+?\]\]+/''____'$stem);
  1275.     }
  1276.     public function fillQuestionStemHtmlFilter($stem)
  1277.     {
  1278.         $index 0;
  1279.         $stem preg_replace_callback(
  1280.             '/\[\[.+?\]\]+/',
  1281.             function ($matches) use (&$index) {
  1282.                 ++$index;
  1283.                 return "<span class='question-stem-fill-blank'>({$index})</span>";
  1284.             },
  1285.             $stem
  1286.         );
  1287.         return $stem;
  1288.     }
  1289.     public function getCourseidFilter($target)
  1290.     {
  1291.         $target explode('/'$target);
  1292.         $target explode('-'$target[0]);
  1293.         return $target[1];
  1294.     }
  1295.     public function getPurifyHtml($html$trusted false)
  1296.     {
  1297.         if (empty($html)) {
  1298.             return '';
  1299.         }
  1300.         $biz $this->container->get('biz');
  1301.         return $biz['html_helper']->purify($html$trusted);
  1302.     }
  1303.     public function atFilter($text$ats = [])
  1304.     {
  1305.         if (empty($ats) || !is_array($ats)) {
  1306.             return $text;
  1307.         }
  1308.         $router $this->container->get('router');
  1309.         foreach ($ats as $nickname => $userId) {
  1310.             $path $router->generate('user_show', ['id' => $userId]);
  1311.             $html "<a href=\"{$path}\" data-uid=\"{$userId}\" target=\"_blank\">@{$nickname}</a>";
  1312.             $text preg_replace("/@{$nickname}/ui"$html$text);
  1313.         }
  1314.         return $text;
  1315.     }
  1316.     public function removeCopyright($source)
  1317.     {
  1318.         if ($this->getSetting('copyright.owned'false)) {
  1319.             $source str_ireplace('edusoho'''$source);
  1320.         }
  1321.         return $source;
  1322.     }
  1323.     public function getSetting($name$default null)
  1324.     {
  1325.         $names explode('.'$name);
  1326.         $name array_shift($names);
  1327.         if (empty($name)) {
  1328.             return $default;
  1329.         }
  1330.         $value $this->createService('System:SettingService')->get($name);
  1331.         if (!isset($value)) {
  1332.             return $default;
  1333.         }
  1334.         if (empty($names)) {
  1335.             return $value;
  1336.         }
  1337.         $result $value;
  1338.         foreach ($names as $name) {
  1339.             if (!isset($result[$name])) {
  1340.                 return $default;
  1341.             }
  1342.             $result $result[$name];
  1343.         }
  1344.         return $result;
  1345.     }
  1346.     public function getOrderPayment($order$default null)
  1347.     {
  1348.         $coinSettings $this->createService('System:SettingService')->get('coin', []);
  1349.         if (!isset($coinSettings['price_type'])) {
  1350.             $coinSettings['price_type'] = 'RMB';
  1351.         }
  1352.         if (!isset($coinSettings['coin_enabled'])) {
  1353.             $coinSettings['coin_enabled'] = 0;
  1354.         }
  1355.         if (!= $coinSettings['coin_enabled'] || 'coin' != $coinSettings['price_type']) {
  1356.             if ($order['coinAmount'] > && == $order['amount']) {
  1357.                 $default '余额支付';
  1358.             } else {
  1359.                 $dictExtension $this->container->get('codeages_plugin.dict_twig_extension');
  1360.                 $default $dictExtension->getDictText('payment'$order['payment']);
  1361.             }
  1362.         }
  1363.         return $default;
  1364.     }
  1365.     public function isPermitRole($classroomId$permission$isStudentOrAuditor false)
  1366.     {
  1367.         $funcName 'can'.$permission.'Classroom';
  1368.         if ($isStudentOrAuditor) {
  1369.             return $this->createService('Classroom:ClassroomService')->$funcName($classroomId$isStudentOrAuditor);
  1370.         }
  1371.         return $this->createService('Classroom:ClassroomService')->$funcName($classroomId);
  1372.     }
  1373.     public function calculatePercent($number$total)
  1374.     {
  1375.         if (== $number || == $total) {
  1376.             return '0%';
  1377.         }
  1378.         if ($number >= $total) {
  1379.             return '100%';
  1380.         }
  1381.         return round($number $total 100).'%';
  1382.     }
  1383.     public function rateFormat($rate$precision 0)
  1384.     {
  1385.         return round($rate$precision);
  1386.     }
  1387.     public function arrayMerge($text$content)
  1388.     {
  1389.         return array_merge($text$content);
  1390.     }
  1391.     public function getSetPrice($price)
  1392.     {
  1393.         return NumberToolkit::roundUp($price);
  1394.     }
  1395.     public function getCategoryChoices($groupCode$isFilter false$indent ' ')
  1396.     {
  1397.         $builder = new CategoryBuilder();
  1398.         return $builder->buildChoices($groupCode$isFilter$indent);
  1399.     }
  1400.     public function getCategoryChoicesWithCategoryEmpty($groupName$isFilter false$indent ' ')
  1401.     {
  1402.         $builder = new CategoryBuilder();
  1403.         $choices $builder->buildChoices($groupName$isFilter$indent);
  1404.         $newChoices[-1] = '未分类';
  1405.         return $newChoices $choices;
  1406.     }
  1407.     public function getNextExecutedTime()
  1408.     {
  1409.         return $this->createService('Crontab:CrontabService')->getNextExcutedTime();
  1410.     }
  1411.     public function getUploadMaxFilesize($formated true)
  1412.     {
  1413.         $max FileToolkit::getMaxFilesize();
  1414.         if ($formated) {
  1415.             return FileToolkit::formatFileSize($max);
  1416.         }
  1417.         return $max;
  1418.     }
  1419.     public function isTrial()
  1420.     {
  1421.         if (file_exists($this->container->getParameter('kernel.root_dir').'/data/trial.lock')) {
  1422.             return true;
  1423.         }
  1424.         return false;
  1425.     }
  1426.     public function timestamp()
  1427.     {
  1428.         return time();
  1429.     }
  1430.     public function blurUserName($name)
  1431.     {
  1432.         return mb_substr($name01'UTF-8').'**';
  1433.     }
  1434.     public function blur_phone_number($phoneNum)
  1435.     {
  1436.         $head substr($phoneNum03);
  1437.         $tail substr($phoneNum, -44);
  1438.         return $head.'****'.$tail;
  1439.     }
  1440.     public function blur_idcard_number($idcardNum)
  1441.     {
  1442.         $head substr($idcardNum04);
  1443.         $tail substr($idcardNum, -22);
  1444.         return $head.'************'.$tail;
  1445.     }
  1446.     public function blur_number($string)
  1447.     {
  1448.         if (SimpleValidator::email($string)) {
  1449.             $head substr($string01);
  1450.             $tail substr($stringstrpos($string'@'));
  1451.             return $head.'***'.$tail;
  1452.         } elseif (SimpleValidator::mobile($string)) {
  1453.             $head substr($string03);
  1454.             $tail substr($string, -44);
  1455.             return $head.'****'.$tail;
  1456.         } elseif (SimpleValidator::bankCardId($string)) {
  1457.             $tail substr($string, -44);
  1458.             return '**** **** **** '.$tail;
  1459.         } elseif (SimpleValidator::idcard($string)) {
  1460.             $head substr($string04);
  1461.             $tail substr($string, -22);
  1462.             return $head.'************'.$tail;
  1463.         }
  1464.     }
  1465.     public function mathFormat($number$multiplicator)
  1466.     {
  1467.         $number *= $multiplicator;
  1468.         return $number;
  1469.     }
  1470.     protected function createService($alias)
  1471.     {
  1472.         return $this->biz->service($alias);
  1473.     }
  1474.     protected function getAppService()
  1475.     {
  1476.         return $this->createService('CloudPlatform:AppService');
  1477.     }
  1478.     public function getPurifyAndTrimHtml($html)
  1479.     {
  1480.         $html strip_tags($html'');
  1481.         return preg_replace("/(\s|\&nbsp\;| |\xc2\xa0)/"''$html);
  1482.     }
  1483.     public function arrayColumn($array$column)
  1484.     {
  1485.         return ArrayToolkit::column($array$column);
  1486.     }
  1487.     private function trans($key$parameters = [])
  1488.     {
  1489.         return $this->container->get('translator')->trans($key$parameters);
  1490.     }
  1491.     public function mb_trim($string$charlist '\\\\s'$ltrim true$rtrim true)
  1492.     {
  1493.         $bothEnds $ltrim && $rtrim;
  1494.         $charClassInner preg_replace(
  1495.             ['/[\^\-\]\\\]/S''/\\\{4}/S'],
  1496.             ['\\\\\\0''\\'],
  1497.             $charlist
  1498.         );
  1499.         $workHorse '['.$charClassInner.']+';
  1500.         $ltrim && $leftPattern '^'.$workHorse;
  1501.         $rtrim && $rightPattern $workHorse.'$';
  1502.         if ($bothEnds) {
  1503.             $patternMiddle $leftPattern.'|'.$rightPattern;
  1504.         } elseif ($ltrim) {
  1505.             $patternMiddle $leftPattern;
  1506.         } else {
  1507.             $patternMiddle $rightPattern;
  1508.         }
  1509.         return preg_replace("/$patternMiddle/usSD"''$string);
  1510.     }
  1511.     public function wrap($object$type)
  1512.     {
  1513.         return $this->container->get('web.wrapper')->handle($object$type);
  1514.     }
  1515.     public function convertAbsoluteUrl($html)
  1516.     {
  1517.         $html preg_replace_callback('/src=[\'\"]\/(.*?)[\'\"]/', function ($matches) {
  1518.             $cdn = new CdnUrl();
  1519.             $cdnUrl $cdn->get('content');
  1520.             if (!empty($cdnUrl)) {
  1521.                 $absoluteUrl AssetHelper::getScheme().':'.rtrim($cdnUrl'/').'/'.ltrim($matches[1], '/');
  1522.             } else {
  1523.                 $absoluteUrl AssetHelper::uriForPath('/'.ltrim($matches[1], '/'));
  1524.             }
  1525.             return "src=\"{$absoluteUrl}\"";
  1526.         }, $html);
  1527.         return $html;
  1528.     }
  1529.     public function getLoginEmailAddress($email)
  1530.     {
  1531.         $dress explode('@'$email);
  1532.         $dress strtolower($dress[1]);
  1533.         $emailAddressMap = [
  1534.             'gmail.com' => 'mail.google.com',
  1535.             'vip.qq.com' => 'mail.qq.com',
  1536.             'vip.163.com' => 'vip.163.com',
  1537.             'vip.sina.com' => 'mail.sina.com.cn',
  1538.             'foxmail.com' => 'mail.qq.com',
  1539.             'hotmail.com' => 'www.hotmail.com',
  1540.             '188.com' => 'www.188.com',
  1541.             '139.com' => 'mail.10086.cn',
  1542.             '126.com' => 'www.126.com',
  1543.             'yeah.net' => 'yeah.net',
  1544.         ];
  1545.         if (!empty($emailAddressMap[$dress])) {
  1546.             return 'http://'.$emailAddressMap[$dress];
  1547.         }
  1548.         return 'http://mail.'.$dress;
  1549.     }
  1550.     public function getCloudSdkUrl($type)
  1551.     {
  1552.         return $this->getResourceFacadeService()->getFrontPlaySDKPathByType($type);
  1553.     }
  1554.     public function isWechatLoginBind()
  1555.     {
  1556.         $wechat $this->isMicroMessenger();
  1557.         $loginBind $this->getSetting('login_bind');
  1558.         return $wechat && !empty($loginBind['enabled']) && !empty($loginBind['weixinmob_enabled']);
  1559.     }
  1560.     public function makeLocalMediaFileToken($file)
  1561.     {
  1562.         $token $this->makeToken('local.media'$file['id']);
  1563.         return $token['token'];
  1564.     }
  1565.     /**
  1566.      * 获取在线咨询授权信息
  1567.      *
  1568.      * @return array
  1569.      */
  1570.     public function onlineAdvisoryAuthInfo()
  1571.     {
  1572.         $info = [
  1573.             'isCustom' => 'none',
  1574.         ];
  1575.         try {
  1576.             $api CloudAPIFactory::create('root');
  1577.             $info $api->get('/me');
  1578.             $displayLevel = ['personal''basic''medium''advanced''gold''custom'];
  1579.             if (is_array($info) && isset($info['level']) && in_array($info['level'], $displayLevel)) {
  1580.                 $info['isCustom'] = ('custom' == $info['level']) ? '是' '否';
  1581.             } else {
  1582.                 $info['isCustom'] = 'none';
  1583.             }
  1584.         } catch (\RuntimeException $e) {
  1585.         }
  1586.         return $info;
  1587.     }
  1588.     public function getSyncModeDict()
  1589.     {
  1590.         $dict = [
  1591.             'closed' => $this->trans('admin.sync-account-docking.btn.closed_btn'),
  1592.             'dingtalk' => $this->trans('admin.sync-account-docking.btn.dingtalk_btn'),
  1593.         ];
  1594.         if ($this->isPluginInstalled('WorkWechat')) {
  1595.             $dict['work_wechat'] = $this->trans('admin.sync-account-docking.btn.work_wechat_btn');
  1596.         }
  1597.         if ($this->isPluginInstalled('FeiShu')) {
  1598.             $dict['feishu'] = $this->trans('admin.sync-account-docking.btn.feishu_btn');
  1599.         }
  1600.         if ($this->isPluginInstalled('LDAP')) {
  1601.             $dict['LDAP'] = 'LDAP';
  1602.         }
  1603.         return $dict;
  1604.     }
  1605.     protected function makeToken($type$fileId$context = [])
  1606.     {
  1607.         $times = ('local.media' == $type) ? 100 10;
  1608.         $duration = ('local.media' == $type) ? 7200 3600;
  1609.         $fields = [
  1610.             'data' => [
  1611.                 'id' => $fileId,
  1612.             ],
  1613.             'times' => $times,
  1614.             'duration' => $duration,
  1615.             'userId' => $this->biz['user']['id'],
  1616.         ];
  1617.         if (isset($context['watchTimeLimit'])) {
  1618.             $fields['data']['watchTimeLimit'] = $context['watchTimeLimit'];
  1619.         }
  1620.         if (isset($context['hideBeginning'])) {
  1621.             $fields['data']['hideBeginning'] = $context['hideBeginning'];
  1622.         }
  1623.         return $this->getTokenService()->makeToken($type$fields);
  1624.     }
  1625.     public function isHiddenVideoHeader($isHidden false)
  1626.     {
  1627.         $storage $this->getSetting('storage');
  1628.         if (!empty($storage) && array_key_exists('video_header'$storage) && $storage['video_header'] && !$isHidden) {
  1629.             return false;
  1630.         }
  1631.         return true;
  1632.     }
  1633.     public function canSendMessage($userId)
  1634.     {
  1635.         $user $this->biz['user'];
  1636.         if (!$user->isLogin()) {
  1637.             return false;
  1638.         }
  1639.         if (in_array('ROLE_ADMIN'$user['roles']) || $user->isSuperAdmin()) {
  1640.             return true;
  1641.         }
  1642.         $toUser $this->getUserService()->getUser($userId);
  1643.         if ($user['id'] == $toUser['id']) {
  1644.             return false;
  1645.         }
  1646.         if (in_array('ROLE_ADMIN'$toUser['roles']) || in_array('ROLE_SUPER_ADMIN'$toUser['roles'])) {
  1647.             return true;
  1648.         }
  1649.         $messageSetting $this->getSetting('message', []);
  1650.         if (empty($messageSetting['teacherToStudent']) && $this->isTeacher($user['roles']) && $this->isOnlyStudent($toUser['roles'])) {
  1651.             return false;
  1652.         }
  1653.         if (empty($messageSetting['studentToStudent']) && $this->isOnlyStudent($user['roles']) && $this->isOnlyStudent($toUser['roles'])) {
  1654.             return false;
  1655.         }
  1656.         if (empty($messageSetting['studentToTeacher']) && $this->isOnlyStudent($user['roles']) && $this->isTeacher($toUser['roles'])) {
  1657.             return false;
  1658.         }
  1659.         return true;
  1660.     }
  1661.     public function daysOfWeek($day)
  1662.     {
  1663.         $weekName = ['日''一''二''三''四''五''六'];
  1664.         if (isset($weekName[$day])) {
  1665.             return $weekName[$day];
  1666.         }
  1667.         return false;
  1668.     }
  1669.     public function filterArrayKeys($array$keys)
  1670.     {
  1671.         foreach ($keys as $key) {
  1672.             unset($array[$key]);
  1673.         }
  1674.         return $array;
  1675.     }
  1676.     public function examScore($score)
  1677.     {
  1678.         return $score $score 0;
  1679.     }
  1680.     public function formatLearnTime($learnTime)
  1681.     {
  1682.         if ($learnTime 3600) {
  1683.             return round($learnTime 60).$this->trans('site.data.minute');
  1684.         }
  1685.         return round($learnTime 36001).$this->trans('site.date.hour');
  1686.     }
  1687.     public function groupBy($array$key)
  1688.     {
  1689.         return ArrayToolkit::group($array$key);
  1690.     }
  1691.     private function isTeacher($roles)
  1692.     {
  1693.         return in_array('ROLE_TEACHER'$roles);
  1694.     }
  1695.     private function isOnlyStudent($roles)
  1696.     {
  1697.         return in_array('ROLE_USER'$roles) && !in_array('ROLE_TEACHER'$roles) && !in_array('ROLE_ADMIN'$roles) && !in_array('ROLE_SUPER_ADMIN'$roles);
  1698.     }
  1699.     public function arraysKeyConvert($arrays$beforeKey$afterKey)
  1700.     {
  1701.         foreach ($arrays as $key => $value) {
  1702.             if ($value == $beforeKey) {
  1703.                 $arrays[$key][$afterKey] = $arrays[$key][$beforeKey];
  1704.                 unset($arrays[$key][$beforeKey]);
  1705.             }
  1706.         }
  1707.         return $arrays;
  1708.     }
  1709.     public function questionHtmlFilter($html$allowed '')
  1710.     {
  1711.         if (!isset($html)) {
  1712.             return '';
  1713.         }
  1714.         $html preg_replace('/(<img .*?src=")(.*?)(".*?>)/is''[图片]'$html);
  1715.         $security $this->getSettingService()->get('security');
  1716.         if (!empty($security['safe_iframe_domains'])) {
  1717.             $safeDomains $security['safe_iframe_domains'];
  1718.         } else {
  1719.             $safeDomains = [];
  1720.         }
  1721.         $config = [
  1722.             'cacheDir' => $this->biz['cache_directory'].'/htmlpurifier',
  1723.             'safeIframeDomains' => $safeDomains,
  1724.         ];
  1725.         $this->warmUp($config['cacheDir']);
  1726.         $htmlConfig = \HTMLPurifier_Config::createDefault();
  1727.         $htmlConfig->set('Cache.SerializerPath'$config['cacheDir']);
  1728.         $htmlConfig->set('HTML.Allowed'$allowed);
  1729.         $htmlpurifier = new \HTMLPurifier($htmlConfig);
  1730.         return $htmlpurifier->purify($html);
  1731.     }
  1732.     public function uniqid()
  1733.     {
  1734.         return MathToolkit::uniqid();
  1735.     }
  1736.     public function canOperateQuestion($user$question)
  1737.     {
  1738.         $currentUser $this->biz['user'];
  1739.         if ($currentUser->hasPermission('admin_question_gather_manage')) {
  1740.             return true;
  1741.         }
  1742.         if (in_array('ROLE_SUPER_ADMIN'$user['roles'])) {
  1743.             return true;
  1744.         }
  1745.         if (in_array('ROLE_TRAINING_ADMIN'$user['roles']) && $question['createdUserId'] === $user['id']) {
  1746.             return true;
  1747.         }
  1748.         return false;
  1749.     }
  1750.     public function showFeedbackBar($route)
  1751.     {
  1752.         if (in_array($route, [
  1753.             'course_teacher_evaluate_list',
  1754.             'project_plan_create',
  1755.             'project_plan_offline_course_homework_list',
  1756.             'survey_result_statistics',
  1757.         ])) {
  1758.             return true;
  1759.         }
  1760.         $allowedRoutes = [
  1761.             'course_set_manage',
  1762.             'course_manage',
  1763.             'classroom_manage',
  1764.             'offline_course_manage',
  1765.             'project_plan_study_data',
  1766.             'questionnaire_manage',
  1767.             'offline_activity_manage',
  1768.             'project_plan',
  1769.             'survey',
  1770.             'admin',
  1771.         ];
  1772.         foreach ($allowedRoutes as $allowedRoute) {
  1773.             if (!== stripos($route$allowedRoute)) {
  1774.                 continue;
  1775.             }
  1776.             if (!in_array($allowedRoute, ['project_plan''survey'])) {
  1777.                 return true;
  1778.             }
  1779.             if (false !== stripos($route'manage')) {
  1780.                 return true;
  1781.             }
  1782.         }
  1783.         if (false !== stripos($route'verify_list')) {
  1784.             return true;
  1785.         }
  1786.         return false;
  1787.     }
  1788.     public function isSaaS()
  1789.     {
  1790.         if ($this->isWithoutNetwork()) {
  1791.             return false;
  1792.         }
  1793.         $site $this->getSetting('site');
  1794.         if (empty($site['level']) || ($site['levelExpired'] ?? 0) < time()) {
  1795.             try {
  1796.                 $api CloudAPIFactory::create('root');
  1797.                 $info $api->get('/me');
  1798.             } catch (\RuntimeException $e) {
  1799.                 $info = [];
  1800.             }
  1801.             $site['level'] = $info['level'] ?? '';
  1802.             $site['levelExpired'] = time() + 7200;
  1803.             $this->getSettingService()->set('site'$site);
  1804.         }
  1805.         return in_array($this->getSetting('site.level'), $this->getSaaSLevels());
  1806.     }
  1807.     public function getSaaSLevels()
  1808.     {
  1809.         return ['personal''basic''medium''advanced''ct-basic''ct-standard''ct-professional''ct-flagship'];
  1810.     }
  1811.     public function getRememberMeDeadlineRangeText()
  1812.     {
  1813.         $rememberMeLifetime LoginToolkit::getRememberMeLifetime();
  1814.         if ($rememberMeLifetime 60 60) {
  1815.             return (int) ($rememberMeLifetime 60).$this->trans('site.data.minute');
  1816.         }
  1817.         if ($rememberMeLifetime 24 60 60) {
  1818.             return (int) ($rememberMeLifetime / (60 60)).$this->trans('site.date.hour');
  1819.         }
  1820.         return (int) ($rememberMeLifetime / (24 60 60)).$this->trans('site.date.day');
  1821.     }
  1822.     protected function warmUp($cacheDir)
  1823.     {
  1824.         if (!@mkdir($cacheDir0777true) && !is_dir($cacheDir)) {
  1825.             throw new ServiceException('mkdir cache dir error');
  1826.         }
  1827.         if (!is_writable($cacheDir)) {
  1828.             chmod($cacheDir0777);
  1829.         }
  1830.     }
  1831.     protected function getSettingService()
  1832.     {
  1833.         return $this->biz->service('System:SettingService');
  1834.     }
  1835.     /**
  1836.      * @return ResourceFacadeService
  1837.      */
  1838.     protected function getResourceFacadeService()
  1839.     {
  1840.         return $this->createService('CloudPlatform:ResourceFacadeService');
  1841.     }
  1842.     /**
  1843.      * @return TagService
  1844.      */
  1845.     protected function getTagService()
  1846.     {
  1847.         return $this->createService('Taxonomy:TagService');
  1848.     }
  1849.     /**
  1850.      * @return TokenService
  1851.      */
  1852.     protected function getTokenService()
  1853.     {
  1854.         return $this->createService('User:TokenService');
  1855.     }
  1856.     /**
  1857.      * @return mixed
  1858.      */
  1859.     public function getCategoryService()
  1860.     {
  1861.         return $this->createService('Taxonomy:CategoryService');
  1862.     }
  1863.     /**
  1864.      * @return ReviewCenterService
  1865.      */
  1866.     protected function getReviewCenterService()
  1867.     {
  1868.         return $this->createService('ReviewCenter:ReviewCenterService');
  1869.     }
  1870. }