¡Bienvenido a PHPost!

Para participar en el foro, descargar complementos y acceder al chat, es necesario tener una cuenta activa. Regístrate con un correo válido para completar la activación.

⚖️ Aviso Legal y Normas de Contenido

PHPost.es es una comunidad dedicada al soporte, desarrollo y difusión de software libre para la creación y administración de comunidades en línea.

Compromiso con la legalidad: No se permite la publicación, promoción o distribución de software pirateado, contenido warez ni material que infrinja derechos de autor o cualquier otra normativa aplicable.

Responsabilidad: Cada usuario es responsable del contenido alojado en su propio sitio web y del uso que haga del software. Los administradores y desarrolladores de Risus Nova no controlan ni supervisan los servidores o contenidos gestionados por terceros.

⚠️ Aviso de seguridad

Risus Nova se distribuye únicamente a través de phpost.es, que es la fuente oficial del proyecto donde publicamos las versiones verificadas.

Recomendamos no utilizar copias obtenidas desde sitios de terceros, ya que podrían haber sido modificadas y no contar con la integridad del código original, lo que puede suponer riesgos de seguridad en la instalación.

Para garantizar una instalación segura y actualizada, descarga siempre la versión oficial desde el botón disponible en esta página.

Importante: No pediremos donaciones en ningún momento ni en ninguna plataforma (Ko-fi, PayPal, redes sociales u otras). Si encuentras campañas de donación que utilicen el nombre de Risus Nova o PHPost, no tienen ninguna relación con el proyecto.

🔄 Desarrollo activo

Risus Nova forma parte de una nueva etapa del proyecto PHPost, en evolución constante con mejoras, correcciones y nuevas funciones. Puedes seguir el progreso y los cambios oficiales a través del changelog y la comunidad.

Risus Nova 2.1 Estable Desarrollo activo Última actualización: 14/07/2026 Ver Demo Changelog 263 Desarrollo del tema: 75% (fase actual de desarrollo) Descargar
Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5

RESUELTO Risus Nova 2.1 - Cosas Que eE Visto
#1

2
Mejor respuesta del mensaje Risus Nova 2.1 - Cosas Que eE VistoHola! estoy corriendo Risus Nova v2.1 en un entorno local con PHP 8.2.12 con ayuda de claude code y fuimos encontrando varios bugs? del core. Los reporto acá con la causa y el fix que aplicamos, por si sirve para una próxima actualización. Los divido por categoría.

1. INCOMPATIBILIDADES CON PHP 8.x

- Error 500 al guardar el perfil si se deja un checkbox "Me gustaría" sin marcar: en c.cuenta.php, se accede a $_POST['g_'.$i] sin verificar que exista. Los checkboxes no marcados no viajan en el POST, y en PHP 8.2 pasar null a una función que espera string es un TypeError fatal. Fix: $_POST['g_'.$i] ?? ''.

- Error 500 al guardar "Sitio Web" con una URL válida: se usa la constante FILTER_FLAG_HOST_REQUIRED en filter_var(), eliminada en PHP 8. Fix: sacar ese tercer argumento.

2. URLs/REDIRECCIONES ROTAS EN INSTALACIONES EN SUBDIRECTORIO

- Redirecciones de login (setLevel(), redirectTo() en c.core.php) arman la URL a mano sin anteponer $this->settings['url'], así que en cualquier instalación que NO viva en la raíz del dominio (ej. midominio.com/foro/), termina redirigiendo a midominio.com/login/... (sin el subdirectorio) → 404.

- Botones "Volver al listado" (/admin/news) y "Mover Posts" (/admin/cats) en el panel de admin usan location.href = '/admin/...' hardcodeado en las plantillas, mismo problema.

- Ícono de RSS de "Últimos posts" en el home también hardcodea /rss/ultimos-post sin el prefijo.

3. BUGS DE LÓGICA / FUNCIONES INCOMPLETAS

- /admin/creditos muestra la librería GD como N/A aunque esté instalada y funcionando: el bloque elseif($action=='creditos') de admin.php nunca asigna $smarty->assign("tsVersion", $tsAdmin->getVersions()).

- Selects de país/estado/mes/año vacíos en /cuenta/perfil: el bloque que asigna esos datos en cuenta.php corre con if(empty($action)), pero la ruta real entra con $action='perfil', así que nunca se ejecuta.

- Faltan las provincias/estados de ~80 países en geodata.php (confirmado con República Dominicana, Islandia, Singapur, entre otros): el array $estados[...] simplemente no los tiene cargados.

- Selects "Fumo" y "Tomo alcohol" vacíos (sección "Cómo soy" del perfil): en datos.php solo existe el array combinado fumo_tomo, pero la plantilla busca fumo y alcohol por separado (no existen).

- "Me gustaría" (checkboxes) no se mostraba en el perfil: typo en la plantilla, pide $tsPData.gustaria/$tsPerfil.p_gustaria en vez de .gustos/.p_gustos (el nombre real usado en toda la base de datos y el resto del código).

- /retos/ da "No direct access." y luego error 500: tres bugs apilados. Falta la regla en .htaccess (las páginas hermanas como calendario/misiones/premios sí la tienen), el guard chequea una constante que no existe en ningún lado del código (TSCRIPT en vez de TS_HEADER), y después de rutear bien, llama a $tsCore->setTitle(), un método que no existe en la clase.

- muro.load_atta() (JS del muro) está sin terminar: recibe la URL de la foto/video adjunto al hacer click, pero nunca la usa, reemplaza el elemento clickeado por una imagen vacía o un string vacío, haciendo "desaparecer" la foto/video en vez de mostrarla en grande.

- Avatar GIF animado se queda estático en todo el sitio: imagecreatefromgif() + imagejpeg() de GD solo puede leer/escribir UN cuadro, así que cualquier GIF que pase por el recorte/generación de miniaturas del avatar (c.upload.php) pierde la animación.

- Imagen de fondo de perfil no se aplicaba nunca: typo de tipo MIME en la plantilla, <style type="text/style"> en vez de text/css. Por spec de HTML5 los navegadores ignoran por completo un <style> con type inválido, así que el background-image nunca se veía aunque la URL fuera correcta.

- Portada de perfil no se mostraba en /mi/: el controlador (portal.php) solo carga $tsPerfil condicionalmente (para el aviso de bienvenida a cuentas nuevas), nunca de forma incondicional para el resto de la página.

- Al subir una foto de perfil inválida, el mensaje de error mostraba [object Object] en vez del texto real, porque el callback de éxito solo sabía manejar dos formatos de respuesta distintos y no el de error real del servidor.

- "Subir por URL" para avatar rechazaba links de imagen con ?token=... (típico en CDNs como Discord/Google): la validación de extensión de archivo no ignoraba el query string de la URL.

- Videos de YouTube embebidos en el cuerpo de un post se comportaban raro al hacer click: la función que los convierte en miniatura con botón de play (youtube_lazy_load()) reemplazaba la miniatura por el iframe original en el mismo lugar sin definir un tamaño, y el botón de play usaba una clase CSS sin top/left definidos, quedando flotando lejos de la miniatura.

- El buscador global solo aparecía en páginas de post individual: en la plantilla del header, el include del formulario de búsqueda estaba envuelto en una condición ($tsPage == 'posts' && $tsPost.post_id) sin ninguna razón aparente (el formulario no depende de esas variables).

-  Los botones "Olvidé mi contraseña" / "No me llegó el correo de confirmación" en el login llaman a remind_password()/resend_validation() en el onclick, pero esas funciones JS no existen en ningún archivo, parecen quedar de una función que nunca se implementó.

4. SEGURIDAD

- Inyección SQL en getMyPosts() (c.portal.php): los IDs de categoría guardados (u_portal.last_posts_cats) se concatenan directo en la query con implode() sin sanitizar ni castear a int. Además, si el array de categorías queda con un string vacío adentro, produce IN () (SQL inválido → error 500).

5. CHECKBOXES/RADIOS QUE NO REFLEJAN LA SELECCIÓN REAL (bug clásico de jQuery)

Encontramos este mismo patrón repetido en al menos 3 lugares distintos del código: se usa $(elem).attr('checked') (o .attr('disabled', '')) para leer/cambiar el estado de un checkbox/radio/input después de que el usuario interactúa con él. El problema es que .attr() refleja el atributo HTML original (con el que se renderizó la página), no el estado real después de un click, para eso hace falta .prop().

- Checkboxes de "categorías de interés" en /mi/ (portal.js, save_configs()) no se guardaban nunca, por leer con .attr('checked') en vez de .prop('checked').

- Al suspender a un miembro de una comunidad, el sistema siempre aplicaba "Cambiar rango" en su lugar: en comunidades.js, member_admin_submit() lee .attr('checked') sobre un selector que matchea los dos radios del formulario (mismo name); jQuery devuelve el atributo del primero que encuentra, que queda marcado desde el HTML y nunca se limpia. Resultado: no importa cuál elija el moderador, siempre se interpreta como "Cambiar rango", la suspensión nunca se ejecuta.

- El campo de URL para adjuntar un enlace/foto/video en el muro queda bloqueado para siempre si la primera URL ingresada es inválida: se deshabilita con .attr('disabled', 'true') y se intenta re-habilitar con .attr('disabled', ''), que en HTML sigue siendo un atributo "presente" (=deshabilitado). Solo se soluciona refrescando toda la página.

6. DOBLE-ESCAPADO DE HTML EN LOS ADJUNTOS DEL MURO

- El título de un video de YouTube compartido se guarda con las entidades HTML duplicadas (por ejemplo, un "&" termina guardado como "&" en vez de "&", y una comilla como "'" literal en vez de la comilla real en enlaces compartidos): el título llega desde get_meta_tags() ya con las entidades HTML codificadas una vez (así lo entrega YouTube), y el código lo vuelve a pasar por htmlspecialchars() sin decodificar primero. Encontramos el mismo patrón en foto, enlace y video: ajaxCheck($return=true) ya devuelve los valores escapados, y streamPost() los vuelve a escapar antes del INSERT, doble pasada de escapado sobre el mismo valor.

7. VISTA PREVIA DE ADJUNTOS EN EL MURO NO SE MOSTRABA

- Al adjuntar una foto o un enlace en el composer del muro, después de dar clic en "Adjuntar" la tarjeta de previsualización (imagen + título + descripción) nunca aparecía visualmente, aunque el AJAX funcionara bien. Causa: una regla CSS muy genérica en el tema, #attaContent div{display:none}, oculta cualquier <div> hijo del composer, y el HTML de la tarjeta no traía display seteado explícito para ganarle a esa regla.
============================================================================================
paises que no tienen provincia en el formulario de perfil

anguila, ciudad del vaticano, eslovenia, filipinas, groenlandia, guam, hong kong, isla bouvet, isla de man, isla navidad, islandia, islas caiman, islas cocos, islas cook, islas feroe, islas georgias del sur y sandwich del sur, islas heard y mcdonald, islas marianas del norte, islas marshall, islas pitcairn, islas salomon, islas turcas y caicos, islas virgenes britanicas, islas virgenes estadounidenses, islas ultramarinas de estados unidos, jersey, libia, liechtenstein, malta, mayotte, moldavia, nauru, niue, norfolk, nueva caledonia, oman, polinesia francesa, republica centroafricana, republica checa, republica democratica del congo, republica dominicana, republica de macedonia, republica del congo, republica arabe saharaui democratica, reunion, ruanda, saint-martin, samoa, samoa americana, san bartolome, seychelles, singapur, siria, somalia, sri lanka, suazilandia, sudan, surinam, svalbard y jan mayen, tayikistan, territorio britanico del oceano indico, territorio australes franceses, territorios palestinos, timor oriental, tokelau, tonga, turkmenistan, tuvalu, uganda, uzbekistan, vanuatu, wallis y futuna, yemen, yibuti y zimbabue.
si. lo revise uno por uno lol

aqui esta un fix rapido que me creo claude del geodata.php:
Registrate o inicia tu sesión para ver este contenido
----------------------------------------------------------------------------------------------
9.vulnerabilidad de seguridad real: en el editor de posts (/agregar/), cuando pegás un link solo en una línea, se genera automáticamente una tarjeta de vista previa (link-preview.js). El título, la descripción y el dominio pasaban por un escapeHtml() antes de insertarse en el HTML — pero la imagen (og:image, sacada de un sitio externo cualquiera) y el link se insertaban sin escapar, directo dentro de un atributo src="...".

Cualquiera podría poner en su propia página un og:image con algo como content='x.jpg" onerror="robar_cookies()"', y si alguien pegaba ese link en un post, ese HTML malicioso quedaba guardado dentro del post — ejecutándose para todos los que lo vieran después (XSS almacenado). fix: agregando el mismo escape a esos dos campos.

Además revisé:

Otros lugares con posible inyección SQL (c.actividad.php, c.mensajes.php, c.admin.php, c.sugerencias.php) — todos están bien sanitizados, no encontré más.
El mismo patrón de HTML sin escapar en otros archivos JS — encontré usos similares con datos de TMDB (posters de películas), pero esos vienen de una API/catálogo curado, no de cualquier sitio externo, así que el riesgo es mucho menor y no lo toqué.
========================================================================
Actualización — después del post original:

10. LLAMADA A MÉTODO INEXISTENTE TRAS UN REFACTOR

Error 500 (fatal) al enviar el formulario de "Olvidé mi contraseña" / "No me llegó el correo de confirmación": en inc/php/ajax/ajax.recover.php (rutas recover-pass / recover-validation) queda una línea residual $tsEmail->emailHeaders = $tsEmail->setEmailHeaders();. En algún momento c.emails.php se reescribió para usar SMTP/PHPMailer y el método setEmailHeaders() ya no existe en la clase — la llamada quedó huérfana. Confirmado en el error.log del servidor. Fix: eliminar esa línea (no hace falta, PHPMailer maneja los headers solo).

11. FEATURE MAL ETIQUETADA / INCOMPLETA [OPCIONAL] 

La pestaña "Mis posts" en /mi/ en realidad no muestra los posts que escribió el usuario: muestra "últimos posts de tu interés" (un filtro por categorías guardadas), no posts de autoría propia. El nombre de la pestaña es engañoso — no hay ningún método en el código que filtre por post_user para esta vista. Fix que aplicamos: agregamos un getAuthoredPosts() nuevo (filtra por post_user) como pestaña real "Mis posts", y renombramos la de categorías a "De mi interés".



NOTA: esto es generado con inteligencia artificial que comete errores, pero dirigido por mí. Le digo qué hacer y dónde buscar. Pongo esto aquí con fines de ayudar. Gracias.
Responder Compartir


Compartir en:

Mensajes en este tema
Risus Nova 2.1 - Cosas Que eE Visto - por carlos007r - 07-09-2026, 09:45 PM
RE: Risus Nova 2.1 - Cosas Que eE Visto - por Tronlar - 07-09-2026, 11:15 PM
RE: Risus Nova 2.1 - Cosas Que eE Visto - por carlos007r - 07-10-2026, 12:59 AM

Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)