php中RSS订阅类的使用方法

胖强君_4167

胖强君_4167

2018-06-13

3200人浏览

原创

这篇文章主要介绍了php生成rss订阅的方法,较为详细的分析了一个rss订阅类及其具体使用技巧,非常具有实用价值,需要的朋友可以参考下

本文实例讲述了php生成RSS订阅的方法。具体分析如下:

RSS(简易信息聚合,也叫聚合内容)是一种描述和同步网站内容的格式。RSS可以是以下三个解释的其中一个: Really Simple Syndication;RDF (Resource Description Framework) Site Summary; Rich Site Summary。但其实这三个解释都是指同一种Syndication的技术。RSS目前广泛用于网上新闻频道,blog和wiki。使用RSS订阅能更快地获取信息,网站提供RSS输出,有利于让用户获取网站内容的最新更新。网络用户可以在客户端借助于支持RSS的聚合工具软件,在不打开网站内容页面的情况下阅读支持RSS输出的网站内容。
从技术上来说一个RSS文件就是一段规范的XML数据,该文件一般以rss,xml或者rdf作为后缀,下面是一段 rss 文件的内容示例:

代码如下:

<?xml  version="1.0" encoding="utf-8"?> 
<rss> 
<channel> 
<title>PHP中文网</title> 
<link>//www.php.cn/ 
<description>PHP中文网</description> 
<item> 
<title>RSS Tutorial</title> 
<link>网站地址/rss 
<description>New RSS tutorial on W3School</description> 
</item> 
<item> 
<title>XML Tutorial</title> 
<link>网站地址/xml 
<description>New XML tutorial on W3School</description> 
</item> 
</channel> 
</rss>

下面分享一段使用 php 动态生成 RSS 的代码示例:

代码如下:

<?php  
/** 
** php 动态生成 RSS 类 
**/ 
define("TIME_ZONE",""); 
define("FEEDCREATOR_VERSION","www.jb51.net");//您的网址 
class FeedItem extends HtmlDescribable{ 
    var $title,$description,$link; 
    var $author,$authorEmail,$image,$category,$comments,$guid,$source,$creator;
    var $date;
    var $additionalElements=Array(); 
} 
 
class FeedImage extends HtmlDescribable{ 
    var $title,$url,$link; 
    var $width,$height,$description; 
} 
 
class HtmlDescribable{ 
    var $descriptionHtmlSyndicated; 
    var $descriptionTruncSize; 
 
    function getDescription(){ 
        $descriptionField=new FeedHtmlField($this->description); 
        $descriptionField->syndicateHtml=$this->descriptionHtmlSyndicated;
        $descriptionField->truncSize=$this->descriptionTruncSize;
        return $descriptionField->output(); 
    } 
} 
 
class FeedHtmlField{ 
    var $rawFieldContent; 
    var $truncSize,$syndicateHtml; 
    function FeedHtmlField($parFieldContent){ 
        if($parFieldContent){ 
            $this->rawFieldContent=$parFieldContent; 
        } 
    } 
    function output(){ 
        if(!$this->rawFieldContent){ 
            $result=""; 
        }    elseif($this->syndicateHtml){ 
            $result="rawFieldContent."]]>"; 
        }else{ 
            if($this->truncSize and is_int($this->truncSize)){ 
                $result=FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize);
            }else{ 
                $result=htmlspecialchars($this->rawFieldContent); 
            } 
        } 
        return $result; 
    } 
} 
 
class UniversalFeedCreator extends FeedCreator{ 
    var $_feed; 
    function _setFormat($format){ 
        switch (strtoupper($format)){ 
            case "2.0": 
                // fall through 
            case "RSS2.0": 
                $this->_feed=new RSSCreator20(); 
                break; 
            case "0.91": 
                // fall through 
            case "RSS0.91": 
                $this->_feed=new RSSCreator091(); 
                break; 
            default: 
                $this->_feed=new RSSCreator091(); 
                break; 
        } 
        $vars=get_object_vars($this); 
        foreach ($vars as $key => $value){ 
            // prevent overwriting of properties "contentType","encoding"; do not copy "_feed" itself 
            if(!in_array($key, array("_feed","contentType","encoding"))){ 
                $this->_feed->{$key}=$this->{$key}; 
            } 
        } 
    } 
 
    function createFeed($format="RSS0.91"){ 
        $this->_setFormat($format); 
        return $this->_feed->createFeed(); 
    } 
 
    function saveFeed($format="RSS0.91",$filename="",$displayContents=true){ 
        $this->_setFormat($format); 
        $this->_feed->saveFeed($filename,$displayContents); 
    } 
 
    function useCached($format="RSS0.91",$filename="",$timeout=3600){ 
        $this->_setFormat($format); 
        $this->_feed->useCached($filename,$timeout); 
    } 
} 
 
class FeedCreator extends HtmlDescribable{ 
    var $title,$description,$link; 
    var $syndicationURL,$image,$language,$copyright,$pubDate,$lastBuildDate,$editor,$editorEmail,$webmaster,$category,$docs,$ttl,$rating,$skipHours,$skipDays;
    var $xslStyleSheet=""; 
    var $items=Array(); 
    var $contentType="application/xml"; 
    var $encoding="utf-8"; 
    var $additionalElements=Array(); 
 
    function addItem($item){ 
        $this->items[]=$item; 
    } 
 
    function clearItem2Null(){ 
        $this->items=array(); 
    } 
 
    function iTrunc($string,$length){ 
        if(strlen($string)=$length-4){ 
            $string=substr($string,0,$length-4); 
            $pos=strrpos($string,"."); 
        } 
        if($pos>=$length*0.4){ 
            return substr($string,0,$pos+1)." ..."; 
        } 
 
        $pos=strrpos($string," "); 
        if($pos>=$length-4){ 
            $string=substr($string,0,$length-4); 
            $pos=strrpos($string," "); 
        } 
        if($pos>=$length*0.4){ 
            return substr($string,0,$pos)." ..."; 
        } 
 
        return substr($string,0,$length-4)." ..."; 
    } 
 
    function _createGeneratorComment(){ 
        return "<!-- generator="".FEEDCREATOR_VERSION."" -->
"; 
    } 
 
    function _createAdditionalElements($elements,$indentString=""){ 
        $ae=""; 
        if(is_array($elements)){ 
            foreach($elements AS $key => $value){ 
                $ae.= $indentString."$value$key>
"; 
            } 
        } 
        return $ae; 
    } 
 
    function _createStylesheetReferences(){ 
        $xml=""; 
        if($this->cssStyleSheet) $xml .= "<?xml-stylesheet  href="".$this->cssStyleSheet."" type="text/css"?>
"; 
        if($this->xslStyleSheet) $xml .= "<?xml-stylesheet  href="".$this->xslStyleSheet."" type="text/xsl"?>
"; 
        return $xml; 
    } 
 
    function createFeed(){} 
 
    function _generateFilename(){ 
        $fileInfo=pathinfo($_SERVER["PHP_SELF"]); 
        return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml"; 
    } 
 
    function _redirect($filename){ 
        Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename)); 
        Header("Content-Disposition: inline; filename=".basename($filename)); 
        readfile($filename,"r"); 
        die(); 
    } 
 
    function useCached($filename="",$timeout=3600){ 
        $this->_timeout=$timeout; 
        if($filename==""){ 
            $filename=$this->_generateFilename(); 
        } 
        if(file_exists($filename) && (time()-filemtime($filename) _redirect($filename); 
        } 
    } 
 
    function saveFeed($filename="",$displayContents=true){ 
        if($filename==""){ 
            $filename=$this->_generateFilename(); 
        } 
        $feedFile=fopen($filename,"w+"); 
        if($feedFile){ 
            fputs($feedFile,$this->createFeed()); 
            fclose($feedFile); 
            if($displayContents){ 
                $this->_redirect($filename); 
            } 
        }else{ 
            echo "<br><b>Error creating feed file, please check write permissions.</b><br>"; 
        } 
    } 
} 
 
class FeedDate{ 
    var $unix; 
    function FeedDate($dateString=""){ 
        if($dateString=="") $dateString=date("r"); 
        if(is_integer($dateString)){ 
            $this->unix=$dateString; 
            return; 
        } 
        if(preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s+)?(\d{1,2})\s+([a-zA-Z]{3})\s+(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s+(.*)~",$dateString,$matches)){ 
            $months=Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12); 
            $this->unix=mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]); 
            if(substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-'){ 
                $tzOffset=(substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; 
            }else{ 
                if(strlen($matches[7])==1){ 
                    $oneHour=3600; 
                    $ord=ord($matches[7]); 
                    if($ord = ord("M") && $matches[7]!="Z"){ 
                        $tzOffset=($ord - ord("M")) * $oneHour; 
                    } elseif($matches[7]=="Z"){ 
                        $tzOffset=0; 
                    } 
                } 
                switch ($matches[7]){ 
                    case "UT": 
                    case "GMT":    $tzOffset=0; 
                } 
            } 
            $this->unix += $tzOffset; 
            return; 
        } 
        if(preg_match("~(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(.*)~",$dateString,$matches)){ 
            $this->unix=mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]); 
            if(substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-'){ 
                $tzOffset=(substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; 
            }else{ 
                if($matches[7]=="Z"){ 
                    $tzOffset=0; 
                } 
            } 
            $this->unix += $tzOffset; 
            return; 
        } 
        $this->unix=0; 
    } 
 
    function rfc822(){ 
        $date=gmdate("Y-m-d H:i:s",$this->unix); 
        if(TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE); 
        return $date; 
    } 
 
    function iso8601(){ 
        $date=gmdate("Y-m-d H:i:s",$this->unix); 
        $date=substr($date,0,22) . ':' . substr($date,-2); 
        if(TIME_ZONE!="") $date=str_replace("+00:00",TIME_ZONE,$date); 
        return $date; 
    } 
 
    function unix(){ 
        return $this->unix; 
    } 
} 
 
class RSSCreator10 extends FeedCreator{ 
    function createFeed(){ 
        $feed="<?xml  version="1.0" encoding="".$this->encoding.""?>
"; 
        $feed.= $this->_createGeneratorComment(); 
        if($this->cssStyleSheet==""){ 
            $cssStyleSheet="http://www.w3.org/2000/08/w3c-synd/style.css"; 
        } 
        $feed.= $this->_createStylesheetReferences(); 
        $feed.= "<rdf>
"; 
        $feed.= "    <channel>syndicationURL."">
"; 
        $feed.= "        <title>".htmlspecialchars($this->title)."</title>
"; 
        $feed.= "        <description>".htmlspecialchars($this->description)."</description>
"; 
        $feed.= "        <link>".$this->link."
"; 
        if($this->image!=null){ 
            $feed.= "        <image>image->url."" />
"; 
        } 
        $now=new FeedDate(); 
        $feed.= "       <date>".htmlspecialchars($now->iso8601())."</date>
"; 
        $feed.= "        <items>
"; 
        $feed.= "            <seq>
"; 
        for ($i=0;$i<count>items);$i++){ 
            $feed.= "                <li>items[$i]->link).""/>
"; 
        } 
        $feed.= "            </li></count></seq>
"; 
        $feed.= "        </items>
"; 
        $feed.= "    </image></channel>
"; 
        if($this->image!=null){ 
            $feed.= "    <image>image->url."">
"; 
            $feed.= "        <title>".$this->image->title."</title>
"; 
            $feed.= "        <link>".$this->image->link."
"; 
            $feed.= "        <url>".$this->image->url."</url>
"; 
            $feed.= "    </image>
"; 
        } 
        $feed.= $this->_createAdditionalElements($this->additionalElements,"    "); 
 
        for ($i=0;$i<count>items);$i++){ 
            $feed.= "    <item>items[$i]->link)."">
"; 
            //$feed.= "        <type>Posting</type>
"; 
            $feed.= "        <format>text/html</format>
"; 
            if($this->items[$i]->date!=null){ 
                $itemDate=new FeedDate($this->items[$i]->date); 
                $feed.= "        <date>".htmlspecialchars($itemDate->iso8601())."</date>
"; 
            } 
            if($this->items[$i]->source!=""){ 
                $feed.= "        <source>".htmlspecialchars($this->items[$i]->source)."</source>
"; 
            } 
            if($this->items[$i]->author!=""){ 
                $feed.= "        <creator>".htmlspecialchars($this->items[$i]->author)."</creator>
"; 
            } 
            $feed.= "        <title>".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"

","  ")))."</title>
"; 
            $feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."
"; 
            $feed.= "        <description>".htmlspecialchars($this->items[$i]->description)."</description>
"; 
            $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements,"        "); 
            $feed.= "    </item>
"; 
        } 
        $feed.= "</count></rdf>
"; 
        return $feed; 
    } 
} 
 
class RSSCreator091 extends FeedCreator{ 
    var $RSSVersion; 
 
    function RSSCreator091(){ 
        $this->_setRSSVersion("0.91"); 
        $this->contentType="application/rss+xml"; 
    } 
 
    function _setRSSVersion($version){ 
        $this->RSSVersion=$version; 
    } 
 
    function createFeed(){ 
        $feed="<?xml  version="1.0" encoding="".$this->encoding.""?>
"; 
        $feed.= $this->_createGeneratorComment(); 
        $feed.= $this->_createStylesheetReferences(); 
        $feed.= "<rss>RSSVersion."">
"; 
        $feed.= "    <channel>
"; 
        $feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>
"; 
        $this->descriptionTruncSize=500; 
        $feed.= "        <description>".$this->getDescription()."</description>
"; 
        $feed.= "        <link>".$this->link."
"; 
        $now=new FeedDate(); 
        $feed.= "        <lastbuilddate>".htmlspecialchars($now->rfc822())."</lastbuilddate>
"; 
        $feed.= "        <generator>".FEEDCREATOR_VERSION."</generator>
"; 
 
        if($this->image!=null){ 
            $feed.= "        <image>
"; 
            $feed.= "            <url>".$this->image->url."</url>
"; 
            $feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."</title>
"; 
            $feed.= "            <link>".$this->image->link."
"; 
            if($this->image->width!=""){ 
                $feed.= "            <width>".$this->image->width."</width>
"; 
            } 
            if($this->image->height!=""){ 
                $feed.= "            <height>".$this->image->height."</height>
"; 
            } 
            if($this->image->description!=""){ 
                $feed.= "            <description>".$this->image->getDescription()."</description>
"; 
            } 
            $feed.= "        </image>
"; 
        } 
        if($this->language!=""){ 
            $feed.= "        <language>".$this->language."</language>
"; 
        } 
        if($this->copyright!=""){ 
            $feed.= "        <copyright>".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."</copyright>
"; 
        } 
        if($this->editor!=""){ 
            $feed.= "        <managingeditor>".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."</managingeditor>
"; 
        } 
        if($this->webmaster!=""){ 
            $feed.= "        <webmaster>".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."</webmaster>
"; 
        } 
        if($this->pubDate!=""){ 
            $pubDate=new FeedDate($this->pubDate); 
            $feed.= "        <pubdate>".htmlspecialchars($pubDate->rfc822())."</pubdate>
"; 
        } 
        if($this->category!=""){ 
            $feed.= "        <category>".htmlspecialchars($this->category)."</category>
"; 
        } 
        if($this->docs!=""){ 
            $feed.= "        <docs>".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."</docs>
"; 
        } 
        if($this->ttl!=""){ 
            $feed.= "        <ttl>".htmlspecialchars($this->ttl)."</ttl>
"; 
        } 
        if($this->rating!=""){ 
            $feed.= "        <rating>".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."</rating>
"; 
        } 
        if($this->skipHours!=""){ 
            $feed.= "        <skiphours>".htmlspecialchars($this->skipHours)."</skiphours>
"; 
        } 
        if($this->skipDays!=""){ 
            $feed.= "        <skipdays>".htmlspecialchars($this->skipDays)."</skipdays>
"; 
        } 
        $feed.= $this->_createAdditionalElements($this->additionalElements,"    "); 
 
        for ($i=0;$i<count>items);$i++){ 
            $feed.= "        <item>
"; 
            $feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>
"; 
            $feed.= "            <link>".htmlspecialchars($this->items[$i]->link)."
"; 
            $feed.= "            <description>".$this->items[$i]->getDescription()."</description>
"; 
 
            if($this->items[$i]->author!=""){ 
                $feed.= "            <author>".htmlspecialchars($this->items[$i]->author)."</author>
"; 
            } 
            /* 
             // on hold 
             if($this->items[$i]->source!=""){ 
             $feed.= "            <source>".htmlspecialchars($this->items[$i]->source)."</source>
"; 
             } 
             */ 
            if($this->items[$i]->category!=""){ 
                $feed.= "            <category>".htmlspecialchars($this->items[$i]->category)."</category>
"; 
            } 
            if($this->items[$i]->comments!=""){ 
                $feed.= "            <comments>".htmlspecialchars($this->items[$i]->comments)."</comments>
"; 
            } 
            if($this->items[$i]->date!=""){ 
                $itemDate=new FeedDate($this->items[$i]->date); 
                $feed.= "            <pubdate>".htmlspecialchars($itemDate->rfc822())."</pubdate>
"; 
            } 
            if($this->items[$i]->guid!=""){ 
                $feed.= "            <guid>".htmlspecialchars($this->items[$i]->guid)."</guid>
"; 
            } 
            $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements,"        "); 
            $feed.= "        </item>
"; 
        } 
        $feed.= "    </count></channel>
"; 
        $feed.= "</rss>
"; 
        return $feed; 
    } 
} 
 
class RSSCreator20 extends RSSCreator091{ 
 
    function RSSCreator20(){ 
        parent::_setRSSVersion("2.0"); 
    } 
}


使用示例:

PHP
PHP

编写健壮的PHP代码,规避类型转换陷阱、数组怪癖及常见安全漏洞。

下载

代码如下:

<?php  
header(&#39;Content-Type:text/html; charset=utf-8&#39;); 
$db=mysql_connect(&#39;127.0.0.1&#39;,&#39;root&#39;,&#39;123456&#39;); 
mysql_query("set names utf8"); 
mysql_select_db(&#39;dbname&#39;,$db); 
$brs=mysql_query(&#39;select * from article order by add_time desc limit 0,10&#39;,$db); 
$rss=new UniversalFeedCreator(); 
$rss->title="页面标题"; 
$rss->link="网址http://"; 
$rss->description="rss标题"; 
while($rowbrs=mysql_fetch_array($brs)){ 
    $item=new FeedItem(); 
    $item->title =$rowbrs['subject']; 
    $item->link='//www.jb51.net/'; 
    $item->description =$rowbrs['description']; 
    $rss->addItem($item); 
} 
mysql_close($db); 
$rss->saveFeed("RSS2.0","rss.xml");

总结:以上就是本篇文的全部内容,希望能对大家的学习有所帮助。

相关推荐:

php通用图片处理类的用法

php实现上传图片客户端和服务器端的方法

php利用数组填充下拉列表框

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
AI视频生成软件推荐
AI视频生成软件推荐

本专题汇总了当前主流的AI视频生成软件推荐与排行榜单,涵盖seko、AniShort、剧云、Lovart、LiblibAI及立刻mv等热门工具。同时整理了各软件在文生视频、图生视频、时长限制、画质表现及免费额度等方面的差异对比,助您快速选对适合创作需求的AI视频生成工具。

2026.09.16

140

9

ai生成视频的工具免费版合集
ai生成视频的工具免费版合集

本专题汇总了当前免费AI生成视频工具的排行榜与推荐清单,涵盖seko、讯飞智作、AniShort及剧云、Lovart等多模型集成平台。同时整理了各工具的免费额度、输出时长、水印政策及适用场景差异,助您快速选择合适工具开启AI视频创作。

2026.09.16

60

10

Pandas时间序列分析与可视化报表
Pandas时间序列分析与可视化报表

本专题整理Pandas日期转换、时间索引、重采样、滚动窗口、时区处理、plot绘图、Styler表格样式和报表输出方法。

2026.09.16

60

23

Pandas数据筛选索引与清洗处理
Pandas数据筛选索引与清洗处理

本专题整理Pandas中的loc、iloc、条件筛选、query查询、缺失值处理、重复值删除、类型转换和字符串列清洗方法。

2026.09.16

40

25

Pandas数据读取导入与文件导出处理
Pandas数据读取导入与文件导出处理

本专题整理Pandas读取CSV、Excel、JSON、SQL、Parquet等文件的方法,以及to_csv、to_excel、to_sql和to_parquet等常用数据导出流程。

2026.09.16

40

27

GDB怎么设置断点
GDB怎么设置断点

本专题介绍GDB按照函数名、源代码行号和文件位置设置断点的方法,详细说明run、continue、next、step等命令的配合使用,帮助定位程序崩溃、逻辑异常及代码未按预期执行的问题。

2026.09.11

360

28

GDB怎么查看变量值
GDB怎么查看变量值

本专题介绍GDB调试过程中查看变量值的具体方法,涵盖局部变量、函数参数、数组、结构体和指针内容查询,同时整理变量持续显示、格式化输出及无法读取变量时的排查思路。

2026.09.11

120

22

GDB C++程序怎么调试
GDB C++程序怎么调试

本专题围绕GDB调试C++程序的实际过程,详细说明程序编译、调试器启动、命令行参数传入、断点命中和程序继续运行等步骤,并介绍条件断点、临时断点和观察点的设置方法,方便开发者跟踪复杂代码的执行状态。

2026.09.11

120

20

Iris框架MVC架构与依赖注入合集
Iris框架MVC架构与依赖注入合集

本专题讲解Iris框架MVC开发模式,包含控制器注册、方法命名与路径映射、By参数绑定、BeforeActivation自定义路由,以及依赖注入容器注册、数据库依赖注入、返回值序列化及MVC下WebSocket与gRPC整合实践。

2026.09.11

80

15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
墨刀帮助中心
墨刀帮助中心

共0课时 | 0人学习

MyEclipse学习中心
MyEclipse学习中心

共0课时 | 0人学习

Apache Subversion 官方手册
Apache Subversion 官方手册

共0课时 | 0人学习