Since SQL differentiates between data types and even if a value was given for a particular field the any value would always need to be composed of two OR-connected parts:
field ="a generous data range that includes any posible existing value ..."
field IS NULL
For numeric types 1. gets a bit complicated and would have to be something like
field IS BETWEEN MIN(<numeric type>) AND MAX(<numeric type>)
For string types it is a little bit simpler:
field LIKE '%'
But in any case these search criteria will never be as simple as you would like them to be and they will cost unnecessary search effort for the SQL server!
So, I guess, your first approach of building a SQL search string is still the method to be applied here. You wil have to put some effort into that but I think it can be made safe nonetheless.
In similar projects I have used a pattern generator in which I put together a search criterion for each field. The pattern generator needs to know the field's name, type and posibly table name and of course the user input. Then, dependent on whether anything was actually input it churns out either
- nothing (
null) --> no comparison!
- a valid search condition like
field LIKE '<processed user input> or field =orfield BETWEEN user min value AND user max value
Since the user input will always be processed according to the data type of the given field (including of course a final call of something like mysqli_real_escape_string()) you can make the whole thing safe.
After you processed all the fields with it's user input you need to put all generated (not the null) criteria together again (surround them with (, ), collect them in an array ($arr) and finally join(' AND ',$arr) them) and if necessary, determine which tables (assuming there will be JOINs) are involved. These JOINS can now also be applied conditionally depending on certain crieteria being given or not. This of course really depends on the deeper logic of your table setup.