在 Informix 4GL 程序中验证 URL

Validate URL in Informix 4GL program

在我的 Informix 4GL 程序中,我有一个输入字段,用户可以在其中插入一个 URL,然后提要会通过脚本发送到 Web。 我如何在输入时验证 URL,以确保它是实时的 link?我可以打个电话看看是否有任何错误吗?

I4GL 检查 URL

没有 built-in 函数可以做到这一点(URL 在发明 I4GL 时不存在等等)。

如果您可以设计一个 C 方法来执行此操作,则可以安排通过 C 接口调用该方法。您将使用本机 C 编写方法,然后使用常规规则编写 I4GL 可调用 C 接口函数。当您使用 I4GL c-code 构建程序时,您也会 link 额外的 C 函数。如果您使用 I4GL-RDS (p-code) 构建程序,您将需要构建一个带有额外函数的自定义 运行ner。所有这些都是 I4GL 的标准技术。

一般来说,您需要的 C 接口代码大致如下所示:

#include <fglsys.h>

// Standard interface for I4GL-callable C functions
extern int i4gl_validate_url(int nargs);

// Using obsolescent interface functions
int i4gl_validate_url(int nargs)
{
    if (nargs != 1)
        fgl_fatal(__FILE__, __LINE__, -1318);
    char url[4096];
    popstring(url, sizeof(url));
    int r = validate_url(url);     // Your C function
    retint(r);
    return 1;
}

您可以而且应该检查 manuals,但是使用 'old style' 函数名的代码应该可以正确编译。可以像这样在 I4GL 中调用代码:

DEFINE url CHAR(256)
DEFINE rc  INTEGER

LET url = "http://www.google.com/"
LET rc = i4gl_validate_url(url)

IF rc != 0 THEN
    ERROR "Invalid URL"
ELSE
    MESSAGE "URL is OK"
END IF

或者按照那些一般路线。您 return 的确切价值观取决于您关于如何 return 从 validate_url() 获得状态的决定。如果需要,您可以从接口函数中 return 多个值(例如错误号和错误消息的文本)。等等。这是关于调用一些 C 代码以从 I4GL 程序中验证 URL 的最简单的可能设计。

现代 C 接口函数

接口库中的函数名称在 00 年代中期都已更改,但旧名称仍然作为宏存在。旧名称是:

  • popstring(char *buffer, int buflen)
  • retint(int retval)
  • fgl_fatal(const char *file, int line, int errnum)

您可以在 IBM Informix 4GL v7.50.xC3: Publication library in PDF in the 4GL Reference Manual 找到修订后的文档,并且您需要附录 C "Using C with IBM Informix 4GL"。

新名字开始ibm_lib4gl_:

  • ibm_libi4gl_popMInt()
  • ibm_libi4gl_popString()

至于错误报告功能,有一个 - 它存在 - 但我无法再访问它的文档。它会在 fglsys.h header 中。它以一个错误号作为一个参数;文件名和行号作为其他参数。据推测,它会是 ibm_lib4gl_… 并且可能会是 Fatalfatal(或者可能是 Errerr)名字。

I4GL 运行ning 一个检查 URL

的脚本

Wouldn't it be easier to write a shell script to get the status code? That might work if I can return the status code or any existing results back to the program into a variable? Can I do that?

很有可能。但是,如果您希望 URL 的内容作为字符串,您最终可能会想要调用 C。当然值得考虑从 I4GL 中调用 shell 脚本是否可行。如果是这样,它将简单得多(RUN "script",IIRC,其中文字字符串可能会被包含命令和 URL 的 built-up 字符串替换。我相信现在 I4GL 中也有文件 I/O 函数,所以如果你能得到写文件的脚本(琐碎的),你就可以从文件中读取数据而不需要自定义 C。很长一段时间以来,你需要自定义 C 来做到这一点。

I just need to validate the URL before storing it into the database. I was thinking about:

#!/bin/bash

read -p "URL to check: " url
if curl --output /dev/null --silent --head --fail "$url"; then
    printf '%s\n' "$url exist"
else
    printf '%s\n' "$url does not exist"
fi

but I just need the output instead of /dev/null to be into a variable. I believe the only option is to dump the output into a temp file and read from there.

不是让 I4GL 运行 代码来验证 URL,而是让 I4GL 运行 脚本来验证 URL。使用脚本的退出状态并将 curl 的输出转储到 /dev/null.

FUNCTION check_url(url)

    DEFINE url VARCHAR(255)
    DEFINE command_line VARCHAR(255)
    DEFINE exit_status  INTEGER

    LET command_line = "check_url ", url
    RUN command_line RETURNING exit_status

    RETURN exit_status

END FUNCTION {check_url}

您的调用代码可以分析 exit_status 以查看它是否有效。值为 0 表示成功; non-zero表示某种问题,可以认为是'URL does not work'.

确保 check_url 脚本 (a) 成功退出时状态为零,失败时状态为 non-zero,并且 (b) 不向标准输出(或标准输出)写入任何内容错误)默认。写入标准错误或输出会搞砸屏幕布局等,您不希望这样。 (显然,您可以为启用标准输出的脚本提供选项,或者您可以调用带有选项的脚本来抑制标准输出和标准错误,或者将输出重定向到 /dev/null;但是,当由 I4GL 程序使用时,它应该是沉默的。)

您的 'script' (check_url) 可以简单为:

#!/bin/bash

exec curl --output /dev/null --silent --head --fail "${1:-http://www.example.com/"

这会将第一个参数传递给 curl,如果没有给出参数,则传递给 non-existent example.com URL,并将其自身替换为 curl,根据需要生成 zero/non-zero 退出状态。您可以在命令行末尾添加 2>/dev/null 以确保看不到错误消息。 (请注意,如果出现任何问题,将很难调试它;请确保您已准备好进行调试。)

exec是一个小的优化;您可以省略它,结果几乎没有差异。 (我可以设计一个可能会发现差异的方案;它涉及向 curl 进程发送信号,不过 — kill -9 9999 或类似的,其中 9999curl 过程——没有实际意义。)

鉴于脚本只是调用另一个程序的一行代码,因此可以将所有这些嵌入到 I4GL 程序中。但是,使用外部 shell 脚本(或 Perl 脚本,或……)具有灵活性的优点;例如,您可以对其进行编辑以记录尝试,而无需更改 I4GL 代码。再来一张e 分发,但更好的灵活性——保留一个单独的脚本,即使它可以全部嵌入到 I4GL 中。

正如乔纳森所说 "URLs didn't exist when I4GL was invented, amongst other things"。您会发现,已经成长为取代 Informix-4gl 的产品(例如 FourJs Genero)将迎合 I4GL 之后发明的新技术和其他事物。

使用 FourJs Genero,在使用您熟悉的 Informix 4gl 语法后,下面的代码将执行您的操作

IMPORT com
MAIN

    -- Should succeed and display 1
    DISPLAY validate_url("http://www.google.com")
    DISPLAY validate_url("http://www.4js.com/online_documentation/fjs-fgl-manual-html/index.html#c_fgl_nf.html") -- link to some of the features added to I4GL by Genero

    -- Should fail and display 0
    DISPLAY validate_url("http://www.google.com/testing")
    DISPLAY validate_url("http://www.google2.com")
END MAIN

FUNCTION validate_url(url)
DEFINE url STRING
DEFINE req com.HttpRequest
DEFINE resp com.HttpResponse

    -- Returns TRUE if http request to a URL returns 200
    TRY
        LET req = com.HttpRequest.create(url)
        CALL req.doRequest()
        LET resp = req.getResponse()
        IF resp.getStatusCode() = 200 THEN
            RETURN TRUE
        END IF
        -- May want to handle other HTTP status codes
    CATCH
        -- May want to capture case if not connected to internet etc
    END TRY
    RETURN FALSE 
END FUNCTION