2011-09-02 41 views
2

我試圖做一個非常簡單的短URL重定向沒有數據庫。更快,如果可能的話更少的內存成本方法生成一個字母數字代碼?

這是我到目前爲止有:

<?php 
$name = $_GET['file']; 
$name = preg_replace("/[^A-Za-z0-9]/", '', $name); 
$file = 'data/' . $name; 

// File found 
if (is_file($file)) 
{ 
    // Read the first line, we don't use file_get_contents as the data folder is protected and must be read internally 
    $f = fopen($file, 'r'); 
    $data = fgets($f); 
    fclose($f); 

    // Redirect to the real URL 
    header("Location: $data"); 
} 
else 
{ 
    // What a shame the URL does not exist 
    header("Location: http://www.mydomain.com/"); 
} 

exit(); 
?> 
  • 我想知道這將是更快,如果 可能更少的內存成本的方法來從 6〜8生成的字母數字代碼不會與 數據文件夾中存在的字符相沖突的字符?

回答

1

你是否也有一個要求:對於任何給定的url,必須可以查找它的短代碼?一個只計數的系統會生成唯一的文件名,但當然這不是一個可重複的方法,所以如果同一個url多次出現,每次都會出現不同的密鑰。

如果這是可以接受的,那麼我只是建議一個計數器,可能在36(不區分大小寫的字母數字)或類似的計數器中給出最大的密鑰空間大小。你可以有一個包含當前計數的文件(也可以存儲在內存中,但需要在重新啓動時重新加載),然後你必須小心多線程訪問,同時讀取下一個值。

如果你需要一個給定的url一致的ID,那麼你可以有第二個目錄存儲以url爲基礎的文件(適當轉義),包含你第一次生成的密鑰。當生成新的密鑰時,你可以在這個文件目錄中查找這個url是否已經有一個密鑰,如果它在那裏就返回。

正如你所看到的,這基本上粗略地複製了數據庫的工作方式,兩個目錄基本上都是一個url和key表的索引。

我能想到的唯一方法就是創建一對一的函數,這個函數將保證您正在查看的輸入在特定長度下生成一個字符串。我想不出你會在哪裏找到這樣的功能。壓縮算法是最接近的東西,但它們當然會生成不太可能滿足您需要的輸出(因爲壓縮後的二進制文件可能會與原始字符串一樣大,一旦它已被base64編碼或類似)

哈希函數正如fardjad所建議的那樣,可能會沒問題,但是沒有辦法從哈希值返回到url,並且不能保證兩個輸入是唯一的(儘管它們不是非常小的可能性)。

我懷疑你在實踐中需要fardjad的解決方案將是一樣好,但它取決於如何穩健這就需要將。

最後我應該注意到,我從來沒有寫過或看過很短的網址服務,所以我說的不是專家的建議,只是想如果我沒有做過研究,我會怎麼做。 :)

+0

我不需要將代碼返回到URL號,但我希望它是字母數字的,我不認爲它會使用8個字符的所有組合,這對於內部使用來說是基本的,所以將會有沒有在同一時間創建短網址,它不是一個公開的系統,只有一個人將控制所有簽名的短網址。這主要是爲什麼我正在研究什麼是生成字母數字代碼以便將其與數據目錄中的現有文件名匹配的最快方式,它並不像我最初所說的那樣只是想保持資源 – Guapo

+0

處於最低使用狀態仍然有它儘可能快地處理,最初我們將有總共90000條目。 – Guapo

+1

具有這麼多文件的單個目錄將導致我認爲的性能問題。考慮子目錄或將映射放入文件並將其讀入內存。 – qingbo

1

當我看到它,你想生成用於添加到數據文件夾,這些文件的內容每個新文件的字母數字代碼是要重定向到。

您使用的方法對我來說看起來不錯。只是一些建議:

您可以使用$name MD5哈希到數據文件夾中的文件名,所以你不需要刪除此行非字母字符:

preg_replace("/[^A-Za-z0-9]/", '', $name); 

只是計算哈希取而代之的是文件名:

file_name = md5($name); 

此外文件名也是唯一的。

另一個建議是如果您不想使用數據庫,則使用XML文件來存儲重定向。這可以通過使用SimpleXML輕鬆完成(請看例子)。

+0

'文件名將以這種方式獨一無二 - 我認爲你的意思是文件名幾乎肯定是唯一的,但有一個非常小的機會不是這樣。它可能不會成爲一個問題,但它的價值是明確的。 :) – Chris

+0

'preg_replace(「/ [^ A-Za-z0-9] /」,'',$ name);'只是爲了確保域斜槓是正確的,我希望保持名稱更短最多6到8個字符,所以如果我仍然需要找出如問題中提到的生成每個短代碼的方式,如何將url轉換爲md5會對我有所幫助? – Guapo

+0

@Guapo,當你減小哈希長度時,無論你使用什麼哈希算法,衝突率都會增加,你可以做的是檢查生成的名字是否已經存在,如果有的話生成另一個代碼,或者你可以使用一些像名字一樣的計數器。 – fardjad

1

如果我是正確的,你的粘貼代碼是URL重定向邏輯,而不是文件名的生成,對不對?我建議您使用單線程進程(例如,node.js服務器)來生成並維護max_number值。

每次您需要一個新的文件名時,只需發送一個請求到該服務器。服務器遞增max_number並返回其當前值。然後在您的PHP代碼中,將此整數轉換爲由字母數字字符組成的字符串。 PHP gmp_strval函數可以通過將數字轉換爲base-62形式來完成這項工作。

這種方式是安全的,因爲它以簡單的方式保證絕對的唯一性。我想這是一個常見的方法,許多公共網址較短的服務使用,因爲我注意到他們的字符串自然增加。

當然的gmp_strval功能,可以在自己的代碼很容易實現,如果它不支持您的機器上。這裏的一些例子:How to convert an integer in any base to a string?

較短的是這種服務的更好。但是,如果您確實需要6-8個字符,只需以base-62字符串「100000」(十進制形式的916132832)開頭。

+0

'如果我是正確的,你的粘貼代碼是url重定向邏輯,而不是文件名的生成,對嗎?「是的! 'gmp_strval'似乎是一個有趣的選項,我會試着看看它是如何工作的,如果它在我們擁有的主機中可用的話。 – Guapo

相關問題