2011-09-15 84 views
4

我使用String.format方法的Java API來記錄東西。我的方法是這樣的:Java安全String.format和轉義%

public static void log(String message, Object... params){ 
    System.out.println(String.format(message, params)); 
} 

但問題是,如果用戶發送帶有%性格介於它的消息,它會拋出異常。這裏有一個場景:

log("SELECT * FROM my WHERE name like '%six%'"); 

和Java尋找東西來取代%s(沒關係)和%'(糟糕)。我想解決這個問題。因爲那裏沒有params%s將會丟失,%'會導致異常。

一個解決方案可以是message.replace("%", "%%")但我不確定它是否是一個優雅的解決方案。

+1

我不明白爲什麼'%s'將是確定的,如果''%是沒有的。如果他們給你破碎的輸入,他們不能指望工作輸出。只是拋出一個異常。 –

+0

@Christoffer我沒有看到包含SQL'like'子句的消息字符串作爲中斷輸入。 – adarshr

+1

如果字符串同時包含'%s'和'%',並且一個被認爲是OK而另一個不是,那麼輸入被破壞。如果輸入是'String.format()'的格式字符串,並且您不希望'like'語句中的'%s'被參數值替換,則除'%% s'和'% %'在輸入中斷。 –

回答

7

log不知道給定%是否意味着作爲格式說明符或百分號。請看下面的例子:

log("%s%s", "test"); 

那是"test%s""%stest",或錯誤?

因此,這個問題將在調用點加以解決:

log(escape("SELECT * FROM my WHERE name like '%six%'")); 

其中escape()是你需要編寫將與%%替換所有%功能。

或者,下面就可以在調用點使用:

log("%s", "SELECT * FROM my WHERE name like '%six%'"); 
+0

或者,可以從'log()'方法內調用'escape()'方法,使得操作無縫。 – adarshr

+1

@adarshr:那麼使用'String.format()'有什麼意義? –

+0

我使用了最後一種情況,現在我的SQL被記錄爲'log(「%s」,query);'。謝謝。 –

1

爲最有可能的誤用一個簡單的解決方案(使用%s%某處String,但不提供參數)將除你原來的方法提供了一種無PARAMS超載你的方法

public static void log(String message) { 
    System.out.println(message); 
} 

另外,您可以動態地嘗試檢測無PARAMS情況,但是這是一個有點更多的工作:

public static void log(String message, Object... params) { 
    final String output; 
    if (params == null || params.length = 0) { 
    output = message; 
    } else { 
    output = String.format(message, params); 
    } 
    System.out.println(output); 
} 
+0

如果客戶端利用格式化功能並執行諸如'%n'之類的操作,則不起作用。 – aioobe

+0

上述兩種方法是不明確的,因爲第一種方法(使用var args)也會採用長度爲0的參數列表。 –

+0

@aioobe:true,它需要記錄,但我沒有看到真正的理由在這裏使用'%n'而不是'\ n'。 –

0

一種選擇w ^應該將字符串直接傳遞給println,如果params的長度爲0. 另一種選擇是有兩個重載。

public static void log(String message); 
public static void log(String format, String param, String...params); 
+1

我不認爲固定的'參數'是必要的。另外:格式參數可以是'Object',所以'log'也應該接受'Object'。 –

+0

但是您是否覺得它提供了更多的可讀性,因爲在無參數情況下調用哪個超載沒有潛在的困惑? –

+2

這是真的,它更明顯,但它有缺點。例如,如果由於某種原因,我已經有*數組(可能是因爲調用方法本身就是一個變量arity方法):那麼你必須複製數組來調用'log'方法。 –