这份文档描述了 rApache 的安装,配置,多样化用法及支持的软件包。此文档将尽量涵盖关于 rApache 的最新信息。评论和建议请联系 维护者.
rApache 是为了支持 Web 应用开发,结合了 R (统计分析、绘图的语言和操作环境) 以及 Apache Web 服务器软件 的项目。当前版本可运行于 UNIX/Linux 及 Mac OS X 操作系统。现可支持使用线程式多处理模块的 Apache 服务器,但我们仍推荐使用 Apache 的 Prefork 多处理模块 (参阅 Apache 文档中的 多处理模块 一节以了解更多)。
rApache 提供了名为 mod_R 的 Apache 模块,相当于在 Web 服务器中嵌入了 R 语言解释器。同时,rApache 捆绑了 libapreq 这个可使 Apache 处理客户端请求数据的 Apache 模块。二者联合提供的胶合层将 R 转换为了一种服务端脚本环境。
虽未与 rApache 捆绑发布,但 R 包 brew (亦可在 CRAN 下载) 也在服务端脚本执行中起着重要作用。brew 实现了一种模板化的框架,可用于在 R 中自动生成报告。同时也是实时生成 HTML 文件的完美选择。其语法与 PHP / JSP / Ruby 的 erb 模块 / Python 的 psp 模块十分相似。由于 brew 包可以单独安装使用,故其未与 rApache 捆绑发布。
与其他任何服务器端脚本环境无异,rApache 是完全由您 —— 编程者所控制的。如果您允许您编写的 R 代码接受和处理第三方提交的信息,就需要根据情况自行决定是否对客户端所提交信息的安全性进行验证。由此,作者可以断言,rapache 与其他流行的 Web 脚本语言或环境 (PHP, Ruby on Rails 等) 在安全性方面不相上下。
rApache 可使用典型的 GNU/Linux 源代码安装方式进行安装:在 shell 中执行 'configure', 然后执行 'make', 和 'make install' .
目前,rApache 仅提供源代码下载。我曾尝试学习过 Debian 系统的打包方法但仍未完全理解。如果任何人有兴趣为任何 Linux 发行版提供二进制安装包,请 给我发邮件。
安装及使用 rApache 的系统要求如下:
configure 将尽力检测您的系统是否满足以上要求。一旦失败,您应当尝试增加以下参数:
常见参数值的示例:
./configure \ --with-R=/usr/bin/R \ --with-apache2-apxs=/usr/bin/apxs2 \ --with-apreq2-config=/usr/bin/apreq2-config
不带目标参数执行 make 将开始构建 rApache. 执行 'make install' 进行安装。以下为其他可用的 make 目标参数:
作为 root 执行以下命令或在每个命令前使用 sudo:
apt-get install r-base-dev apache2-mpm-prefork apache2-prefork-dev wget http://biostat.mc.vanderbilt.edu/rapache/files/rapache-latest.tar.gz rapachedir=`tar tzf rapache-latest.tar.gz | head -1` tar xzvf rapache-latest.tar.gz cd $rapachedir ./configure make make install
此节详细说明了您需要向 Apache 配置文件中添加的内容。如果您使用编译源代码的方式安装 Apache, 则只需编辑主配置文件 httpd.conf 即可。如果您是以二进制方式安装,可能需要分别修改多个分散的配置文件。所以,在做任何修改之前,请首先了解您的 Apache 配置文件分布情况。
首先使 Apache 加载 mod_R 模块 (必须置于任何 rApache 相关命令之前):
# 所有 Apache 模块均以此方式加载. 请切记 # 字符串 "R_module" 是大小写敏感的, # 在配置文件中请务必正确书写. LoadModule R_module /apache/module/path/mod_R.so
LoadModule 是一个 Apache 指令,用以连接包含 module strucutres 的目标文件。rApache 的 module structure 名为 "R_Module".
注意:
在某些 UNIX 系统上尝试启动 apache2 时,您也许会看到类似下列错误信息:
apache2: Syntax error on line 186 of /etc/apache2/apache2.conf: Cannot load
/usr/lib/apache2/modules/mod_R.so into server: libR.so: cannot open shared
object file: No such file or directory
要解决此问题,我们需要引导您系统的实时连接器(real-time linker),即 ld.so, 寻找到 libR.so 的所在目录。最简单的方法是添加该目录的路径到文件 /etc/ld.so.conf 中,然后以 root 重新执行 ldconfig. 如果您不知道此目录的路径,执行以下命令即可得到:
$ R CMD config --ldflags
-L/usr/lib/R/lib -lR
在上面的输出信息中,/usr/lib/R/lib 即为需要向 /etc/ld.so.conf 中添加的路径。
3.2 ROutputErrors
这条指令的出现意味着 rApache 需要将 R 的出错信息转换为 HTML 代码输出到浏览器中显示,而非写入 Apache 的错误日志。请注意,此举改变了传递给浏览器的 HTTP 响应状态代码。当 Apache 配置文件中含有 ROutputErrors 这条指令时,出错后将返回 200 OK. 否则,出错后将返回 500 INTERNAL_SERVER_ERROR. 示例配置片段如下:
# 将下列语句加入配置文件以将错误信息转换为在浏览器中显示的 HTML. # 否则, 所有警告和错误信息将被写入 Apache 的错误日志. ROutputErrors
第一次配置 rapache 时,不妨添加以下指令来确认整套系统已正常工作。当您访问 /RApacheInfo 时,将看到一份自动生成的关于 R 和 Apache 状态的报告。配置生产环境的主机时,此步骤可略去。
# 生成并输出一份关于 R 在 Apache 中运行状态的报告. <Location /RApacheInfo> SetHandler r-info </Location>点击这里查看一个示例。
这条指令可接受一个字符串型参数:在启动时要执行的 R 语言表达式。在配置文件中可写任意多条此类指令,并根据出现的先后顺序在全局环境 (global environment) 执行。如下所示,适合设置选项或载入 R 包:
# 载入所需的 DBI 包和 RMySQL 包 REvalOnStartup "library(DBI); library(RMySQL)"
使用此指令即可在启动时执行较多的 R 代码。这等价于在全局环境中调用 source() 函数。与 REvalOnStartup 指令类似,此指令可以出现在配置文件的任何位置,且根据出现的顺序依次执行。
# 配置启动时要执行的代码所在的文件 RSourceOnStartup "/var/www/lib/R/startup.R"
由于此节所述内容非常容易引发混乱,所以认真阅读此节是十分必要的。您将学习两条 Apache 指令,两条 rApache 指令,以及两种 SetHandler 选项。
在此使用 Apache 指令 Location 和 Directory 的目的是将 URL、文件路径匹配到 R 处理器 (handler) 上。的确,Apache 的可定制性极强,还存在其他可以更精细地控制 URL 和文件的指令。请参阅 Apache 官方文档 以了解更多信息。
"Location" 用于定义与文件系统中的文件无映射关系的 URL 行为。在 rApache 中,它可以用于调用一个 R 处理器 (handler). 举例来说,假设我们已在 example.com 安装了 rApache, 并且如 3.3 节添加了如下的 "Location" 指令:
<Location /Risneat> SetHandler r-info </Location>
那么,此 URL http://example.com/Risneat 将调用处理器 r-info, 但此 URL 不与文件系统中的任何文件存在映射关系。
"Directory" 用于定义文件系统中与文件有关的行为。在 rApache 中,它可以通过类似于下述的 R 处理器 (handler) 来执行包含 R 语言表达式的文件:
# 位于 /var/www/brew 目录下的所有文件 # 都将被传递给 brew 包中的函数 brew() 进行处理 <Directory /var/www/brew> SetHandler r-script RHandler brew::brew </Directory>
假设站点 example.com 的 Apache 根目录 (DocumentRoot) 为 /var/www/, 那么文件 /var/www/brew/foo.html 映射到的 URL 就为 http://example.com/brew/foo.html, 且将通过 brew 包执行。
r-handler, r-script 和 r-info 均为 Apache 中 SetHandler 指令的可用参数 ("r-info" 在 3.3 节中已作阐释)。调用 SetHandler 将强制通过指定名称的处理器 (handler) 解析相应的 URL.
r-handler 可用于不加参数调用 R 函数。您也可以指定一个特定文件 (见下文)。此参数通常与指令 Location 配合使用。
r-script 使用两个参数调用 R 函数:第一个参数为文件的完整路径,第二个参数用于指定 R 中的环境 (environment)。此参数通常与 Directory 指令配合使用。
使用上述任意一个 SetHandler 指令的参数都要求调用的函数或脚本返回一个合适的 HTTP 响应代码。当此代码的值为 OK 的情况下 (大多数), 将传递给浏览器一个 HTTP 响应代码 200. 若您的函数或脚本想在出错时给出提示,则须返回一个 S3 类 (class) 中的 'try-error' 对象 (关于 'try-error' 类,请参阅 R 语言文档中关于 try 和 tryCatch 的部分)。
RHandler 用以指定一个具体的 R 函数来处理提交的 Web 请求。此 R 函数必须存在于已加载包或 R 的搜索路径中。如同在 R 中一样,您可以在函数名前使用 "::" 以指定其所属包的名称。示例:
# 指定 foo() 为要执行的函数. # 可能由 REvalOnStartup 或 RSourceOnStartup 创建 RHandler foo # 执行位于 foo 包中的 bar() 函数 RHandler foo::bar
RFileHandler 用以指定一个文件和 (或) 函数来处理收到的 Web 请求。使用记号 "::" 来同时指定文件和文件中的函数 (需使用文件的绝对路径)。示例:
# 一个 Hello world 程序. 等价于对每个请求调用 source('/var/www/R/hello.R') RFileHandler /var/www/R/hello.R # 调用 bar.R 中的 foo() 函数 RFileHandler /var/www/R/bar.R::foo
关于 RFileHandler 另外一个注解是,当且仅当其指定的文件的时间戳改变时,文件才会被重新解析。这一特性对调试有相当帮助,一旦代码成熟,您可以将其做成包并使用 RSourceOnStartup 指令来读取,然后作为函数调用,这样做效率更高。
目前最简单的配置实例是 brew 包的例子。在 /var/www/brew 目录下的每个文件均被视为一个 brew 脚本:
# 位于 /var/www/brew 目录下的所有文件都将通过 brew 包中的 brew() 函数处理 <Directory /var/www/brew> SetHandler r-script RHandler brew::brew </Directory>
另一个选择是使用 sys.source:
# 在 /var/www/R-files 目录下的所有文件都将通过函数 sys.source() 执行. <Directory /var/www/R-files> SetHandler r-script RHandler sys.source </Directory>
一个 Hello World 程序,URL 为 /test/helloworld:
# 为所有匹配 /test/helloworld 目录的请求, 包括针对 # /test/helloworld/foobar 目录的请求执行 helloworld.r 中的 R 表达式 <Location /test/helloworld> SetHandler r-handler RFileHandler /path/to/R/scripts/helloworld.r </Location>
以下函数可用于 R 处理器 (handler) 中。
为响应添加 HTTP 响应头 (response header) (RFC2616). 所有的 headers 必须在第一次 print() 或 cat() 的输出前被添加。
示例:
setHeader(header='X-Powered-By',value='rApache')
参数:
返回值:
允许处理器 (handler) 设置请求的 内容类型 (content type). 必须在使用 print() 或 cat() 函数做输出前调用.
示例:
setContentType(type='image/png')
参数:
返回值:
为响应头添加 HTTP Cookies. 最简单的情形, 调用 setCookie(r,'foo','bar') 将赋值 'bar' 给名为 'foo' 的 cookie. 调用 setCookie(r,'foo') 将删除名为 'foo' 的 cookie. 可使用 ... 来附加任何非标准的键值对.
示例:
setCookie(name='sessionID',value=paste(rnorm(1)))
参数:
返回值:
对字符型向量进行百分比式编解码.
示例:
urlEncode(str='hello world@example.com') urlDecode(str='hello+world%40example.com')
参数:
返回值:
输出一份关于 rapache 的报告 (示例). 须为 R 处理器 (handler) 中的唯一调用。等价于使用 "SetHandler r-info".
示例:
RApacheInfo()
参数:
返回值:
向浏览器发送二进制数据. 此函数等价于 R 中的 writeBin() 函数, 但在这里参数 connection 已被忽略. 参阅 R 文档中关于 writeBin() 函数的部分.
示例:
sendBin(object=readBin(t,'raw',n=file.info(t)$size))
参数:
返回值:
决定 rApache 将错误信息输出到浏览器还是输出到 apache 错误日志. 优先级高于作用于整个模块的 apache 配置指令 ROutputErrors. 此函数也可控制发送给请求者的 HTTP 响应代码, 参数 status=TRUE 时为 200, 参数 status=FALSE 时为 500.
示例:
# 将警告和错误转换为 HTML 注释 RApacheOutputErrors(status=TRUE,prefix='<!--\n',suffix='-->\n')
参数:
返回值:
在早期版本的 rApache 中,来自 Web 服务器的信息是作为一个单独的变量传递给 R 处理器 (handler) 的。这种体系设计仿效了其他第三方 apache 模块的普遍做法,但事实证明,这种设计给维护模块的开发者带来了诸多不便。由于 R 支持词法作用域 (lexical scoping) 机制,并拥有在更广意义上灵活操纵语言的能力,所以我们改而实现了另一种更为简明的设计。
和 PHP 变量的名字相似,rApache 变量存在于一个只读列表中,大多数情况下其值为字符型向量。它们已被注入到 R 处理器 (handler) 所在环境中,您编写的 R 代码将根据词法作用域规则来寻找它们。
变量 GET 包含了以 HTTP GET 方式获取的值 (values). 即 URL 中,问号后接的键值对,或当 HTML 表单的 method 属性为 "GET" 时所传递的数据。举例来说,如下表单:
<form method="GET" action="http://example.com/brew/get.html"> <input type="text" name="p1" value="0.95"> <input type="text" name="p2" value="0.7"> <input type="submit" name="Submit"> </form>将生成如下的 GET 变量 (列表型):
> str(GET) List of 3 $ p1 : chr "0.95" $ p2 : chr "0.7" $ Submit: chr "Submit Query"
变量 POST 包含了通过 HTTP POST 方式发送的值。即,当 HTML 表单的 method 属性为 "POST" 时所传递的数据。将上一小节示例中的 method 修改为 "POST" 将生成同样的值。只是此处存入的是 POST 变量:
> str(POST) List of 3 $ p1 : chr "0.95" $ p2 : chr "0.7" $ Submit: chr "Submit Query"
变量 COOKIES 包含了从名为 "Cookie" 的 HTTP 响应头取得的值。它是一个值为字符型向量的列表型变量。参考 setCookie 函数和此链接以了解更多。
变量 FILES 包含了当 HTML 表单的 enctype 属性被设置为 "multipart/form-data" 时,通过表单所上传文件的信息。如下表单:
<form enctype="multipart/form-data" method="POST" action="URL"> <input type="file" name="FirstFile"> <input type="file" name="SecondFile"> <input type="submit" name="Upload">将生成如下 FILES 变量:
> str(FILES) List of 2 $ FirstFile :List of 2 ..$ name : chr "useR2007poster.pdf" ..$ tmp_name: chr "/tmp/apreqc9GlXE" $ SecondFile:List of 2 ..$ name : chr "rapache-1.0.0-useR2007.tar.gz" ..$ tmp_name: chr "/tmp/apreqoQ2hhX"
它是一个由列表组成的列表型变量,以嵌套结构给出了文件的名称 ("name")、缓存文件的文件名 ("tmp_name") 以及缓存文件的所在位置。例如,要引用 input 标签名为 "FirstFile" 的已上传文件,写法即为 FILES$FirstFile$tmp_name. 以下是一段将文件复制到 '/usr/local/uploaded_files' 目录的代码:
destination <- file.path('/usr/local/uploaded_files',FILES$FirstFile$name) file.copy(FILES$FirstFile$tmp_name,destination,overwrite=TRUE)
注意:当 R 处理器 (handler) 处理请求完成后,缓存文件将被自动删除。因此,请切记在 R 处理器 return 之前将缓存文件复制或移动到您想要的位置。
如下列输出所示,SERVER 变量包含了关于传入 Web 请求的丰富信息:
> str(SERVER) List of 30 $ headers_in :List of 9 ..$ Host : chr "localhost:8181" ..$ User-Agent : chr "Mozilla/5.0 (X11; U; Linux i686; en-US; ..." ..$ Accept : chr "text/xml,application/xml,application/x..." ..$ Accept-Language: chr "en-us,en;q=0.5" ..$ Accept-Encoding: chr "gzip,deflate" ..$ Accept-Charset : chr "ISO-8859-1,utf-8;q=0.7,*;q=0.7" ..$ Keep-Alive : chr "300" ..$ Connection : chr "keep-alive" ..$ Cache-Control : chr "max-age=0" $ proto_num : int 1001 $ protocol : chr "HTTP/1.1" $ unparsed_uri : chr "/brew/server.html/beetles/?foo=bar" $ uri : chr "/brew/server.html/beetles/" $ filename : chr "/home/hornerj/rapache/branches/rapache-1-0-br..." $ canonical_filename: chr "/home/hornerj/rapache/branches/rapache-1-0-br..." $ path_info : chr "/beetles/" $ args : chr "foo=bar" $ content_type : chr "text/html" $ handler : chr "r-script" $ content_encoding : NULL $ range : NULL $ hostname : chr "localhost" $ user : NULL $ header_only : logi FALSE $ no_cache : logi FALSE $ no_local_copy : logi FALSE $ assbackwards : logi FALSE $ status : int 200 $ method_number : int 0 $ eos_sent : logi FALSE $ the_request : chr "GET /brew/server.html/beetles/?foo=bar HTTP/1.1" $ method : chr "GET" $ status_line : NULL $ bytes_sent : num 0 $ clength : num 0 $ remaining : num 0 $ read_length : num 0 $ request_time :'POSIXct', format: chr "2007-08-15 11:11:49" $ mtime :'POSIXct', format: chr "1969-12-31 18:00:00"
以下是列表中元素的具体说明:
headers_in 客户端发送的 HTTP 头信息组成的列表.
proto_num 整数型. 协议的版本号; 1.1 = 1001
protocol 字符型. 协议字符串, 如上所示, 或可能为 HTTP/0.9.
unparsed_uri 字符型. 未进行任何解析的 URI.
uri 字符型. URI 的路径部分.
filename 字符型. 含有完整路径信息的文件名.
canonical_filename 字符型. 真正的文件名. 大小写、别名、符号链接已被解析.
path_info 字符型. 当 URL 已被匹配到一个 Web 服务器已知的资源时, URL 的前缀部分. 这里的"资源"指被 Apache 的 Location 指令定义的一个文件或一个 URL.
args 字符型. 从请求中提取的, 以HTTP GET 方式发送的数据.
content_type 字符型. 当前请求的内容类型.
handler 字符型. 用来调用处理器函数 (handler function) 的处理器字符串 (handler string).
content_encoding 字符型. 数据的编码.
range 字符型. 名为 "Range:" 的 HTTP 响应头.
hostname 字符型. 服务器的主机名.
user 字符型. 若进行了 HTTP 认证, 此元素取得用户名.
header_only 逻辑型. HEAD 请求, 与 GET 相对.
no_cache 逻辑型. 此响应不可被缓存.
no_local_copy 逻辑型. 此响应无本地副本.
assbackwards 逻辑型. HTTP/0.9, "简易"型请求 (如 GET /foo\n w/no headers). 开发者发现这是一种不使用头 (header) 进行内部重定向的有效途径.
status 整数型. 状态行.
method_number GET, POST 等方式的整数代表值.
eos_sent 逻辑型. 一个判断流终止存储段 (EOS bucket) 是否已被发送的标志.
the_request 字符型. 请求的第一行.
method 字符型. 请求方式 (如 GET, HEAD, POST 等).
status_line 字符型. 状态行, 如果已被脚本设定.
bytes_sent 数值型. 已发送的字节数.
clength 数值型. "真正的"内容长度.
remaining 数值型. 要从请求体中读取的剩余字节数.
read_length 数值型. 已从请求体中读取的字节数.
request_time POSIXct DateTime 对象. 请求开始的时间.
mtime POSIXct DateTime 对象. 所请求资源的最后修改时间.
下表描述了在 R 处理器 (handler) 环境中以长度为 1 的整数型向量形式存在的变量,以及它们对于 R 处理器 (handler) 正确的返回值。其中包括了 Apache 模块的返回值和 HTTP 状态代码 (参看 RFC2616 中的状态代码定义)。最正常的,同时也是绝大多数处理器 (handler) 将返回的值为 DONE.
名称 | 值 | 描述 |
---|---|---|
DECLINDED | -1 | 模块拒绝处理. |
DONE | -2 | 模块处理响应完毕. |
OK | -0 | 模块已处理此 Apache 响应阶段 (response stage). |
HTTP_CONTINUE | 100 | |
HTTP_SWITCHING_PROTOCOLS | 101 | |
HTTP_PROCESSING | 102 | |
HTTP_OK | 200 | |
HTTP_CREATED | 201 | |
HTTP_ACCEPTED | 202 | |
HTTP_NON_AUTHORITATIVE | 203 | |
HTTP_NO_CONTENT | 204 | |
HTTP_RESET_CONTENT | 205 | |
HTTP_PARTIAL_CONTENT | 206 | |
HTTP_MULTI_STATUS | 207 | |
HTTP_MULTIPLE_CHOICES | 300 | |
HTTP_MOVED_PERMANENTLY | 301 | |
HTTP_MOVED_TEMPORARILY | 302 | |
HTTP_SEE_OTHER | 303 | |
HTTP_NOT_MODIFIED | 304 | |
HTTP_USE_PROXY | 305 | |
HTTP_TEMPORARY_REDIRECT | 307 | |
HTTP_BAD_REQUEST | 400 | |
HTTP_UNAUTHORIZED | 401 | |
HTTP_PAYMENT_REQUIRED | 402 | |
HTTP_FORBIDDEN | 403 | |
HTTP_NOT_FOUND | 404 | |
HTTP_METHOD_NOT_ALLOWED | 405 | |
HTTP_NOT_ACCEPTABLE | 406 | |
HTTP_PROXY_AUTHENTICATION_REQUIRED | 407 | |
HTTP_REQUEST_TIME_OUT | 408 | |
HTTP_CONFLICT | 409 | |
HTTP_GONE | 410 | |
HTTP_LENGTH_REQUIRED | 411 | |
HTTP_PRECONDITION_FAILED | 412 | |
HTTP_REQUEST_ENTITY_TOO_LARGE | 413 | |
HTTP_REQUEST_URI_TOO_LARGE | 414 | |
HTTP_UNSUPPORTED_MEDIA_TYPE | 415 | |
HTTP_RANGE_NOT_SATISFIABLE | 416 | |
HTTP_EXPECTATION_FAILED | 417 | |
HTTP_UNPROCESSABLE_ENTITY | 422 | |
HTTP_LOCKED | 423 | |
HTTP_FAILED_DEPENDENCY | 424 | |
HTTP_UPGRADE_REQUIRED | 426 | |
HTTP_INTERNAL_SERVER_ERROR | 500 | |
HTTP_NOT_IMPLEMENTED | 501 | |
HTTP_BAD_GATEWAY | 502 | |
HTTP_SERVICE_UNAVAILABLE | 503 | |
HTTP_GATEWAY_TIME_OUT | 504 | |
HTTP_VERSION_NOT_SUPPORTED | 505 | |
HTTP_VARIANT_ALSO_VARIES | 506 | |
HTTP_INSUFFICIENT_STORAGE | 507 | |
HTTP_NOT_EXTENDED | 510 |
另一个可能的处理器 (handler) 返回值是一个 S3 中 'try-error' 类的对象.
要查看一个完整的 rApache 应用,请下载 useR2007 会议上的示例程序。 此程序使用了 Hmisc 和 brew 包来进行势和样本量的计算。
下列代码通过对浏览器发送的数据给出回显,实践了 rApache 的全部功能。请复制以下代码并粘贴到一个文件中,然后使用下述选项设置 rApache, 最后使用浏览器访问 http://example.com/rapachetest (请用您自己的主机名替换 example.com).
# # 以下请放入您的 Apache 配置文件. # <Location /rapachetest> SetHandler r-handler RFileHandler /var/www/R/test.R </Location>
# # 复制下列代码到 /var/www/R/test.R 并保存 # hrefify <- function(title) gsub('[\\.()]','_',title,perl=TRUE) scrub <- function(str){ if (is.null(str)) return('NULL') if (length(str) == 0) return('length 0 string') cat("\n<!-- before as.character: (",str,")-->\n",sep='') str <- as.character(str) cat("\n<!-- after as.character: (",str,")-->\n",sep='') str <- gsub('&','&',str); str <- gsub('@','_at_',str); str <- gsub('<','<',str); str <- gsub('>','>',str); if (length(str) == 0 || is.null(str) || str == '') str <- ' ' str } cl<-'e' zebary <- function(i){ cl <<- ifelse(cl=='e','o','e') cat('<tr class="',cl,'"><td>',scrub(i),'</td></tr>\n',sep='') } zeblist <- function(i,l){ cl <<- ifelse(cl=='e','o','e') cat('<tr class="',cl,'"><td class="l">',names(l)[i],'</td><td>') if(is.list(l[[i]])) zebra(names(l)[i],l[[i]]) else { if (length(l[[i]]) > 1) zebary(l[[i]]) else cat(scrub(l[[i]])) } cat('</td></tr>\n',sep='') } zebra <- function(title,l){ cat('<h2><a name="',hrefify(title),'"> </a>',title,'</h2>\n<table><tbody>',sep='') ifelse(is.list(l),lapply(1:length(l),zeblist,l), lapply(l,zebary)) cat('</tbody></table>\n<br/><hr/>') } # Output starts here setContentType("text/html") if(is.null(GET)){ called <- 1 } else { called <- as.integer(GET$called) + 1 } setCookie('called',called,expires=Sys.time()+100) cat('<HTML><head><style type="text/css">\n') cat('table { border: 1px solid #8897be; border-spacing: 0px; font-size: 10pt; }') cat('td { border-bottom:1px solid #d9d9d9; border-left:1px solid #d9d9d9; border-spacing: 0px; padding: 3px 8px; }') cat('td.l { font-weight: bold; width: 10%; }\n') cat('tr.e { background-color: #eeeeee; border-spacing: 0px; }\n') cat('tr.o { background-color: #ffffff; border-spacing: 0px; }\n') cat('</style></head><BODY><H1>Canonical Test for rApache</H1>\n') cat('<form enctype=multipart/form-data method=POST action="?called=',called,'">\n',sep='') cat('Enter a string: <input type=text name=name value=""><br>\n',sep='') cat('Enter another string: <input type=text name=name value=""><br>\n',sep='') cat('Upload a file: <input type=file name=fileUpload><br>\n') cat('Upload another file: <input type=file name=anotherFile><br>\n') cat('<input type=submit name=Submit>') cat("<hr>\n") zebra('CGI GET Data',GET) zebra('CGI POST Data',POST) zebra('Cookies',COOKIES) if (!is.null(FILES)){ cat('<h2>Files Uploaded in POST Data</h2>\n') for (n in names(FILES)){ zebra(paste("Form Variable",n),FILES[[n]]) } } zebra("SERVER Variables",SERVER) cat("</BODY></HTML>\n") DONE
rApache 的源代码使用 Apache License Version 2.0 进行授权。
要引用 rApache,使用:
可供 LaTeX 用户使用的 BibTeX 条目为
@Manual{, title = {rApache: Web application development with R and Apache.}, author = {Jeffrey Horner}, year = {2011}, url = {http://www.rapache.net/}, }
感谢以下同仁的贡献、建议和对问题的反馈。如果我忘记提到您,请发邮件与我联系。
Gregoire Thomas Jan de Leeuw Keven E. Thorpe Jeremy Stephens Aleksander Wawer David Konerding Robert Kofler Jeroen Ooms Michael Driscoll