Кодирование пробелов в UITextView / UITextField в формат URL - PullRequest
8 голосов
/ 27 мая 2009

Я пытаюсь отправить содержимое UITextView или UITextField в качестве параметров в файл php

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

Когда я регистрирую URL-адрес, формат URL-адреса в порядке, если только UITextView или UITextField не содержат пробелов. Как мне преобразовать пробелы в% 20?

редактировать

здесь представлен код, который не только аварийно завершает работу, но и неправильно кодирует URL-адрес.

name = John Doe & tags = повторяющийся кошмар и запись = тестирование тестирование тестирование

преобразуется в

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];


}

Ответы [ 3 ]

20 голосов
/ 10 ноября 2010

На самом деле, все предыдущие ответы содержат, по крайней мере, некоторые неточности, которые для многих общих значений предоставленного пользователем текста в текстовых полях не будут правильно связываться с сервером

stringByAddingPercentEscapesUsingEncoding: процентов экранирует все символы, которые не являются допустимыми символами 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. Строка формата описывает точное количество переменных, которые должны следовать за ней. Кроме того, технически строки для имен строк запроса (name, tags, entry, ..) должны проходить через stringByAddingPercentEscapesUsingEncoding: как само собой разумеющееся, но в этом небольшом примере мы легко видим, что они не содержат недопустимых символов URL.

Чтобы понять, почему предыдущие решения неверны, представьте, что пользовательский ввод текста в dreamEntry.text содержит &, что не исключено. В предыдущих решениях весь текст, следующий за этим символом, будет потерян к тому времени, когда сервер получит этот текст, поскольку амперсанд без экранирования будет интерпретироваться сервером как завершение части значения этой пары строк запроса.

14 голосов
/ 27 мая 2009

Вы не должны 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. Идентификация рассматриваемого объекта - это упражнение, оставленное читателю.

0 голосов
/ 27 мая 2009

Вы можете взять свой 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];
...