iphone html objective-c cocoa-touch escaping

iphone - Objetivo C HTML escape/unescape



objective-c cocoa-touch (14)

Esta es una respuesta antigua que publiqué hace algunos años. Mi intención no era proporcionar una solución "buena" y "respetable", sino una solución "hacky" que podría ser útil en algunas circunstancias. Por favor, no use esta solución a menos que nada más funcione.

En realidad, funciona perfectamente bien en muchas situaciones que otras respuestas no, porque UIWebView está haciendo todo el trabajo. E incluso puedes insertar algo de javascript (que puede ser peligroso y / o útil). El rendimiento debería ser horrible, pero en realidad no es tan malo.

Hay otra solución que debe mencionarse. Simplemente crea un UIWebView , carga la cadena codificada y recupera el texto. Se escapa de las etiquetas "<>", y también decodifica todas las entidades html (por ejemplo, "& gt;") y podría funcionar donde otras no (por ejemplo, utilizando cirílico). No creo que sea la mejor solución, pero puede ser útil si las soluciones anteriores no funcionan.

Aquí hay un pequeño ejemplo usando ARC:

@interface YourClass() <UIWebViewDelegate> @property UIWebView *webView; @end @implementation YourClass - (void)someMethodWhereYouGetTheHtmlString:(NSString *)htmlString { self.webView = [[UIWebView alloc] init]; NSString *htmlString = [NSString stringWithFormat:@"<html><body>%@</body></html>", self.description]; [self.webView loadHTMLString:htmlString baseURL:nil]; self.webView.delegate = self; } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { self.webView = nil; } - (void)webViewDidFinishLoad:(UIWebView *)webView { self.webView = nil; NSString *escapedString = [self.webView stringByEvaluatingJavaScriptFromString:@"document.body.textContent;"]; } - (void)webViewDidStartLoad:(UIWebView *)webView { // Do Nothing } @end

Preguntándose si existe una manera fácil de hacer un simple escape / unescape HTML en el Objetivo C. Lo que quiero es algo como este código psuedo:

NSString *string = @"&lt;span&gt;Foo&lt;/span&gt;"; [string stringByUnescapingHTML];

Que devuelve

<span>Foo</span>

Es de esperar que destape todas las demás entidades HTML e incluso códigos ASCII como Ӓ y similares.

¿Hay algún método en Cocoa Touch / UIKit para hacer esto?


¿Por qué no solo usar?

NSData *data = [s dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; NSString *result = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; return result;

Pregunta nova pero en mi caso funciona ...


Aquí hay una solución que neutraliza todos los caracteres (al convertirlos en todas las entidades codificadas en HTML por su valor Unicode) ... Usé esto para mi necesidad (asegurándome de que una cadena que venía del usuario pero que estaba dentro de una vista web no podía tener ninguna Ataques XSS):

Interfaz:

@interface NSString (escape) - (NSString*)stringByEncodingHTMLEntities; @end

Implementación:

@implementation NSString (escape) - (NSString*)stringByEncodingHTMLEntities { // Rather then mapping each individual entity and checking if it needs to be replaced, we simply replace every character with the hex entity NSMutableString *resultString = [NSMutableString string]; for(int pos = 0; pos<[self length]; pos++) [resultString appendFormat:@"&#x%x;",[self characterAtIndex:pos]]; return [NSString stringWithString:resultString]; } @end

Ejemplo de uso:

UIWebView *webView = [[UIWebView alloc] init]; NSString *userInput = @"<script>alert(''This is an XSS ATTACK!'');</script>"; NSString *safeInput = [userInput stringByEncodingHTMLEntities]; [webView loadHTMLString:safeInput baseURL:nil];

Su kilometraje variará.



En iOS 7 puede usar la capacidad de NSAttributedString para importar HTML para convertir entidades HTML a un NSString.

P.ej:

@interface NSAttributedString (HTML) + (instancetype)attributedStringWithHTMLString:(NSString *)htmlString; @end @implementation NSAttributedString (HTML) + (instancetype)attributedStringWithHTMLString:(NSString *)htmlString { NSDictionary *options = @{ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute :@(NSUTF8StringEncoding) }; NSData *data = [htmlString dataUsingEncoding:NSUTF8StringEncoding]; return [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil]; } @end

Luego, en tu código cuando quieras limpiar las entidades:

NSString *cleanString = [[NSAttributedString attributedStringWithHTMLString:question.title] string];

Esta es probablemente la forma más simple, pero no sé qué tan eficiente es. Probablemente deberías estar bastante seguro de que el contenido de tu "limpieza" no contiene ninguna etiqueta <img> o cosas por el estilo porque este método descargará esas imágenes durante la conversión de HTML a NSAttributedString. :)


Esta es una implementación de categoría NSString fácil de usar:

No está completo, pero puede agregar algunas entidades que faltan desde aquí: http://code.google.com/p/statz/source/browse/trunk/NSString%2BHTML.m

Uso:

#import "NSString+HTML.h" NSString *raw = [NSString stringWithFormat:@"<div></div>"]; NSString *escaped = [raw htmlEscapedString];


Esta es una solución increíblemente pirateada que hice, pero si quieres simplemente escapar de una cadena sin preocuparte por el análisis, haz esto:

-(NSString *)htmlEntityDecode:(NSString *)string { string = [string stringByReplacingOccurrencesOfString:@"&quot;" withString:@"/""]; string = [string stringByReplacingOccurrencesOfString:@"&apos;" withString:@"''"]; string = [string stringByReplacingOccurrencesOfString:@"&lt;" withString:@"<"]; string = [string stringByReplacingOccurrencesOfString:@"&gt;" withString:@">"]; string = [string stringByReplacingOccurrencesOfString:@"&amp;" withString:@"&"]; // Do this last so that, e.g. @"&amp;lt;" goes to @"&lt;" not @"<" return string; }

Sé que de ninguna manera es elegante, pero hace el trabajo bien. A continuación, puede decodificar un elemento llamando:

string = [self htmlEntityDecode:string];

Como dije, es raro pero funciona. SI desea codificar una cadena, simplemente invierta los parámetros stringByReplacingOccurencesOfString.


Esta solución más fácil es crear una categoría de la siguiente manera:

Aquí está el archivo de encabezado de la categoría:

#import <Foundation/Foundation.h> @interface NSString (URLEncoding) -(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding; @end

Y aquí está la implementación:

#import "NSString+URLEncoding.h" @implementation NSString (URLEncoding) -(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding { return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)self, NULL, (CFStringRef)@"!*''/"();:@&=+$,/?%#[]% ", CFStringConvertNSStringEncodingToEncoding(encoding)); } @end

Y ahora podemos simplemente hacer esto:

NSString *raw = @"hell & brimstone + earthly/delight"; NSString *url = [NSString stringWithFormat:@"http://example.com/example?param=%@", [raw urlEncodeUsingEncoding:NSUTF8Encoding]]; NSLog(url);

Los créditos para esta respuesta van al siguiente sitio web:

http://madebymany.com/blog/url-encoding-an-nsstring-on-ios


Este link contiene la solución a continuación. Cocoa CF tiene la función CFXMLCreateStringByUnescapingEntities, pero eso no está disponible en el iPhone.

@interface MREntitiesConverter : NSObject <NSXMLParserDelegate>{ NSMutableString* resultString; } @property (nonatomic, retain) NSMutableString* resultString; - (NSString*)convertEntitiesInString:(NSString*)s; @end @implementation MREntitiesConverter @synthesize resultString; - (id)init { if([super init]) { resultString = [[NSMutableString alloc] init]; } return self; } - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)s { [self.resultString appendString:s]; } - (NSString*)convertEntitiesInString:(NSString*)s { if (!s) { NSLog(@"ERROR : Parameter string is nil"); } NSString* xmlStr = [NSString stringWithFormat:@"<d>%@</d>", s]; NSData *data = [xmlStr dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; NSXMLParser* xmlParse = [[[NSXMLParser alloc] initWithData:data] autorelease]; [xmlParse setDelegate:self]; [xmlParse parse]; return [NSString stringWithFormat:@"%@",resultString]; } - (void)dealloc { [resultString release]; [super dealloc]; } @end


La forma menos invasiva y más ligera de codificar y decodificar cadenas HTML o XML es usar GTMNSStringHTMLAdditions CocoaPod .

Es simplemente la categoría GTMNSString+HTML Google Toolbox para Mac NSString, despojado de la dependencia de GTMDefines.h . Entonces, todo lo que necesita agregar es una .hy una .m, y está listo para comenzar.

Ejemplo:

#import "GTMNSString+HTML.h" // Encoding a string with XML / HTML elements NSString *stringToEncode = @"<TheBeat>Goes On</TheBeat>"; NSString *encodedString = [stringToEncode gtm_stringByEscapingForHTML]; // encodedString looks like this now: // &lt;TheBeat&gt;Goes On&lt;/TheBeat&gt; // Decoding a string with XML / HTML encoded elements NSString *stringToDecode = @"&lt;TheBeat&gt;Goes On&lt;/TheBeat&gt;"; NSString *decodedString = [stringToDecode gtm_stringByUnescapingFromHTML]; // decodedString looks like this now: // <TheBeat>Goes On</TheBeat>



Mira mi categoría de NSString para XMLEntidades . Hay métodos para decodificar entidades XML (incluidas todas las referencias de caracteres HTML), codificar entidades XML, eliminar etiquetas y eliminar líneas nuevas y espacios en blanco de una cadena:

- (NSString *)stringByStrippingTags; - (NSString *)stringByDecodingXMLEntities; // Including all HTML character references - (NSString *)stringByEncodingXMLEntities; - (NSString *)stringWithNewLinesAsBRs; - (NSString *)stringByRemovingNewLinesAndWhitespace;


Otra categoría HTML NSString de Google Toolbox para Mac
A pesar del nombre, esto también funciona en iOS.

http://google-toolbox-for-mac.googlecode.com/svn/trunk/Foundation/GTMNSString+HTML.h

/// Get a string where internal characters that are escaped for HTML are unescaped // /// For example, ''&amp;'' becomes ''&'' /// Handles &#32; and &#x32; cases as well /// // Returns: // Autoreleased NSString // - (NSString *)gtm_stringByUnescapingFromHTML;

Y tuve que incluir solo tres archivos en el proyecto: encabezado, implementación y GTMDefines.h .