2011-03-22 10 views
7

EDITAR DE NUEVO: No quiero crear otra pregunta, por lo que pregunta aquí. Tengo la misma situación. Pero esta vez necesito el algo en lenguaje C. Alguien puede ayudarme.¿Cómo se genera el Id. De pedido único (solo para mostrar al usuario) con el Id del pedido real?

Tengo la siguiente tabla.

CREATE TABLE IF NOT EXISTS `j741_order` (
    `order_id` int(11) NOT NULL AUTO_INCREMENT, 
    `buyer_id` int(11) NOT NULL, 
    `subtotal` decimal(15,5) DEFAULT '0.00000', 
    `discount` decimal(15,5) NOT NULL DEFAULT '0.00000', 
    `shipping` decimal(15,5) DEFAULT '0.00000', 
    `tax` decimal(15,5) DEFAULT '0.00000', 
    `total` decimal(15,5) NOT NULL DEFAULT '0.00000', 
    `currency` char(3) DEFAULT NULL, 
    `status` int(11) NOT NULL DEFAULT '0', 
    `created_date` datetime NOT NULL, 
    `modified_date` datetime NOT NULL, 
    PRIMARY KEY (`order_id`), 
    KEY `idx_buyer_id` (`buyer_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 

Quiero generar una identificación de la orden único, (sólo para mostrar para el usuario) para que el usuario no puede adivinar lo que va a ser el próximo ID del pedido.

¿Cómo puedo conseguir que el único orden aleatorio Id del orden original Si

y volver orden original de identificación de que orden aleatorio Id?

EDIT: No quiero crear ningún otro campo.

+1

Si un usuario dado es solamente capaz de ver sus pedidos, luego adivinar el siguiente OrderId no debería ser un problema. Si todos los pedidos son públicos, entonces sería mejor, desde una perspectiva de rendimiento, mantenimiento y esfuerzo, simplemente agregar una columna única que tome un valor aleatorio o al menos agregue una tabla de asignación de valores aleatorios a OrderIds. ¿Por qué la solución más simple y obvia no está sobre la mesa? – Thomas

+1

Su edición ha cambiado sustancialmente la pregunta. Si tiene problemas para implementar el algoritmo en otro idioma, debe publicar una pregunta al respecto, con cualquier progreso que haya realizado. –

Respuesta

9

Si sus requisitos son:

  • Debe ser reversible (es decir dado simplemente el ID "al azar", se puede encontrar la order_id el original)
  • No hay columnas adicionales
  • Usted no quieren mostrar order_id/interna original al usuario en todo

entonces Recomendaría algún tipo de encriptación bidireccional. Hashing no funcionará ya que no puede encontrar el valor original de un hash.

También estoy agregando que debe ser amigable para los hombres, por ejemplo. alguien puede llamarlo por teléfono

Voy a utilizar una clase de encriptación bidireccional muy simple ubicada here, que fue escrita por Tony Marston.

Queremos que la solución sea humana, así que eliminemos algunos de los caracteres. Solo he dejado caracteres en mayúsculas, números y símbolos de espacio y guión. Todos estos pueden comunicarse fácilmente usando el alfabeto fonético estándar, y el uso forzado de mayúsculas elimina cualquier confusión sobre qué es un personaje.

Estas son las cadenas revueltos que he utilizado (utilicé this online word scrambler lugar de tratar de trepar la cuerda yo):

$this->scramble1 = '-ABCDEFGHIJKLMNOPQRSTUVWXYZ '; 
    $this->scramble2 = 'UKAH652LMOQ FBDIEG03JT17N4C89XPV-WRSYZ'; 

Así que el código para crear nuestra orden humano de usar la identificación es:

<?php 

include 'encryption_class.php'; 

$crypt = new encryption_class(); 

$key = "A-COMPLETELY-RANDOM-KEY-THAT-I-HAVE-USED"; 
// Min length of 8 for encrypted string 
$min_length = 8; 

$order_id = 123456789; 

print "Original: " . $order_id . PHP_EOL; 

$encrypt_result = $crypt->encrypt($key, $order_id, $min_length); 

print "Encrypted: " . $encrypt_result . PHP_EOL; 

// DECRYPT 
$decrypt_result = $crypt->decrypt($key, $encrypt_result); 

print "Decrypted: " . $decrypt_result . PHP_EOL; 

?> 

(Debe descargar y guardar el archivo * encryption_class * localmente e incluirlo).

me corrieron de que el código de la línea de comandos y recibió el siguiente resultado:

Original: 123456789 
Encrypted: 2UD5UIK9S 
Decrypted: 123456789 

Ahora tenemos nuestra corta, order_id humana de usar, que puede ser utilizado en un enlace como http://myapp.example.com/order/view/2UD5UIK9S, y que nunca necesita mostrar o comunicar el order_id interno a sus usuarios.

Notas:

El código encriptado será único una vez que su order_id es única (ya que es un PK será)

Esto no debe ser utilizado como una rutina de cifrado/descifrado contraseña - no almacene contraseñas, almacenar hashes.

Asegúrese de que su clave secreta sea aleatoria, compleja y contenga solo los caracteres en las variables $ scramble.

Ofusca solo el order_id.

Editar:

Aunque el relleno de la cadena de entrada (order_id) genera una cierta cantidad de ramdomness, se podría combinar esto con la respuesta de @ biakaveron para crear una URL como http://myapp.example.com/order/view/5cc46aea44e898c3b4e1303eb18d8161302cd367/2UD5UIK9S

+0

gracias. Pero respondiste después de recompensar generosidad. – Gaurav

+0

Es realmente útil. Lamento que no haya otra opción o revertir la recompensa otorgada. – Gaurav

+0

¿Conoces algo similar en C – Gaurav

2

En primer lugar, usted debe mantener su order_id como un identificador físico en su base de datos: el campo es un entero, funciona bien (el código está diseñado para utilizar eso - y los números enteros da un mejor rendimiento que teclas de cadena).

Pero se puede agregar otro campo que actuaría como un identificador para el usuario:

  • Un campo varchar(something) o char(something), que se pueden conseguir una mejor pantalla y sería más difícil de adivinar,
  • sería mostrará al usuario,
  • habría un índice de UNIQUE en él,
  • pero sería h no tiene ningún significado técnico para su código.


Un GUID podría ser una buena idea - pero tengo la Fealing que podría ser un poco demasiado largo ...

¿Qué pasa algo basado en la primera letra del nombre del usuario, la fecha y algún numero al azar?
Sería difícil de adivinar, y aún tiene un poco de significado para el usuario ...

Por supuesto, no podrá calcular el order_id desde ese identificador de cadena, pero si ese es único , una simple consulta y obtendrá order_id vuelta:

select order_id from your_table where nice_looking_id = '...'; 
+0

No quiero agregar otra columna a mi tabla. – Gaurav

+0

@Gaurav: Y no hay otra forma de hacerlo de manera eficiente sin la columna de tabla buena suerte –

+0

@Gaurav deberías: mantener la clave primaria entera es buena desde el punto de vista técnico. –

0

puede eludir un poco, pero lo recomiendo totalmente la adición de otra columna. Así es como lo haría con PHP.

// do your insert 

// Retrieve last insert id 
$orderId = mysql_insert_id(); 

// get the current timestamp 
$time = time(); 

// Intersperse the $orderId into the $time to get a new "hash" 
$orderId = explode("", (string)$orderId); 
$time = explode("", (string)$time); 

$orderIdLength = sizeof($orderId); 
$newOrderId = ""; 
for ($i = 0; $i < $orderIdLength; ++$i) { 
    $newOrderId .= $orderId[$i] . $time[$i]; 
} 
$newOrderId = (int)$newOrderId; 

lo tanto, si su pedido ID real es 489, y la fecha y hora actual es 1300778794, se llega a un número de pedido que se parece a 418.390.Si su cliente, entonces utiliza esa identificación de la orden para cualquier cosa, simplemente tiene que romper de nuevo hacia abajo:

$newOrderId = explode("", (string)$newOrderId); 
$length = sizeof($newOrderId); 
$oldOrderId = ""; 
for ($i = 0; $i < $length; $i = $i + 2) { 
    $oldOrderId .= $newOrderId[$i]; 
} 
$oldOrderId = (int)$oldOrderId; 

Esto no es un enfoque muy sofisticado y no es 100% a prueba de tontos. Pero por el bien de ofuscar suavemente los identificadores de sus pedidos, creo que hace el trabajo lo suficiente.

Editar: al igual que una rápida lado, se puede utilizar algún otro método de generación de un número semi-aleatoria para rellenar el id que no sea time(). Por ejemplo, puede hacer rand(pow(10, log10($orderId)), pow(10, log10($orderId)+1)), que siempre devolverá algún número aleatorio que tenga la misma longitud que el ID de pedido.

+0

Esta solución no es realmente fácil de usar, ya que la identificación del pedido emitido será diferente cada vez que cambie el valor del tiempo(). Aunque computacionalmente es posible revertir la ofuscación, confundirá al usuario, si la identificación del pedido cambia constantemente. – Riimu

+0

@Rinuwise: luego use UNIX_TIMESTAMP ('created_date').Por alguna razón, imaginé que estaba generando una identificación de pedido para una factura impresa que solo se entregaría una vez. No tengo idea de por qué pensé esto. :) –

9
  1. Crea tu clave secreta (cualquier cadena) y guárdala en tus archivos de configuración (o configuración DB).
  2. Crear ID único: $newId = hash_hmac('sha1', $orderId, $secret_key).'-'.$orderId;. Por lo tanto, sus páginas de pedidos se verán como http://example.com/order/show/123456...absdef-123.
  3. Usted puede obtener de forma rápida identificación de la orden original y comprobar que:
list($hash, $original) = explode($newId, '-', 2); 
if (hash_hmac('sha1', $original, $secret_key).'-'.$original === $hash) 
{ 
    // its a correct ID 
} 
else 
{ 
    // wrong hash, ignore it! 
} 

De esta manera ID original es pública, pero el usuario no puede volver a colocarlo en la dirección del sitio debido cadena hash desconocido (primera parte de identificación única).

+0

También puede agregar datos específicos del usuario como USER-AGENT a $ secret_key, por lo que el enlace generado no funcionará en otra computadora. – biakaveron

+4

+1 para usar un HMAC de modo que, incluso si el usuario adivina el siguiente orden ** y ** del método hash, no puede generar el código opaco y enmascarar la solicitud de otro orderId. Gran respuesta. – paracycle

+0

gracias. Es realmente útil. – Gaurav

0

Otro método realmente simple es codificar base64 el OrderID. Usted pasa la ID codificada en base64 al cliente en lugar de la ID real y luego decodifica la ID cuando vuelve. Recomendaría eliminar los signos iguales del final de la cadena codificada.

Las ventajas:

  • realmente fácil y rápido de ofuscación de la ID real

Desventajas:

  • Hay que recordar decodificarlo
  • Un usuario inteligente lo calcularía fácilmente cabo
+0

Vota con placer, pero di por qué por favor. Especialmente dado que esta solución, por mala que sea, sí cumple con los requisitos de la pregunta. –

+0

Havent vote por su respuesta, pero base64 no es seguro, porque el usuario avanzado puede calcular el valor codificado para cada OrderID y (probablemente) acceder a él. – biakaveron

0

$ original_id = [whatever];

$salt = [very big private number/string/value]; 

$checksum = hexdec(substr(md5($original_id . $salt)), 0, 4); // Generate 16 bit checksum 

while(strlen($checksum) < 5)  // make sure it's five digits long 
    $checksum = "0" . $checksum; 

$user_facing_id = $checksum . $original_id; // Prepend original with checksum 

Puede obtener el identificador original de nuevo con substr ($ user_facing_id, 5), e incluso se puede comprobar si se trata de una identificación de la orden válida sin interrogar la base de datos mediante la comprobación de la igualdad entre dechex (substr ($ user_facing_id, 0 , 5)) y substr (md5 (substr ($ user_facing_id, 5). $ Salt).

0

Como han dicho otros simplemente puede generar un hash de la identificación de la orden con una sal conocida -, mientras que los ordenadores no les importa si el número de pedido es

854bf1176798d77ecaf6b66cbe71a8fc1b0c1847

o

Hay una gran diferencia cuando se trata de wetware.

para que el usuario no pueda adivinar cuál será el siguiente ID de pedido.

¿Qué estás tratando de evitar aquí? Hubiera pensado que lo único que desea es evitar que los usuarios vean pedidos de otras personas, en cuyo caso solo necesita usar la combinación de ID de pedido y el identificador de usuario para seleccionar pedidos.

Ciertamente, el volumen total de pedidos podría considerarse información confidencial, en cuyo caso, basta con utilizar un número de secuencia vinculado a la identificación del usuario. Aunque no indicó explícitamente qué DBMS está utilizando, supongo que es mysql o una derivada basada en el motor, pero lo siguiente también se aplica a la mayoría de los DBMS relacionales:

Si agrega una columna a la tabla que describe a los usuarios con un valor predeterminado de 0, luego puede agregar desencadenantes en la tabla de órdenes para obtener, incrementar y actualizar automáticamente este valor para cada inserción en la tabla de órdenes; es decir, no se requieren cambios en el código en ninguna otra parte excepto para respaldar la referencia de orden 'externa'. Por supuesto que había necesidad de sembrar este valor con el número correspondiente de pedidos ya realizados - algo así como ....

ALTER TABLE buyers ADD COLUMN buy_ref_last INTEGER DEFAULT 0; 
ALTER TABLE orders ADD COLUMN buyer_order_ref INTEGER; 
UPDATE orders o SET buyer_order_ref = (SELECT COUNT(*) 
    FROM orders r WHERE r.buyer_id=o.buyer_id 
    AND r.order_id<o.order_id); 

(nota Sospecho que lo anterior no se ejecutará directamente en MySQL, no lo hace como subselects en la misma mesa como una actualización/eliminar - que necesita para desenrollar la lógica en un procedimiento)

y ....

UPDATE buyers b SET buy_ref_last=(SELECT MAX(buyer_order_ref) 
    FROM orders o WHERE o.buyer_id=b.id); 
Cuestiones relacionadas