8

我正在尝试将 UITextView 或 UITextField 的内容作为参数发送到 php 文件

NSString *urlstr = [[NSString alloc] initWithFormat:@"http://server.com/file.php?name=%@&tags=%@&entry=%@",nameField.text, tagsField.text, dreamEntry.text];

当我记录 urlstr 时,只要 UITextView 或 UITextField 不包含空格,url 格式就可以了。我将如何将空格转换为 %20 ?

编辑

这是目前的代码,它不仅崩溃,而且没有正确编码 url。

name=John Doe&tags=recurring nightmare&entry=测试测试测试

被转换为

name=John -1844684964oe&tags=recurringightmare&entry=测试 4.214929e-307sting -1.992836e+00sting

- (IBAction)sendButtonPressed:(id)sender
{

    NSString *urlString = [[NSString alloc] initWithFormat:@"http://server.com/file.php?name=%@&tags=%@&entry=%@", nameField.text, tagsField.text, dreamEntry.text];

    NSString *encodedString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    NSURL *url = [[NSURL alloc] initWithString:encodedString];

    NSLog(encodedString);

    NSLog(urlString);

    [urlString release];
    [url release];
    [encodedString release];


}
4

3 回答 3

20

实际上,所有先前的答案都至少包含一些不准确之处,对于 TextFields 中用户提供的文本的许多常见值,它们无法与服务器正确通信

stringByAddingPercentEscapesUsingEncoding:percent 转义所有不是有效 URL 字符的字符。此方法应该对整个 URL 应用一次。

先前的答案声称它的stringByAddingPercentEscapesUsingEncoding:工作方式类似于许多脚本语言中的 URL 构建类,您不应将其应用于整个 URL 字符串,但事实并非如此。&任何人都可以通过检查其输出中未转义的 s 和s来轻松验证这一点?。因此,适用于整个字符串是可以的,但仅适用于您的“动态”url 内容是不够的。

前面的答案是正确的,因为您必须对进入 CGI 查询字符串的名称和值做更多的工作。由于 CGI 由 RFC3875 指定,这通常称为 RFC3875 百分比转义。它确保您的名称和值不包含有效的 URL 字符但在 URL 的其他部分很重要的字符(;?:@&=$+{}<>,

然而,完成对整个字符串执行纯 URL 百分比转义以确保字符串中的所有字符都是有效的 URL 字符也是非常重要的。虽然您的示例中没有,但通常字符串的“静态”部分中可能存在无效 URL 字符的字符,因此您也需要转义这些字符。

不幸的是,NSString它没有给我们逃避 RFC3875 重要字符的能力,所以我们必须深入研究CFString这样做。显然使用CFString是一种痛苦,所以我通常会像这样添加Category一个NSString

@interface NSString (RFC3875)
- (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding;
@end

@implementation NSString (RFC3875)
- (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding {
    CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(encoding);
    NSString *rfcEscaped = (NSString *)CFURLCreateStringByAddingPercentEscapes(
                                                NULL, 
                                                (CFStringRef)self,
                                                NULL, 
                                                (CFStringRef)@";/?:@&=$+{}<>,",
                                                cfEncoding);
    return [rfcEscaped autorelease];
}
@end

有了这个Category,原始问题可以通过以下方式正确解决:

NSString *urlEscapedBase = [@"http://server.com/file.php" stringByAddingPercentEscapesUsingEncoding:
                                            NSUTF8StringEncoding];
NSString *rfcEscapedName = [nameField.text stringByAddingRFC3875PercentEscapesUsingEncoding:
                                                NSUTF8StringEncoding];
NSString *rfcEscapedTags = [tagsField.text stringByAddingRFC3875PercentEscapesUsingEncoding:
                                                NSUTF8StringEncoding];
NSString *rfcEscapedEntry = [dreamEntry.text stringByAddingRFC3875PercentEscapesUsingEncoding:
                                                NSUTF8StringEncoding];

NSString *urlStr = [NSString stringWithFormat:@"%@?name=%@&tags=%@&entry=%@",
                                urlEscapedBase,
                                rfcEscapedName,
                                rfcEscapedTags,
                                rfcEscapedEntry];

NSURL *url = [NSURL URLWithString:urlStr];

这有点变重,只是更清楚。另请注意,提供给的变量列表stringWithFormat:不应nil终止。格式字符串描述了应该跟随它的变量的精确数量。此外,从技术上讲,查询字符串名称(名称、标签、条目等)的字符串应该stringByAddingPercentEscapesUsingEncoding:理所当然地运行,但在这个小示例中,我们可以很容易地看到它们不包含无效的 URL 字符。

要了解前面的解决方案为什么不正确,假设用户输入的文本dreamEntry.text包含一个&,这并非不可能。使用以前的解决方案,当服务器获取该文本时,该字符后面的所有文本都将丢失,因为未转义的 & 符号将被服务器解释为该查询字符串对的值部分的结尾。

于 2010-11-10T00:34:27.683 回答
14

您不应该对整个字符串进行 URL 转义,而应该对动态组件进行 URL 转义。尝试

NSString *urlStr = [NSString stringWithFormat:@"http://server.com/file.php?name=%@&tags=%@&entry=%@",
                        [nameField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
                        [tagsField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
                        [dreamEntry.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
                        nil];
NSURL *url = [NSURL URLWithString:urlStr];

您的代码的第二个问题(无疑是奇怪打印的原因)是您将字符串直接传递给 NSLog,因此它被视为格式字符串。你需要使用

NSLog(@"%@", encodedString);

反而。这将使它按预期打印。

编辑:您的代码的第三个问题是您混合了自动释放和拥有的对象,然后在最后释放它们。去看看你创建的 3 个对象,稍后你会发布它们。其中一个不应在以后发布,因为它是由不以 alloc、copy 或 new 开头的方法生成的。识别有问题的对象是留给读者的练习。

于 2009-05-27T19:41:31.477 回答
0

您可以获取您的 URL 并使用:

NSString *urlStr = [[NSString alloc] initWithFormat:@"http://server.com/file.php?name=%@&tags=%@&entry=%@",nameField.text, tagsField.text, dreamEntry.text];

NSString *encStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
于 2009-05-27T18:59:02.157 回答