Кодирование пробелов в формате UITextView/UITextField в URL

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

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

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

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

вот код в настоящее время, который не только дает сбой, но и не кодирует URL-адрес должным образом.

name=Джон Доу&tags=повторяющийся кошмар&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];


}

person bcsantos    schedule 27.05.2009    source источник


Ответы (3)


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

person Lily Ballard    schedule 27.05.2009

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

stringByAddingPercentEscapesUsingEncoding: процент экранирует все символы, которые не являются допустимыми символами URL. Этот метод следует применить один раз ко всему URL-адресу.

В предыдущем ответе утверждается, что stringByAddingPercentEscapesUsingEncoding: работает как классы построения URL-адресов на многих языках сценариев, где вы не должны применять его ко всей строке URL-адреса, но это не так. Любой может легко убедиться в этом, проверив вывод на наличие неэкранированных символов & и ?. Таким образом, можно применить ко всей строке, но недостаточно применить к вашему «динамическому» содержимому 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 содержит &, что вполне вероятно. В предыдущих решениях весь текст, следующий за этим символом, будет потерян к тому времени, когда сервер получит этот текст, поскольку неэкранированный амперсанд будет интерпретирован сервером как окончание части значения этой пары строк запроса.

person barrycburton    schedule 10.11.2010
comment
слава. В настоящее время правильный ответ, как мы все видим, слишком неверен. однако при использовании этого для экранирования значений параметров, отправляемых в приложение Twitter, результаты искажаются (на самом деле просто набор символов %). Если это проблема с декодированием от имени клиента Twitter или нет, я не знаю. Однако он работает с другим решением, использующим CFURLCreateStringByAddingPercentEscapes(). Я получил это решение отсюда: wiki.akosma.com/ - person Jonny; 19.11.2010
comment
Реализация категории, которую я предоставил, практически идентична решению, на которое вы ссылаетесь (оно также использует CFURLCreateStringByAddingPercentEscapes() для тяжелой работы. Основное отличие состоит в том, что решение не упаковано аккуратно). Если у вас возникла проблема с категорией выше, я подозреваю, что вы применяли как stringByAddingRFC3875PercentEscapesUsingEncoding(), так и обычную NSString stringByAddingPercentEscapesUsingEncoding() к одной и той же строке, что плохо, поскольку экранирование URL не является идемпотентным, поэтому вы начинаете экранировать экранирование ( например, %20 становится %2520). - person barrycburton; 24.11.2010
comment
На самом деле это решение почти правильное. А именно, вызов [self stringByAddingPercentEscapesUsingEncoding:encoding] не нужен, так как CFURLCreateStringByAddingPercentEscapes() уже сделает это за вас. Таким образом, метод становится следующим: - (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding { CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(encoding); NSString *rfcEscaped = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,(CFStringRef)self, NULL, (CFStringRef)@;/?:@&=$+{}‹›,, cfEncoding); return [rfcEscaped autorelease]; } - person lensovet; 17.12.2010

Вы можете взять свой 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];
person Heat Miser    schedule 27.05.2009