• 首页
  • 友链
  • 排行
  • 友圈
  • 归档
  • 搜索
  • 夜间模式
    ©2021-2025  老罗博客 Theme by OneBlog
    搜索
    标签
    # 网络 # 游记
  • 首页>
  • 网络>
  • 正文
  • typecho利用rss订阅制作朋友圈

    2025年08月24日 91 阅读 14 评论 11366 字

    效果:网页版的朋友圈
    1、默认缓存1小时
    2、管理员状态可点击 “刷新缓存” 按钮更新。
    3、确保usr/cache/目录权限为755,文件权限为644,否则缓存失效,页面加载慢。
    4、提取了每个订阅的最新2篇文章
    5、增加了重试机制配置。
    最大重试次数($maxRetries = 3)
    设置了重试延迟时间($retryDelay = 1 秒)
    最终失败时会在错误信息中显示尝试次数

      <?php
        /**
        * 朋友圈
        *
        * @package custom
        */
        
        if (!defined('__TYPECHO_ROOT_DIR__')) exit;?>
        <?php $this->need('component/header.php'); ?>
        
        <!-- 引入pyq.css样式文件 -->
        <link rel="stylesheet" href="<?php $this->options->themeUrl('assets/css/pyq.css'); ?>">
        
            <!-- aside -->
            <?php $this->need('component/aside.php'); ?>
            <!-- / aside -->
        
           <a class="off-screen-toggle hide"></a>
           <main class="app-content-body <?php echo Content::returnPageAnimateClass($this); ?>">
            <div class="hbox hbox-auto-xs hbox-auto-sm">
            <!--文章-->
             <div class="col center-part gpu-speed" id="post-panel">
                <?php  echo Content::exportPostPageHeader($this,$this->user->uid); ?>
              <div class="wrapper-md">
               <?php echo Content::BreadcrumbNavigation($this, $this->options->rootUrl); ?>
               <div id="postpage" class="blog-post">
                <article class="single-post panel">
                    <?php echo Content::exportHeaderImg($this); ?>
                 <div id="post-content" class="wrapper-lg">
                <div class="container">
            <h1><?php $this->title() ?></h1>
            
            <?php
            // 缓存设置
            $cacheDir = __TYPECHO_ROOT_DIR__ . '/usr/cache/'; // Typecho默认缓存目录
            $cacheFile = $cacheDir . 'friends_circle_cache.html';
            $cacheTime = 3600; // 缓存时间:1小时(3600秒)
            
            // 确保缓存目录存在
            if (!is_dir($cacheDir)) {
                mkdir($cacheDir, 0755, true);
            }
            
            // 尝试读取缓存
            $cachedContent = false;
            if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTime)) {
                $cachedContent = file_get_contents($cacheFile);
            }
            
            // 管理员判断(Typecho 权限控制)
            if ($this->user->hasLogin()) {
                if (isset($_GET['refresh_pyq_cache']) && $_GET['refresh_pyq_cache'] == '1') {
                    // 删除缓存文件
                    if (file_exists($cacheFile)) unlink($cacheFile);
                    // 刷新页面
                    $this->response->redirect($this->permalink);
                }
                // 输出刷新按钮
                echo '<a href="' . $this->permalink . '?refresh_pyq_cache=1" class="refresh-cache-btn">刷新内容</a>';
            }
            
            
            if ($cachedContent === false) {
                // 缓存不存在或已过期,重新获取内容
                $feedUrls = [
                      '李的博客' => 'https://lilog.cn/feed',
                    '刘郎阁' => 'https://vjo.cc/feed'
                   
                   
                ];
                
                $allArticles = [];
                $errorMessages = [];
                
                // 创建超时上下文(5秒超时)
                $context = stream_context_create([
                    'http' => [
                        'timeout' => 5, // 超时时间设置为5秒
                        'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' // 添加用户代理,避免部分服务器拒绝访问
                    ],
                    'https' => [
                        'timeout' => 5 // HTTPS链接同样应用5秒超时
                    ]
                ]);
                
                foreach ($feedUrls as $blogName => $feedUrl) {
                    // 解析RSS(添加超时控制)
                    $feedContent = @file_get_contents($feedUrl, false, $context);
                  // 修改为带重试机制的代码
    $maxRetries = 3; // 最大重试次数
    $retryDelay = 1000000; // 重试延迟(微秒),1秒=1000000微秒
    $feedContent = false;
    
    // 重试循环
    for ($retry = 0; $retry < $maxRetries; $retry++) {
        $feedContent = @file_get_contents($feedUrl, false, $context);
        if ($feedContent !== false) {
            break; // 获取成功,跳出重试循环
        }
        // 重试前等待一段时间
        if ($retry < $maxRetries - 1) {
            usleep($retryDelay);
        }
    }
    
    // 所有重试都失败
    if (!$feedContent) {
        $errorMessages[] = "无法获取 {$blogName} 的内容(经过 {$maxRetries} 次重试仍失败)";
        continue;
    }
                    
                    // 加载XML
                    $xml = simplexml_load_string($feedContent);
                    if (!$xml) {
                        $errorMessages[] = "{$blogName} 的RSS格式错误";
                        continue;
                    }
                    
                    // 解析RSS(兼容RSS 2.0和Atom)
                    $items = [];
                    if (isset($xml->channel->item)) {
                        // RSS 2.0
                        $items = $xml->channel->item;
                    } elseif (isset($xml->entry)) {
                        // Atom
                        $items = $xml->entry;
                    }
                    
                    if (empty($items)) {
                        $errorMessages[] = "{$blogName} 暂无内容";
                        continue;
                    }
                    
                    // 提取最新2篇文章
                    $count = 0;
                    foreach ($items as $item) {
                        if ($count >= 2) break;
                        
                        // 获取标题和链接
                        $title = (string)($item->title ?? '无标题');
                        $link = (string)($item->link ?? ($item->guid ?? '#'));
                        
                        // 处理Atom格式的链接
                        if (isset($item->link['href'])) {
                            $link = (string)$item->link['href'];
                        }
                        
                        // 获取发布时间
                        $pubDate = (string)($item->pubDate ?? ($item->published ?? ''));
                        $pubTime = strtotime($pubDate);
                        $displayDate = $pubDate ? date('Y-m-d', $pubTime) : '';
                        
                        // 将文章添加到总数组
                        $allArticles[] = [
                            'title' => $title,
                            'link' => $link,
                            'date' => $displayDate,
                            'timestamp' => $pubTime,
                            'source' => $blogName
                        ];
                        
                        $count++;
                    }
                }
                
                // 按发布时间排序(最新的在前)
                usort($allArticles, function($a, $b) {
                    return $b['timestamp'] - $a['timestamp'];
                });
                
                // 生成输出内容
                $output = '';
                
                // 输出错误信息
                if (!empty($errorMessages)) {
                    foreach ($errorMessages as $msg) {
                        $output .= "<div class='error-message'>{$msg}</div>";
                    }
                }
                
                // 输出文章卡片
                if (!empty($allArticles)) {
                    $output .= '<div class="articles-container">';
                    
                    foreach ($allArticles as $article) {
                        $output .= '<div class="article-card">';
                        $output .= '<div class="card-title"><a href="' . $article['link'] . '" target="_blank" rel="noopener">' . $article['title'] . '</a></div>';
                        $output .= '<div class="card-meta">';
                        if ($article['date']) {
                            $output .= '<span class="card-date">' . $article['date'] . '</span>';
                        }
                        $output .= '<span class="card-source">来源: ' . $article['source'] . '</span>';
                        $output .= '</div></div>';
                    }
                    
                    $output .= '</div>';
                } else {
                    $output .= '<div class="error-message">没有获取到任何文章内容</div>';
                }
                
                // 保存到缓存文件
                file_put_contents($cacheFile, $output);
                $cachedContent = $output;
            }
            
            // 输出最终内容
            echo $cachedContent;
            ?>
        </div>
                     <?php Content::pageFooter($this->options,$this) ?>
                 </div>
                </article>
               </div>
                <?php $this->need('component/comments.php') ?>
              </div>
                 <?php echo WidgetContent::returnRightTriggerHtml() ?>
             </div>
             <!--文章右侧边栏开始-->
            <?php $this->need('component/sidebar.php'); ?>
             <!--文章右侧边栏结束-->
            </div>
           </main>
        <?php echo Content::returnReadModeContent($this,$this->user->uid,$content); ?>
        
            <!-- footer -->
            <?php $this->need('component/footer.php'); ?>
              <!-- / footer -->
    
    /* 文章卡片样式 */
        .article-card {
            background: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
            overflow: hidden;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            border: 1px solid #f0f0f0;
            padding: 12px;
            box-sizing: border-box;
        }
        
        .article-card:hover {
            transform: translateY(-3px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }
        
        /* 文章标题 - 移除h3标签,使用div+class,字号16px */
        .card-title {
            margin: 0 0 10px 0;
            font-size: 16px; /* 标题字号16px */
            line-height: 1.4;
            font-weight: normal;
        }
        
        .card-title a {
            color: #2d3748;
            text-decoration: none;
            transition: color 0.2s;
        }
        
        .card-title a:hover {
            color: #3182ce;
            text-decoration: none;
        }
        
        /* 元数据区域(日期和来源)- 同一行显示 */
        .card-meta {
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-size: 12px;
            gap: 8px; /* 两者之间保留间距 */
            flex-wrap: wrap; /* 防止小屏幕内容重叠 */
        }
        
        /* 发布日期和来源共享样式 */
        .card-date, .card-source {
            color: #718096;
            background: #f7fafc; /* 来源添加与日期相同的背景 */
            padding: 2px 6px;
            border-radius: 3px;
            white-space: nowrap; /* 防止内容换行 */
        }
        
        /* 错误提示样式 */
        .error-message {
            background: #fff5f5;
            border-left: 4px solid #e53e3e;
            padding: 15px;
            margin: 10px 0;
            color: #c53030;
            border-radius: 4px;
            font-size: 14px;
            box-sizing: border-box;
        }
    
    
    
    
    
    
    本文著作权归作者 [ 老罗 ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    网络
    取消回复

    发表留言
    回复

    读者留言14

    1. 全局变量 Lv.1
      2025-08-25 10:43 回复

      可增加重试机制避免网络波动异常

      1. 老罗
        2025-08-25 11:43 回复
        @全局变量

        好的,我去试试

    2. LiuShen Lv.2
      2025-08-25 00:01 回复

      呜,为啥抓不到我的 ::QQ:ganga::

      1. 老罗
        2025-08-25 08:23 回复
        @LiuShen

        换你atom那个抓到了😄

        1. LiuShen Lv.2
          2025-08-25 11:23 回复
          @老罗

          什么叫换,我好像本来就只有这一个来着:$(闭嘴)

          1. 老罗
            2025-08-25 11:42 回复
            @LiuShen

            你忘记了吧😂,我在你这个订阅页面https://blog.liushen.fun/subscribe看到的,有两个。
            RSS2 格式:https://blog.liushen.fun/rss2.xml
            Atom 格式:https://blog.liushen.fun/atom.xml

            1. 老罗
              2025-08-25 11:55
              @老罗

              不小心被我发现碰巧又用上了😄

            2. LiuShen Lv.2
              2025-08-25 11:45
              @老罗

              嘶,老早之前删掉了,没想到这里还写着哈哈:$(坏笑)

    3. 刘郎 Lv.2
      2025-08-24 23:57 回复

      自己之前弄了好几个rss订阅的 感觉都用不上 不好用😂后面直接放弃了

      1. 老罗
        2025-08-25 08:26 回复
        @刘郎

        我也是不断捣鼓这个😄

    4. 李的日志 Lv.2
      2025-08-24 20:25 回复

      还有获取不到的提示语,不错(可以把没开通feed规避掉

      1. 老罗
        2025-08-24 21:24 回复
        @李的日志

        下一步打算把订阅源放在后台主题设置里添加,这个主题有点复杂

    5. ACEVS Lv.2
      2025-08-24 15:16 回复

      效果不错。有的链接没有更新

      1. 老罗
        2025-08-24 21:22 回复
        @ACEVS

        有些可能是临时打不开

    加载更多评论
    加载中...
    — 已加载全部评论 —
    首页友链排行友圈归档
    Copyright©2021-2025  All Rights Reserved.  Load:0.047 s
    粤ICP备2024302751号-1
    Theme by OneBlog V3.6.3
    夜间模式

    开源不易,请尊重作者版权,保留基本的版权信息。